Compare commits

...

107 Commits

Author SHA1 Message Date
chriadam
4e067fa827 Merge branch 'jb50214' into 'master'
[ofono] Don't support '.' as a DTMF pause character. Contributes to JB#50214

See merge request mer-core/ofono!271
2020-07-13 00:36:38 +00:00
Chris Adams
2ee5e4c827 [ofono] Don't support '.' as a DTMF pause character. Contributes to JB#50214 2020-07-13 10:35:30 +10:00
Niels Breet
1366e426be Merge branch 'jb49681' into 'master'
[aarch64] Use macros for unitdir. Contributes to JB#49681

See merge request mer-core/ofono!272
2020-07-08 13:19:30 +00:00
Niels Breet
586c9b9262 [aarch64] Use macros for unitdir. Contributes to JB#49681 2020-07-08 13:19:30 +00:00
Slava Monich
83554e071a Merge branch 'cbs_retry' into 'master'
Tweak CBS request retry logic

See merge request mer-core/ofono!270
2020-06-25 21:12:01 +00:00
Slava Monich
dc41c2d003 [ril] Allow CBS PDU arrive from RIL as a plain blob. JB#5761
I swear I've seen such cases!
2020-06-25 20:21:09 +03:00
Slava Monich
550d41ae37 [ril] Tweaked CBS request retry logic. JB#5761
There's no need for RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, since we
are not using its result anyway. Better just register for notifications
which would simply never arrive if CBS doesn't work at all.

Important requests, however, better be retried on RIL_E_INVALID_STATE.
2020-06-25 20:05:31 +03:00
Slava Monich
60e4246d93 Merge branch 'cbs' into 'master'
Allow the last CBS fragment to be truncated.

See merge request mer-core/ofono!269
2020-06-19 13:18:21 +00:00
Slava Monich
50619607b0 [cbs] Allow the last CBS fragment to be truncated. JB#5761
That does happen in real life.
2020-06-18 11:59:06 +03:00
Slava Monich
98b357f365 Merge branch 'recap' into 'master'
Refactring radio caps code

See merge request mer-core/ofono!261
2020-06-17 16:00:13 +00:00
Denis Grigorev
56c488d10c [ril] Select the best network for LTE. JB#49391
The radio caps manager will not do anything until the roles are assigned
to modems, so data manager must select the modem with highest capabilities
for LTE instead of the first one.
2020-06-17 18:03:40 +03:00
Denis Grigorev
944cd603e8 [ril] Fix typo. JB#49391 2020-06-17 17:52:41 +03:00
Denis Grigorev
77be0d5e98 [ril] Assert the network mode at startup. JB#49391
At startup, the device may have an inconsistency between data and voice
network modes, so it needs to be asserted.
2020-06-17 17:52:15 +03:00
Denis Grigorev
d8dd20092c [ril] Fix a memory leak in ril_plugin_shutdown_slot(). JB#49391 2020-06-17 17:49:11 +03:00
Slava Monich
c7faa21172 [ril] Refactored radio caps code. JB#49391 2020-06-13 13:29:24 +03:00
Slava Monich
98ffc61a03 Merge branch 'oemraw-access' into 'master'
OemRaw access control

See merge request mer-core/ofono!265
2020-06-11 22:08:55 +00:00
Slava Monich
f2b1625872 Merge branch 'scan' into 'master'
Workaround for bogus operator names in network scan

See merge request mer-core/ofono!152
2020-06-11 22:06:17 +00:00
Slava Monich
2d5a22284e Merge branch 'cbs' into 'master'
Fix parsing of NEW_BROADCAST_SMS packet

See merge request mer-core/ofono!268
2020-06-10 21:09:47 +00:00
Slava Monich
9d742180ab [ril] Fixed parsing of NEW_BROADCAST_SMS packet. JB#5761
It's 4-byte length followed by the specified number of bytes
zero-padded to 4-byte boundary. Kind of like a string.
2020-06-10 15:01:59 +03:00
Slava Monich
f8b0ccc1b4 [ril] Workaround for bogus operator names in network scan. JB#49900
Some RILs (e.g. Sony Xperia X, MediaTek) report bogus operator names
in response to QUERY_AVAILABLE_NETWORKS request. We can make user's
life easier by looking up possible operator name in MBPI database
based on MCC and MNC (assuming those are reported correctly) in case
if weirdness is detected.

To turn this feature on, add this to /etc/ofono/ril_subscription.conf
config file:

replaceStrangeOperatorNames=true
2020-06-05 20:15:35 +03:00
Slava Monich
7a54bb8cbe Merge branch 'jb49955' into 'master'
Provide SmsHistory interface for all modems.

See merge request mer-core/ofono!266
2020-05-20 11:04:49 +00:00
Denis Grigorev
56e0923dc3 [ril] Provide SmsHistory interface for all modems. JB#49955
The SmsHistory plugin uses a global variable to determine if it is already
registered. Because of that, Ofono provides org.ofono.SmsHistory only for
the first modem, and SMS delivery notifications do not work on the others.
After this commit is applied, the plugin will be registered for each modem.
2020-05-19 18:30:44 +03:00
Slava Monich
6dfce4b5e9 [ril] Housekeeping 2020-05-15 15:24:03 +03:00
Slava Monich
4ec3568d71 [ril] Added access control for OemRaw interface. JB#49309 2020-05-15 15:22:09 +03:00
Slava Monich
9b2b7127ef [unit] Added test for OemRaw access control. JB#49309 2020-05-15 15:20:35 +03:00
Slava Monich
1053577376 [ofono] Add OemRaw to D-Bus access control framework. JB#49309
Even though it's RIL specific, it makes sense to reuse the
existing access control mechanism.
2020-05-15 15:19:51 +03:00
Slava Monich
22197b5e04 Merge branch 'jb49798' into 'master'
Fix a memory leak on switching an active SIM card

See merge request mer-core/ofono!263
2020-05-05 14:59:51 +00:00
Denis Grigorev
3a358ddc9d [ril] Fix GRilIoTransportSocket object leak. JB#49798 2020-05-05 16:44:37 +03:00
Denis Grigorev
53929f9f1a [ril] Fix RilCellInfo object leak. JB#49798
On some devices RIL requires to reset the modem while switching radio
capabilities. During this procedure all associated objects should be
disposed and replaced by new instances. This patch fixes a memory
leak through RilCellInfo object.
2020-05-05 16:44:24 +03:00
Slava Monich
08bae57a2b Merge branch 'jb49714' into 'master'
Register settings atom as soon as we have IMSI

See merge request mer-core/ofono!262
2020-04-23 09:08:23 +00:00
Slava Monich
1915aeda76 [ril] Register settings atom as soon as we have IMSI. Fixes JB#49714
There's no need to wait for modem to get powered on. This is just a user
setting - if it can't be applied right away, it will be applied later at
appropriate time.
2020-04-23 04:20:28 +03:00
Slava Monich
51bfb17cbc Merge branch 'modem_offline' into 'master'
Take modem offline when ril_modem is deleted

See merge request mer-core/ofono!260
2020-04-01 16:33:23 +00:00
Slava Monich
a83b553032 [ril] Stop repeating requests on RADIO_NOT_AVAILABLE. JB#49471
If the modem is powered off, this error is repeated indefinitely,
causing unnecessary wakeups.
2020-03-30 21:19:40 +03:00
Slava Monich
ec00abd62d [ril] Tweaked power state confirmation logic. JB#49471
Changed ril_radio_confirm_power_on() to send RADIO_POWER request even if
we think that modem is powered on. Some RILs change power state without
letting us know and that's what this function is for - to make sure that
power is on when we think that it's on.
2020-03-29 01:38:58 +02:00
Slava Monich
80924d5787 [ril] Take modem offline when ril_modem is deleted. JB#49471
Also, mobile data need to be disallowed before deleting the modem
object, so that power keep-on request could be submitted before
bringing the modem offline, to keep power on while data call is
being deactivated (if there was one).
2020-03-29 01:34:39 +02:00
Slava Monich
2bdd05aa31 [ril] Fixed ref vs unref mixup.
RilRadioCapsManager was never freed :/

That was leaving 472 bytes in 8 blocks still reachable on exit.
2020-03-20 18:30:40 +02:00
Slava Monich
544f02e5a2 Merge branch 'jb49322' into 'master'
Improve network registration process

See merge request mer-core/ofono!256
2020-03-16 19:05:22 +00:00
Denis Grigorev
6d4638f9bf [ril] Do not trigger automatic PLMN selection if not needed. JB#49322
On some devices SET_NETWORK_SELECTION_AUTOMATIC takes significant time,
because it triggers a complete scan of available PLMNs. If applied, this
commit will make ofono to issue QUERY_NETWORK_SELECTION_MODE first and
check whether the mode actually needs to be changed.
2020-03-16 20:24:14 +03:00
Slava Monich
6584919e9d Merge branch 'configurable-netsel-timeout' into 'master'
Add networkSelectionTimeout config option

See merge request mer-core/ofono!257
2020-03-12 18:48:50 +00:00
Denis Grigorev
34fb44f4eb [ril] Add networkSelectionTimeout config option. JB#49322
On some devices (such as BQ Aquarius NS208) SET_NETWORK_SELECTION_AUTOMATIC
takes a long time and ofono fails with timeout. If applied, this commit
will make network selection timeout configurable.
2020-03-12 18:02:24 +03:00
Slava Monich
c98d2f41c5 Merge branch 'jb49175' into 'master'
Support combinations of device state tracking methods

See merge request mer-core/ofono!255
2020-03-10 13:28:27 +00:00
Slava Monich
b279be4528 [ril] Support combinations of device state tracking methods. JB#49175
In addition to specifying ss, ds or ur method, one can specify a
combination of methods, e.g. ds+ur
2020-03-06 22:02:23 +02:00
Slava Monich
a7912fea39 [ril] Added ril_config_get_mask. JB#49175 2020-03-06 19:25:19 +02:00
Slava Monich
f291cea905 Merge branch 'jb49175' into 'master'
Add a new device state management method

See merge request mer-core/ofono!253
2020-03-05 12:45:13 +00:00
Denis Grigorev
68f7d30b77 [ril] Add a new device state management method. JB#49175
If applied, this commit will add a new ril_devmon implementation which
controls network state updates by sending SET_UNSOLICITED_RESPONSE_FILTER.
This is useful for devices with RIL version >= 15 if they ignore
both SEND_DEVICE_STATE and SEND_SCREEN_STATE requests as some Qualcomm-
based devices do.
2020-03-04 12:19:55 +03:00
Slava Monich
890a2697fe Merge branch 'jb49163' into 'master'
Access control for SIM Toolkit agent

See merge request mer-core/ofono!254
2020-03-03 21:35:16 +00:00
Slava Monich
9568c8449b [ofono] Access control for SIM Toolkit agent. Fixes JB#49163
Non-privileged process will get org.ofono.Error.AccessDenied from
RegisterAgent. Other methods already check that D-Bus call is coming
from a registered agent.
2020-03-03 19:19:47 +02:00
Slava Monich
cf91be9742 Merge branch 'ims_ap' into 'master'
Support for provisioning and configuring IMS access point

See merge request mer-core/ofono!252
2020-02-21 09:24:25 +00:00
Slava Monich
087771dc0f [ril] Allocate context for IMS. JB#48905 2020-02-20 14:56:10 +02:00
Slava Monich
645dfe47e5 [ofono] Support for automatic creation of IMS context. JB#48905
The approach is quite generic, it's up to the driver to configure
contexts that it wants to be created automatically at startup.
2020-02-20 14:56:02 +02:00
Slava Monich
68e8b02d3b [ofono] Added support for provisioning IMS access points. JB#48905 2020-02-20 14:55:52 +02:00
Slava Monich
aa4309e8cb Merge branch 'once' into 'master'
Store one-time data SIM selection

See merge request mer-core/ofono!251
2020-02-13 17:05:02 +00:00
Slava Monich
cb6b24d950 [ofono] Store one-time data SIM selection. JB#48462
This way, automatic choice survives a reboot.
2020-02-13 18:53:32 +03:00
Slava Monich
6d1ab13c74 [ofono] Ignore known deprecation warnings
Apparently, the only way to get rid of "warning: G_ADD_PRIVATE" is to
completely disable all Glib deprecation warnings in the entire file.
G_GNUC_BEGIN/END_IGNORE_DEPRECATIONS macros don't help :/
2020-02-12 20:58:24 +03:00
Slava Monich
45424a3f96 Merge branch 'error55' into 'master'
Workaround for data call status 55

See merge request mer-core/ofono!250
2020-02-12 17:05:43 +00:00
Slava Monich
4f7398e39d [ril] Workaround for data call status 55. JB#40162
With some networks we sometimes start getting error 55 (Multiple
PDN connections for a given APN not allowed) when trying to setup
an LTE data call and this error doesn't go away until we successfully
establish a data call over 3G. Then we can switch back to LTE.
2020-02-11 17:08:01 +03:00
Slava Monich
cd118ce70b [qmimodem] Move lte.c to the right place 2020-02-11 12:51:15 +03:00
Slava Monich
99d4ce538e [ofono] Updated baseline to 1.23. Fixes JB#48840 2020-02-05 17:05:33 +02:00
Slava Monich
9b2c4bcf76 Merge branch 'v1.23' into 'master'
Update baseline to 1.23

See merge request mer-core/ofono!247
2020-02-05 14:59:54 +00:00
Slava Monich
0122db04a3 Revert "[unit] Fixed memory leak in test-simutil"
This reverts commit c04b14c49a.

It conflicts with commit f5971198 cherry-picked from upstream.
2020-02-05 16:10:42 +02:00
Marcel Holtmann
021db194cb Release 1.23 2020-02-05 15:49:23 +02:00
Jonas Bonn
e0a0896205 qmimodem: release DMS service on radio-settings atom removal 2020-02-05 15:49:23 +02:00
Jonas Bonn
49d0bbbb28 qmimodem: release WDS service on GPRS atom removal 2020-02-05 15:49:22 +02:00
Jonas Bonn
9193d06b77 qmimodem: get LTE default bearer APN from modem
When an LTE modem registers with the network, a default bearer is
automatically established.  The APN used for this bearer is taken from
whatever default settings the modem has.

The LTE atom takes cares of setting up the default context/profile with
the APN to use.  From there, a default bearer will be established when
the modem registers with the network.  This results in a call to 'Get
LTE Attach Parameters' which tells us what APN the gateway negotiated
with us.

If we can't get the APN, we do what the AT driver does:  pretend the
bearer wasn't established.  This is a reasonable fallback, currently,
because connman can't handle zero-length APN's anyway; the previous
approach of setting the APN to 'automatic' breaks connman badly when it
needs to switch between LTE and non-LTE networks.
2020-02-05 15:49:22 +02:00
Jonas Bonn
b0cd3e4544 gobi: add LTE atom
This atom needs to be created in post_sim so that the APN can be
written to the default profile before the modem attempts to use the
setting to connect to the network.
2020-02-05 15:49:22 +02:00
Jonas Bonn
29cce6969b qmi: add LTE atom driver
This patch adds an LTE atom for QMI modems.

This atom sets the APN that the LTE default bearer should use when
establishing its PDP context.  This APN needs to be set on the 'default'
profile so the atom queries which profile is the default and resets
it before allowing the APN to be set.

Once configured, the default profile settings are used when the
modem connects to the network; for this reason, the LTE atom needs
to be instantiated in post_sim, before the modem is set online.
2020-02-05 15:49:22 +02:00
Denis Kenzior
b87f666e4b sim-auth: Improve pending cleanup on sim_auth_remove 2020-02-05 15:49:21 +02:00
Denis Kenzior
1c1e4fa28b sim-auth: Do not leak nai
==31530== 88 bytes in 2 blocks are definitely lost in loss record 132 of 186
==31530==    at 0x4C2BF8F: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==31530==    by 0x5847B97: vasprintf (in /lib64/libc-2.23.so)
==31530==    by 0x510AE38: g_vasprintf (gprintf.c:316)
==31530==    by 0x50D8BDF: g_strdup_vprintf (gstrfuncs.c:514)
==31530==    by 0x50D8CAA: g_strdup_printf (gstrfuncs.c:540)
==31530==    by 0x4F706B: build_nai (sim-auth.c:660)
==31530==    by 0x4F706B: sim_auth_register (sim-auth.c:738)
==31530==    by 0x4F706B: ofono_sim_auth_create (sim-auth.c:768)
==31530==    by 0x4ACBB4: modem_change_state (modem.c:525)
==31530==    by 0x4AD0CD: sim_state_watch.part.5 (modem.c:720)
==31530==    by 0x4CF6D0: call_state_watches (sim.c:366)
==31530==    by 0x4CF6D0: sim_set_ready (sim.c:1475)
==31530==    by 0x4CF6D0: sim_imsi_obtained (sim.c:1577)
==31530==    by 0x45D868: at_cimi_cb (sim.c:453)
==31530==    by 0x49CB5F: at_chat_finish_command (gatchat.c:459)
==31530==    by 0x49DAC7: at_chat_handle_command_response (gatchat.c:521)
==31530==    by 0x49DAC7: have_line (gatchat.c:600)
==31530==    by 0x49DAC7: new_bytes (gatchat.c:759)
2020-02-05 15:49:03 +02:00
Denis Kenzior
f597119845 unit: Use sim_app_record_free to avoid memleaks 2020-02-05 15:49:03 +02:00
Christophe Ronco
633888932d udevng: Add modem string SystemPath 2020-02-05 15:44:38 +02:00
Christophe Ronco
a37f325d4a modem: Add SystemPath dbus property 2020-02-05 15:44:38 +02:00
Christophe Ronco
0afceac554 doc: Add SystemPath to Modem interface 2020-02-05 15:44:38 +02:00
Philippe De Swert
109751bcc0 doc: add new DialMemory method to VoicecallManager 2020-02-05 15:44:38 +02:00
Denis Kenzior
30dfbf8fd7 hfpmodem: Don't use strcat 2020-02-05 15:44:37 +02:00
Philippe De Swert
c7aab2e790 hfpmodem: Add memory dialling support
Handle the request to dial from a memory index and send the
correct ATD> sequence to make it happen.
2020-02-05 15:44:37 +02:00
Philippe De Swert
412a2a0e7f voicecall: Add memory location dialing
Implement functionality to allow to  dial favourites/quick contacts over
bluetooth.
2020-02-05 15:44:37 +02:00
Philippe De Swert
f1aeedd113 voicecall: Add support for dialing number at a given memory location
Add a new function to be able to dial numbers from memory/favourites.

Conflicts:
	ofono/include/voicecall.h
2020-02-05 15:44:32 +02:00
Philippe De Swert
639fce8eca voicecall: Rename hfp dialing functions
Calling from memory index is very similar in functionality to dialing
the last called number. So we rename the functions so we can reuse them,
to deal with memory index calling. Function names now also reflect this
is for hfp.
2020-02-05 15:34:26 +02:00
Jonas Bonn
9cfd0a195e xmm7modem: drop executable bit from C source file 2020-02-05 15:34:25 +02:00
Slava Monich
cf2d8488cc Merge branch 'dbm' into 'master'
Add signalStrengthRange option

See merge request mer-core/ofono!246
2020-01-22 10:10:44 +00:00
Slava Monich
ab0ac10abd [ril] Added signalStrengthRange option. JB#46086
Allows to tweak conversion of dBm values returned by the modem
into signal strength percentage.
2020-01-21 19:15:52 +02:00
Slava Monich
b2df7de223 Merge branch 'auto-select-data' into 'master'
Add AutoSelectDataSim option.

See merge request mer-core/ofono!245
2020-01-16 18:39:03 +00:00
Slava Monich
b56930a87f [unit] Updated test-sailfish_manager. JB#48462 2020-01-16 03:35:07 +02:00
Slava Monich
f65e8dd5af [ofono] Added AutoSelectDataSim option. JB#48462
To change the default behavior in respect to selecting the data SIM, the
following option can be added to /etc/ofono/main.conf:

[ModemManager]
AutoSelectDataSim=on

And data SIM will be picked automatically if none is selected by the user.
All possible options:

   off = option is off (default)
   once = automatically select data SIM once
   always = make sure that data SIM is always selected

"on" is equivalent to "always"
2020-01-16 03:34:26 +02:00
Slava Monich
f2439243b2 [ofono] ril_config_merge_files => config_merge_files
And moved to the core, to make it usable from RIL independent code.
2019-12-26 15:56:54 +02:00
Slava Monich
93ff644856 [ofono] Added __ofono_set_config_dir() function
Allows to make configuration directory configurable.
Also, useful for unit tests.
2019-12-26 02:35:09 +02:00
Slava Monich
08f8555d51 [packaging] Remove sailfish headers from the ofono-devel
Those symbols are not exported by ofono anyway and can't be
referenced by external plugins. Built-in plugins can pull those
headers directly from the source tree.
2019-12-19 16:51:23 +02:00
Slava Monich
04b2a9b0f9 Merge branch 'ecclist' into 'master'
Add support for MediaTek specific ril.ecclist syntax

See merge request mer-core/ofono!244
2019-11-25 11:26:17 +00:00
Slava Monich
4d513b68d2 [unit] Added unit test for ril_ecclist. JB#47953 2019-11-22 20:03:40 +02:00
Slava Monich
36f971dc78 [ril] Support MTK specific ril.ecclist syntax. JB#47953
Some MediaTek adaptations use semicolon as a separator between
comma-separated phone number/service category pairs, e.g.

  112,31;911,31;112,-1;911,-1
2019-11-22 20:03:24 +02:00
Slava Monich
8ba2d96cff [ril] Hosekeeping
gcc 8.3 noticed this:

ril_data.c: In function 'ril_data_call_list_equal':
ril_data.c:437:19: warning: self-comparison always evaluates to true [-Wtautological-compare]
    if (l1->version == l1->version && l1->num == l2->num) {
                    ^~
2019-11-22 19:51:38 +02:00
Slava Monich
a76f50be67 Merge branch 'vendor_signal' into 'master'
Add vendor-specific parsing of SIGNAL_STRENGTH messages

See merge request mer-core/ofono!242
2019-10-31 14:18:45 +00:00
Slava Monich
43227086c0 [ril] Added vendor-specific parsing of SIGNAL_STRENGTH messages. JB#47880
MediaTek loves inventing non-standard message formats.
2019-10-25 15:48:07 +03:00
Slava Monich
e40811fbc6 Merge branch 'gsm_when_radio_off' into 'master'
Add forceGsmWhenRadioOff config option

On some phones (such as Jolla C), even if the slot which has been
using LTE gets powered off, we still need to explicitly set its
preferred mode to GSM, to make LTE machinery available to the other
slot.

Some RILs don't like it when we do this.

See merge request mer-core/ofono!241
2019-10-21 10:27:29 +00:00
Slava Monich
8c543b054a [ril] Added forceGsmWhenRadioOff config option. JB#47747
On some phones (such as Jolla C), even if the slot which has been
using LTE gets powered off, we still need to explicitly set its
preferred mode to GSM, to make LTE machinery available to the other
slot.

Some RILs don't like it when we do this.
2019-10-16 16:48:19 +03:00
Slava Monich
53233b4dc8 Merge branch 'force-gsm' into 'master'
Add ForceGsmForNonDataSlots configuration option

See merge request mer-core/ofono!239
2019-10-10 21:09:01 +00:00
Slava Monich
4458fbf844 Merge branch 'simfs-crash' into 'master'
[ofono] Fix simfs crash. JB#47678

See merge request mer-core/ofono!240
2019-10-11 00:06:36 +03:00
Denis Kenzior
542a086d93 simfs: Fix crash in sim_fs_op_free
If an operation is in progress and an operation is canceled, we don't
actually destroy it, but simply clear out the callback.  In the case of
a context being destroyed, the operation is left on the simfs op_q with
a dangling pointer to the already freed context.  So the current logic
in sim_fs_op_free tries to access invalid memory.

Fix this by performing the watch operations in sim_fs_end_current
instead and setting the context pointer appropriately.
2019-10-10 13:17:46 +03:00
Denis Kenzior
1176662a81 simfs: Fix crash
0  0x00007ffff7b20517 in g_queue_is_empty () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
1  0x00005555556adcdd in sim_fs_op_free (pointer=0x5555559cb990) at src/simfs.c:101
2  0x00007ffff7b205fc in g_queue_foreach () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
3  0x00007ffff7b2065b in g_queue_free_full () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
4  0x00005555556add81 in sim_fs_free (fs=0x5555559c0780) at src/simfs.c:125
5  0x00005555556828f3 in sim_remove (atom=0x5555559cb000) at src/sim.c:3175
6  0x000055555564f16f in flush_atoms (modem=0x555555a8fb00, new_state=MODEM_STATE_POWER_OFF) at src/modem.c:432
7  0x000055555564f3bd in modem_change_state (modem=0x555555a8fb00, new_state=MODEM_STATE_POWER_OFF)
    at src/modem.c:510
8  0x000055555564ff99 in set_powered (modem=0x555555a8fb00, powered=0) at src/modem.c:896
9  0x000055555565074c in modem_set_property (conn=0x55555596c8d0, msg=0x55555596e460, data=0x555555a8fb00)
    at src/modem.c:1120
2019-10-10 13:17:37 +03:00
Slava Monich
ae29a08a76 [ril] Added ForceGsmForNonDataSlots configuration option. JB#47663
By default, ril plugin would force GSM-only mode for non-data SIM.
This option allows to change that behavior.
2019-10-08 18:25:41 +03:00
Slava Monich
af1a569430 Merge branch 'jb36701' into 'master'
Report USSD request errors to the core

See merge request mer-core/ofono!238
2019-10-04 13:39:26 +00:00
Slava Monich
a75558031b [ril] Report USSD errors to the core. JB#36701 2019-10-04 12:09:18 +03:00
Slava Monich
139fff2e5d Merge branch 't8_pin' into 'master'
Fail PIN entry on receiving PASSWORD_INCORRECT

See merge request mer-core/ofono!237
2019-09-27 23:00:53 +00:00
Slava Monich
12614d377a [ril] Fail PIN entry on receiving PASSWORD_INCORRECT. Fixes JB#47494
There's no need to wait for anything in this case.

Also, call ofono_sim_initialized_notify() when completing pin entry
in ril_sim_pin_change_state_cb() to let the core know that we are
ready to accept further requests.
2019-09-26 20:21:59 +03:00
Slava Monich
463f4f183e Merge branch 'pin_recheck' into 'master'
Call ofono_sim_initialized_notify() earlier

See merge request mer-core/ofono!236
2019-09-25 20:04:47 +00:00
Slava Monich
0ba7505f1e [ril] Call ofono_sim_initialized_notify() before unlock. JB#47474
This way PIN retry count gets rechecked after each PIN entry, not
just after the successful one.
2019-09-25 17:09:34 +03:00
Slava Monich
c1156320ac [ril] Map RADIO_TECH_LTE_CA to ACCESS_TECHNOLOGY_EUTRAN 2019-09-25 14:57:12 +03:00
81 changed files with 4793 additions and 1814 deletions

2
ofono/.gitignore vendored
View File

@@ -48,6 +48,7 @@ unit/test-dbus-access
unit/test-dbus-queue unit/test-dbus-queue
unit/test-gprs-filter unit/test-gprs-filter
unit/test-ril_config unit/test-ril_config
unit/test-ril_ecclist
unit/test-ril_util unit/test-ril_util
unit/test-ril_vendor unit/test-ril_vendor
unit/test-ril-transport unit/test-ril-transport
@@ -61,6 +62,7 @@ unit/test-sailfish_cell_info_dbus
unit/test-sailfish_manager unit/test-sailfish_manager
unit/test-sailfish_sim_info unit/test-sailfish_sim_info
unit/test-sailfish_sim_info_dbus unit/test-sailfish_sim_info_dbus
unit/test-config
unit/test-watch unit/test-watch
unit/test-sms-filter unit/test-sms-filter
unit/test-voicecall-filter unit/test-voicecall-filter

View File

@@ -1,3 +1,8 @@
ver 1.23:
Fix issue with handling SIM AID sessions.
Add support for QMI LTE bearer handling.
Add support for memory location dialing.
ver 1.22: ver 1.22:
Fix issue with GPIO handling and Nokia modems. Fix issue with GPIO handling and Nokia modems.
Fix issue with SIM state callback and AT modems. Fix issue with SIM state callback and AT modems.

View File

@@ -32,11 +32,6 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
nodist_pkginclude_HEADERS = include/version.h nodist_pkginclude_HEADERS = include/version.h
if SAILFISH_MANAGER
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
include/sailfish_manager.h
endif
local_headers = $(foreach file,$(pkginclude_HEADERS) \ local_headers = $(foreach file,$(pkginclude_HEADERS) \
$(nodist_pkginclude_HEADERS), \ $(nodist_pkginclude_HEADERS), \
include/ofono/$(notdir $(file))) include/ofono/$(notdir $(file)))
@@ -156,8 +151,10 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_devinfo.c \ drivers/ril/ril_devinfo.c \
drivers/ril/ril_devmon.c \ drivers/ril/ril_devmon.c \
drivers/ril/ril_devmon_auto.c \ drivers/ril/ril_devmon_auto.c \
drivers/ril/ril_devmon_combine.c \
drivers/ril/ril_devmon_ds.c \ drivers/ril/ril_devmon_ds.c \
drivers/ril/ril_devmon_ss.c \ drivers/ril/ril_devmon_ss.c \
drivers/ril/ril_devmon_ur.c \
drivers/ril/ril_ecclist.c \ drivers/ril/ril_ecclist.c \
drivers/ril/ril_gprs.c \ drivers/ril/ril_gprs.c \
drivers/ril/ril_gprs_context.c \ drivers/ril/ril_gprs_context.c \
@@ -310,6 +307,7 @@ builtin_sources += $(qmi_sources) \
drivers/qmimodem/ussd.c \ drivers/qmimodem/ussd.c \
drivers/qmimodem/gprs.c \ drivers/qmimodem/gprs.c \
drivers/qmimodem/gprs-context.c \ drivers/qmimodem/gprs-context.c \
drivers/qmimodem/lte.c \
drivers/qmimodem/radio-settings.c \ drivers/qmimodem/radio-settings.c \
drivers/qmimodem/location-reporting.c \ drivers/qmimodem/location-reporting.c \
drivers/qmimodem/netmon.c drivers/qmimodem/netmon.c
@@ -777,7 +775,7 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/handsfree-audio.c src/bluetooth.h \ src/handsfree-audio.c src/bluetooth.h \
src/sim-mnclength.c src/voicecallagent.c \ src/sim-mnclength.c src/voicecallagent.c \
src/sms-filter.c src/gprs-filter.c \ src/sms-filter.c src/gprs-filter.c \
src/dbus-queue.c src/dbus-access.c \ src/dbus-queue.c src/dbus-access.c src/config.c \
src/voicecall-filter.c src/ril-transport.c \ src/voicecall-filter.c src/ril-transport.c \
src/hfp.h src/siri.c src/watchlist.c \ src/hfp.h src/siri.c src/watchlist.c \
src/netmon.c src/lte.c src/ims.c \ src/netmon.c src/lte.c src/ims.c \
@@ -808,7 +806,8 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ $(builtin_cflags) \
AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/src \ AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/src \
-I$(srcdir)/gdbus -I$(srcdir)/gisi -I$(srcdir)/gatchat \ -I$(srcdir)/gdbus -I$(srcdir)/gisi -I$(srcdir)/gatchat \
-I$(srcdir)/btio -I$(srcdir)/gril -I$(srcdir)/btio -I$(srcdir)/gril \
-I$(srcdir)/plugins/sailfish_manager
doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
doc/manager-api.txt doc/modem-api.txt doc/network-api.txt \ doc/manager-api.txt doc/modem-api.txt doc/network-api.txt \
@@ -972,8 +971,7 @@ if SAILFISH_MANAGER
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \ unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c plugins/sailfish_manager/sailfish_cell_info.c
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \ unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
-Iplugins/sailfish_manager
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS) unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
unit_tests += unit/test-sailfish_cell_info unit_tests += unit/test-sailfish_cell_info
@@ -986,7 +984,7 @@ unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
gdbus/object.c \ gdbus/object.c \
src/dbus.c src/log.c src/dbus.c src/log.c
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \ unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
@DBUS_GLIB_CFLAGS@ -Iplugins/sailfish_manager @DBUS_GLIB_CFLAGS@
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS) unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
unit_tests += unit/test-sailfish_cell_info_dbus unit_tests += unit/test-sailfish_cell_info_dbus
@@ -996,7 +994,7 @@ unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
plugins/sailfish_manager/sailfish_sim_info.c \ plugins/sailfish_manager/sailfish_sim_info.c \
src/storage.c src/watchlist.c src/log.c src/storage.c src/watchlist.c src/log.c
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \ unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager -DSTORAGEDIR='"/tmp/ofono"'
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS) unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
unit_tests += unit/test-sailfish_sim_info unit_tests += unit/test-sailfish_sim_info
@@ -1008,8 +1006,7 @@ unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
gdbus/object.c \ gdbus/object.c \
src/dbus.c src/storage.c src/watchlist.c src/log.c src/dbus.c src/storage.c src/watchlist.c src/log.c
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \ unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"' \ @DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"'
-Iplugins/sailfish_manager
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS) unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
unit_tests += unit/test-sailfish_sim_info_dbus unit_tests += unit/test-sailfish_sim_info_dbus
@@ -1021,7 +1018,7 @@ unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
plugins/sailfish_manager/sailfish_sim_info.c \ plugins/sailfish_manager/sailfish_sim_info.c \
src/storage.c src/log.c src/storage.c src/log.c
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \ unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager -DSTORAGEDIR='"/tmp/ofono"'
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_manager_OBJECTS) unit_objects += $(unit_test_sailfish_manager_OBJECTS)
unit_tests += unit/test-sailfish_manager unit_tests += unit/test-sailfish_manager
@@ -1029,13 +1026,20 @@ unit_tests += unit/test-sailfish_manager
unit_test_watch_SOURCES = unit/test-watch.c src/watch.c \ unit_test_watch_SOURCES = unit/test-watch.c src/watch.c \
src/log.c src/watchlist.c src/log.c src/watchlist.c
unit_test_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \ unit_test_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager -DSTORAGEDIR='"/tmp/ofono"'
unit_test_watch_LDADD = @GLIB_LIBS@ -ldl unit_test_watch_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_watch_OBJECTS) unit_objects += $(unit_test_watch_OBJECTS)
unit_tests += unit/test-watch unit_tests += unit/test-watch
endif endif
unit_test_config_SOURCES = unit/test-config.c drivers/ril/ril_util.c \
src/config.c src/log.c
unit_test_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_config_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_config_OBJECTS)
unit_tests += unit/test-config
if SAILFISH_ACCESS if SAILFISH_ACCESS
unit_test_sailfish_access_SOURCES = unit/test-sailfish_access.c \ unit_test_sailfish_access_SOURCES = unit/test-sailfish_access.c \
plugins/sailfish_access.c src/dbus-access.c src/log.c plugins/sailfish_access.c src/dbus-access.c src/log.c
@@ -1062,6 +1066,13 @@ unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_config_OBJECTS) unit_objects += $(unit_test_ril_config_OBJECTS)
unit_tests += unit/test-ril_config unit_tests += unit/test-ril_config
unit_test_ril_ecclist_SOURCES = unit/test-ril_ecclist.c \
drivers/ril/ril_ecclist.c src/log.c
unit_test_ril_ecclist_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_ecclist_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_ecclist_OBJECTS)
unit_tests += unit/test-ril_ecclist
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \ unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
src/log.c src/log.c
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60) AC_PREREQ(2.60)
AC_INIT(ofono, 1.22) AC_INIT(ofono, 1.23)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests]) AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h) AC_CONFIG_HEADERS(config.h)
@@ -189,8 +189,8 @@ CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
LIBS="$LIBS $GLIBUTIL_LIBS" LIBS="$LIBS $GLIBUTIL_LIBS"
if (test "${enable_sailfish_rilmodem}" = "yes"); then if (test "${enable_sailfish_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.35, dummy=yes, PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.38, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.35 is required)) AC_MSG_ERROR(libgrilio >= 1.0.38 is required))
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.6, dummy=yes, PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.6, dummy=yes,
AC_MSG_ERROR(libmce-glib >= 1.0.6 is required)) AC_MSG_ERROR(libmce-glib >= 1.0.6 is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS" CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"

View File

@@ -95,6 +95,13 @@ Properties boolean Powered [readwrite]
String representing the software version number of the String representing the software version number of the
modem device. modem device.
string SystemPath [readonly, optional]
String representing the system path for the modem
device.
For modems detected by udev events, this corresponds to
the modem sysfs path.
array{string} Features [readonly] array{string} Features [readonly]
List of currently enabled features. It uses simple List of currently enabled features. It uses simple

View File

@@ -69,6 +69,17 @@ Methods dict GetProperties()
[service].Error.NotImplemented [service].Error.NotImplemented
[service].Error.Failed [service].Error.Failed
object DialMemory(string memory position, string hide_callerid)
Initiates a new outgoing call to the number in the given memory
position/favourite. For callerid see the Dial method.
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.InvalidFormat
[service].Error.NotImplemented
[service].Error.Failed
void Transfer() void Transfer()
Joins the currently Active (or Outgoing, depending Joins the currently Active (or Outgoing, depending

View File

@@ -422,6 +422,28 @@ static void hfp_dial_last(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
CALLBACK_WITH_FAILURE(cb, data); CALLBACK_WITH_FAILURE(cb, data);
} }
static void hfp_dial_memory(struct ofono_voicecall *vc,
unsigned int memory_location,
ofono_voicecall_cb_t cb, void *data)
{
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[256];
cbd->user = vc;
DBG("Calling memory location %d\n", memory_location);
snprintf(buf, sizeof(buf), "ATD>%d;", memory_location);
if (g_at_chat_send(vd->chat, buf, none_prefix,
atd_cb, cbd, g_free) > 0)
return;
g_free(cbd);
DBG("at_chat_failed");
CALLBACK_WITH_FAILURE(cb, data);
}
static void hfp_template(const char *cmd, struct ofono_voicecall *vc, static void hfp_template(const char *cmd, struct ofono_voicecall *vc,
GAtResultFunc result_cb, unsigned int affected_types, GAtResultFunc result_cb, unsigned int affected_types,
ofono_voicecall_cb_t cb, void *data) ofono_voicecall_cb_t cb, void *data)
@@ -1287,6 +1309,7 @@ static struct ofono_voicecall_driver driver = {
.remove = hfp_voicecall_remove, .remove = hfp_voicecall_remove,
.dial = hfp_dial, .dial = hfp_dial,
.dial_last = hfp_dial_last, .dial_last = hfp_dial_last,
.dial_memory = hfp_dial_memory,
.answer = hfp_answer, .answer = hfp_answer,
.hangup_active = hfp_hangup, .hangup_active = hfp_hangup,
.hold_all_active = hfp_hold_all_active, .hold_all_active = hfp_hold_all_active,

View File

@@ -29,12 +29,16 @@
#include "qmi.h" #include "qmi.h"
#include "nas.h" #include "nas.h"
#include "wds.h"
#include "src/common.h" #include "src/common.h"
#include "qmimodem.h" #include "qmimodem.h"
struct gprs_data { struct gprs_data {
struct qmi_device *dev;
struct qmi_service *nas; struct qmi_service *nas;
struct qmi_service *wds;
unsigned int last_auto_context_id;
}; };
static bool extract_ss_info(struct qmi_result *result, int *status, int *tech) static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
@@ -64,8 +68,124 @@ static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
return true; return true;
} }
static void get_lte_attach_param_cb(struct qmi_result *result, void *user_data)
{
struct ofono_gprs *gprs = user_data;
struct gprs_data *data = ofono_gprs_get_data(gprs);
char *apn = NULL;
uint16_t error;
uint8_t iptype;
DBG("");
if (qmi_result_set_error(result, &error)) {
ofono_error("Failed to query LTE attach params: %hd", error);
goto noapn;
}
/* APN */
apn = qmi_result_get_string(result, 0x10);
if (!apn) {
DBG("Default profile has no APN setting");
goto noapn;
}
if (qmi_result_get_uint8(result, 0x11, &iptype))
ofono_info("LTE attach IP type: %hhd", iptype);
ofono_gprs_cid_activated(gprs, data->last_auto_context_id, apn);
g_free(apn);
return;
noapn:
data->last_auto_context_id = 0;
ofono_error("LTE bearer established but APN not set");
}
static void get_default_profile_cb(struct qmi_result *result, void *user_data)
{
struct ofono_gprs* gprs = user_data;
struct gprs_data *data = ofono_gprs_get_data(gprs);
uint16_t error;
uint8_t index;
DBG("");
if (qmi_result_set_error(result, &error)) {
ofono_error("Get default profile error: %hd", error);
goto error;
}
/* Profile index */
if (!qmi_result_get_uint8(result, 0x01, &index)) {
ofono_error("Failed query default profile");
goto error;
}
DBG("Default profile index: %hhd", index);
data->last_auto_context_id = index;
/* Get LTE Attach Parameters */
if (qmi_service_send(data->wds, 0x85, NULL,
get_lte_attach_param_cb, gprs, NULL) > 0)
return;
error:
data->last_auto_context_id = 0;
ofono_error("LTE bearer established but APN not set");
}
/*
* Query the settings in effect on the default bearer. These may be
* implicit or may even be something other than requested as the gateway
* is allowed to override whatever was requested by the user.
*/
static void get_lte_attach_params(struct ofono_gprs* gprs)
{
struct gprs_data *data = ofono_gprs_get_data(gprs);
struct {
uint8_t type;
uint8_t family;
} __attribute((packed)) p = {
.type = 0, /* 3GPP */
.family = 0, /* embedded */
};
struct qmi_param *param;
DBG("");
if (data->last_auto_context_id != 0)
return; /* Established or in progress */
/* Set query in progress */
data->last_auto_context_id = -1;
/* First we query the default profile in order to find out which
* context the modem has activated.
*/
param = qmi_param_new();
if (!param)
goto error;
/* Profile type */
qmi_param_append(param, 0x1, sizeof(p), &p);
/* Get default profile */
if (qmi_service_send(data->wds, 0x49, param,
get_default_profile_cb, gprs, NULL) > 0)
return;
qmi_param_free(param);
error:
ofono_warn("Unable to query LTE APN... will not activate context");
}
static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs) static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
{ {
struct gprs_data *data = ofono_gprs_get_data(gprs);
int status; int status;
int tech; int tech;
@@ -74,16 +194,19 @@ static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
if (!extract_ss_info(result, &status, &tech)) if (!extract_ss_info(result, &status, &tech))
return -1; return -1;
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED) if (status == NETWORK_REGISTRATION_STATUS_REGISTERED) {
if (tech == ACCESS_TECHNOLOGY_EUTRAN) { if (tech == ACCESS_TECHNOLOGY_EUTRAN) {
/* On LTE we are effectively always attached; and /* On LTE we are effectively always attached; and
* the default bearer is established as soon as the * the default bearer is established as soon as the
* network is joined. * network is joined. We just need to query the
* parameters in effect on the default bearer and
* let the ofono core know about the activated
* context.
*/ */
/* FIXME: query default profile number and APN get_lte_attach_params(gprs);
* instead of assuming profile 1 and "" }
*/ } else {
ofono_gprs_cid_activated(gprs, 1 , "automatic"); data->last_auto_context_id = 0;
} }
return status; return status;
@@ -198,7 +321,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
g_free(cbd); g_free(cbd);
} }
static void create_nas_cb(struct qmi_service *service, void *user_data) static void create_wds_cb(struct qmi_service *service, void *user_data)
{ {
struct ofono_gprs *gprs = user_data; struct ofono_gprs *gprs = user_data;
struct gprs_data *data = ofono_gprs_get_data(gprs); struct gprs_data *data = ofono_gprs_get_data(gprs);
@@ -206,12 +329,12 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
DBG(""); DBG("");
if (!service) { if (!service) {
ofono_error("Failed to request NAS service"); ofono_error("Failed to request WDS service");
ofono_gprs_remove(gprs); ofono_gprs_remove(gprs);
return; return;
} }
data->nas = qmi_service_ref(service); data->wds = qmi_service_ref(service);
/* /*
* First get the SS info - the modem may already be connected, * First get the SS info - the modem may already be connected,
@@ -228,6 +351,25 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
ofono_gprs_register(gprs); ofono_gprs_register(gprs);
} }
static void create_nas_cb(struct qmi_service *service, void *user_data)
{
struct ofono_gprs *gprs = user_data;
struct gprs_data *data = ofono_gprs_get_data(gprs);
DBG("");
if (!service) {
ofono_error("Failed to request NAS service");
ofono_gprs_remove(gprs);
return;
}
data->nas = qmi_service_ref(service);
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS,
create_wds_cb, gprs, NULL);
}
static int qmi_gprs_probe(struct ofono_gprs *gprs, static int qmi_gprs_probe(struct ofono_gprs *gprs,
unsigned int vendor, void *user_data) unsigned int vendor, void *user_data)
{ {
@@ -240,6 +382,8 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
ofono_gprs_set_data(gprs, data); ofono_gprs_set_data(gprs, data);
data->dev = device;
qmi_service_create_shared(device, QMI_SERVICE_NAS, qmi_service_create_shared(device, QMI_SERVICE_NAS,
create_nas_cb, gprs, NULL); create_nas_cb, gprs, NULL);
@@ -254,6 +398,9 @@ static void qmi_gprs_remove(struct ofono_gprs *gprs)
ofono_gprs_set_data(gprs, NULL); ofono_gprs_set_data(gprs, NULL);
qmi_service_unregister_all(data->wds);
qmi_service_unref(data->wds);
qmi_service_unregister_all(data->nas); qmi_service_unregister_all(data->nas);
qmi_service_unref(data->nas); qmi_service_unref(data->nas);

View File

@@ -0,0 +1,264 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jonas Bonn. All rights reserved.
* Copyright (C) 2018 Norrbonn AB. All rights reserved.
* Copyright (C) 2018 Data Respons ASA. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <glib.h>
#include <ofono/modem.h>
#include <ofono/gprs-context.h>
#include <ofono/log.h>
#include <ofono/lte.h>
#include "qmi.h"
#include "wds.h"
#include "qmimodem.h"
struct lte_data {
struct qmi_service *wds;
uint8_t default_profile;
};
static void modify_profile_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
ofono_lte_cb_t cb = cbd->cb;
uint16_t error;
DBG("");
if (qmi_result_set_error(result, &error)) {
DBG("Failed to modify profile: %d", error);
CALLBACK_WITH_FAILURE(cb, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void qmimodem_lte_set_default_attach_info(const struct ofono_lte *lte,
const struct ofono_lte_default_attach_info *info,
ofono_lte_cb_t cb, void *data)
{
struct lte_data *ldd = ofono_lte_get_data(lte);
struct cb_data *cbd = cb_data_new(cb, data);
struct qmi_param* param;
struct {
uint8_t type;
uint8_t index;
} __attribute__((packed)) p = {
.type = 0, /* 3GPP */
};
DBG("");
p.index = ldd->default_profile;
param = qmi_param_new();
if (!param)
goto error;
/* Profile selector */
qmi_param_append(param, 0x01, sizeof(p), &p);
/* WDS APN Name */
qmi_param_append(param, QMI_WDS_PARAM_APN,
strlen(info->apn), info->apn);
/* Modify profile */
if (qmi_service_send(ldd->wds, 0x28, param,
modify_profile_cb, cbd, g_free) > 0)
return;
qmi_param_free(param);
error:
CALLBACK_WITH_FAILURE(cb, cbd->data);
}
static void reset_profile_cb(struct qmi_result *result, void *user_data)
{
struct ofono_lte *lte = user_data;
uint16_t error;
DBG("");
if (qmi_result_set_error(result, &error))
ofono_error("Reset profile error: %hd", error);
ofono_lte_register(lte);
}
static void get_default_profile_cb(struct qmi_result *result, void *user_data)
{
struct ofono_lte *lte = user_data;
struct lte_data *ldd = ofono_lte_get_data(lte);
uint16_t error;
uint8_t index;
struct qmi_param *param;
struct {
uint8_t type;
uint8_t index;
} __attribute__((packed)) p = {
.type = 0, /* 3GPP */
};
DBG("");
if (qmi_result_set_error(result, &error)) {
ofono_error("Get default profile error: %hd", error);
goto error;
}
/* Profile index */
if (!qmi_result_get_uint8(result, 0x01, &index)) {
ofono_error("Failed query default profile");
goto error;
}
DBG("Default profile index: %hhd", index);
ldd->default_profile = index;
p.index = index;
param = qmi_param_new();
if (!param)
goto error;
/* Profile selector */
qmi_param_append(param, 0x01, sizeof(p), &p);
/* Reset profile */
if (qmi_service_send(ldd->wds, 0x4b, param,
reset_profile_cb, lte, NULL) > 0)
return;
qmi_param_free(param);
error:
ofono_error("Failed to reset profile %hhd", index);
ofono_lte_remove(lte);
}
static void create_wds_cb(struct qmi_service *service, void *user_data)
{
struct ofono_lte *lte = user_data;
struct lte_data *ldd = ofono_lte_get_data(lte);
struct qmi_param *param;
struct {
uint8_t type;
uint8_t family;
} __attribute((packed)) p = {
.type = 0, /* 3GPP */
.family = 0, /* embedded */
};
DBG("");
if (!service) {
ofono_error("Failed to request WDS service");
ofono_lte_remove(lte);
return;
}
ldd->wds = qmi_service_ref(service);
/* Query the default profile */
param = qmi_param_new();
if (!param)
goto error;
/* Profile type */
qmi_param_append(param, 0x1, sizeof(p), &p);
/* Get default profile */
if (qmi_service_send(ldd->wds, 0x49, param,
get_default_profile_cb, lte, NULL) > 0)
return;
qmi_param_free(param);
error:
ofono_error("Failed to query default profile");
ofono_lte_register(lte);
}
static int qmimodem_lte_probe(struct ofono_lte *lte, void *data)
{
struct qmi_device *device = data;
struct lte_data *ldd;
DBG("qmimodem lte probe");
ldd = g_try_new0(struct lte_data, 1);
if (!ldd)
return -ENOMEM;
ofono_lte_set_data(lte, ldd);
qmi_service_create_shared(device, QMI_SERVICE_WDS,
create_wds_cb, lte, NULL);
return 0;
}
static void qmimodem_lte_remove(struct ofono_lte *lte)
{
struct lte_data *ldd = ofono_lte_get_data(lte);
DBG("");
ofono_lte_set_data(lte, NULL);
qmi_service_unregister_all(ldd->wds);
qmi_service_unref(ldd->wds);
g_free(ldd);
}
static struct ofono_lte_driver driver = {
.name = "qmimodem",
.probe = qmimodem_lte_probe,
.remove = qmimodem_lte_remove,
.set_default_attach_info = qmimodem_lte_set_default_attach_info,
};
void qmi_lte_init(void)
{
ofono_lte_driver_register(&driver);
}
void qmi_lte_exit(void)
{
ofono_lte_driver_unregister(&driver);
}

View File

@@ -39,6 +39,7 @@ static int qmimodem_init(void)
qmi_ussd_init(); qmi_ussd_init();
qmi_gprs_init(); qmi_gprs_init();
qmi_gprs_context_init(); qmi_gprs_context_init();
qmi_lte_init();
qmi_radio_settings_init(); qmi_radio_settings_init();
qmi_location_reporting_init(); qmi_location_reporting_init();
qmi_netmon_init(); qmi_netmon_init();
@@ -51,6 +52,7 @@ static void qmimodem_exit(void)
qmi_netmon_exit(); qmi_netmon_exit();
qmi_location_reporting_exit(); qmi_location_reporting_exit();
qmi_radio_settings_exit(); qmi_radio_settings_exit();
qmi_lte_exit();
qmi_gprs_context_exit(); qmi_gprs_context_exit();
qmi_gprs_exit(); qmi_gprs_exit();
qmi_ussd_exit(); qmi_ussd_exit();

View File

@@ -48,6 +48,9 @@ extern void qmi_gprs_exit(void);
extern void qmi_gprs_context_init(void); extern void qmi_gprs_context_init(void);
extern void qmi_gprs_context_exit(void); extern void qmi_gprs_context_exit(void);
extern void qmi_lte_init(void);
extern void qmi_lte_exit(void);
extern void qmi_radio_settings_init(void); extern void qmi_radio_settings_init(void);
extern void qmi_radio_settings_exit(void); extern void qmi_radio_settings_exit(void);

View File

@@ -277,6 +277,9 @@ static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
ofono_radio_settings_set_data(rs, NULL); ofono_radio_settings_set_data(rs, NULL);
qmi_service_unregister_all(data->dms);
qmi_service_unref(data->dms);
qmi_service_unregister_all(data->nas); qmi_service_unregister_all(data->nas);
qmi_service_unref(data->nas); qmi_service_unref(data->nas);

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2017 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,7 @@ struct ril_cbs {
GRilIoChannel *io; GRilIoChannel *io;
GRilIoQueue *q; GRilIoQueue *q;
char *log_prefix; char *log_prefix;
guint register_id;
gulong event_id; gulong event_id;
}; };
@@ -51,6 +52,12 @@ static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
return cbd; return cbd;
} }
static gboolean ril_cbs_retry(GRilIoRequest *request, int ril_status,
const void *resp_data, guint resp_len, void *user_data)
{
return ril_status == RIL_E_INVALID_STATE;
}
static void ril_cbs_request_activation(struct ril_cbs *cd, static void ril_cbs_request_activation(struct ril_cbs *cd,
gboolean activate, GRilIoChannelResponseFunc response, gboolean activate, GRilIoChannelResponseFunc response,
GDestroyNotify destroy, void* user_data) GDestroyNotify destroy, void* user_data)
@@ -61,6 +68,9 @@ static void ril_cbs_request_activation(struct ril_cbs *cd,
grilio_request_append_int32(req, activate ? 0 :1); grilio_request_append_int32(req, activate ? 0 :1);
DBG_(cd, "%sactivating CB", activate ? "" : "de"); DBG_(cd, "%sactivating CB", activate ? "" : "de");
grilio_request_set_retry_func(req, ril_cbs_retry);
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
RIL_CBS_CHECK_RETRY_COUNT);
grilio_queue_send_request_full(cd->q, req, grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
response, destroy, user_data); response, destroy, user_data);
@@ -97,6 +107,9 @@ static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
} }
DBG_(cd, "configuring CB"); DBG_(cd, "configuring CB");
grilio_request_set_retry_func(req, ril_cbs_retry);
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
RIL_CBS_CHECK_RETRY_COUNT);
grilio_queue_send_request_full(cd->q, req, grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
response, destroy, user_data); response, destroy, user_data);
@@ -144,27 +157,41 @@ static void ril_cbs_notify(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data) const void *data, guint len, void *user_data)
{ {
struct ril_cbs *cd = user_data; struct ril_cbs *cd = user_data;
GRilIoParser rilp;
guint32 pdu_len;
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS); GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
DBG_(cd, "%u bytes", len); grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &pdu_len)) {
const void* pdu = grilio_parser_get_bytes(&rilp, pdu_len);
/*
* By default assume that it's a length followed by the
* binary PDU data.
*/
if (pdu && grilio_parser_bytes_remaining(&rilp) < 4) {
DBG_(cd, "%u bytes", pdu_len);
ofono_cbs_notify(cd->cbs, pdu, pdu_len);
} else {
/*
* But I've seen cell broadcasts arriving without
* the length, simply as a blob.
*/
ofono_cbs_notify(cd->cbs, data, len); ofono_cbs_notify(cd->cbs, data, len);
}
}
} }
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status, static gboolean ril_cbs_register(void *user_data)
const void *data, guint len, void *user_data)
{ {
struct ril_cbs *cd = user_data; struct ril_cbs *cd = user_data;
if (status == RIL_E_SUCCESS) {
DBG_(cd, "registering for CB"); DBG_(cd, "registering for CB");
cd->register_id = 0;
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io, cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
cd);
ofono_cbs_register(cd->cbs); ofono_cbs_register(cd->cbs);
} else { return G_SOURCE_REMOVE;
DBG_(cd, "failed to query CB config");
ofono_cbs_remove(cd->cbs);
}
} }
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor, static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
@@ -172,7 +199,6 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
{ {
struct ril_modem *modem = data; struct ril_modem *modem = data;
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1); struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
GRilIoRequest* req = grilio_request_new();
ofono_cbs_set_data(cbs, cd); ofono_cbs_set_data(cbs, cd);
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ? cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
@@ -182,20 +208,7 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
DBG_(cd, ""); DBG_(cd, "");
cd->io = grilio_channel_ref(ril_modem_io(modem)); cd->io = grilio_channel_ref(ril_modem_io(modem));
cd->q = grilio_queue_new(cd->io); cd->q = grilio_queue_new(cd->io);
cd->register_id = g_idle_add(ril_cbs_register, cd);
/*
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup
* especially if other RIL requests are running in parallel. We may
* have to retry a few times. Also, make it blocking in order to
* improve the chance of success.
*/
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
RIL_CBS_CHECK_RETRY_COUNT);
grilio_request_set_blocking(req, TRUE);
grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
ril_cbs_probe_done_cb, NULL, cd);
grilio_request_unref(req);
return 0; return 0;
} }
@@ -204,6 +217,9 @@ static void ril_cbs_remove(struct ofono_cbs *cbs)
struct ril_cbs *cd = ofono_cbs_get_data(cbs); struct ril_cbs *cd = ofono_cbs_get_data(cbs);
DBG_(cd, ""); DBG_(cd, "");
if (cd->register_id) {
g_source_remove(cd->register_id);
}
ofono_cbs_set_data(cbs, NULL); ofono_cbs_set_data(cbs, NULL);
grilio_channel_remove_handler(cd->io, cd->event_id); grilio_channel_remove_handler(cd->io, cd->event_id);
grilio_channel_unref(cd->io); grilio_channel_unref(cd->io);

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2016-2019 Jolla Ltd. * Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -344,11 +345,24 @@ static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
self->set_rate_id = 0; self->set_rate_id = 0;
} }
static gboolean ril_cell_info_retry(GRilIoRequest* request, int ril_status,
const void* response_data, guint response_len, void* user_data)
{
switch (ril_status) {
case RIL_E_SUCCESS:
case RIL_E_RADIO_NOT_AVAILABLE:
return FALSE;
default:
return TRUE;
}
}
static void ril_cell_info_query(struct ril_cell_info *self) static void ril_cell_info_query(struct ril_cell_info *self)
{ {
GRilIoRequest *req = grilio_request_new(); GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES); grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
grilio_request_set_retry_func(req, ril_cell_info_retry);
grilio_channel_cancel_request(self->io, self->query_id, FALSE); grilio_channel_cancel_request(self->io, self->query_id, FALSE);
self->query_id = grilio_channel_send_request_full(self->io, req, self->query_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb, RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
@@ -362,6 +376,7 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self)
(self->update_rate_ms > 0) ? self->update_rate_ms : INT_MAX); (self->update_rate_ms > 0) ? self->update_rate_ms : INT_MAX);
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES); grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
grilio_request_set_retry_func(req, ril_cell_info_retry);
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE); grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
self->set_rate_id = grilio_channel_send_request_full(self->io, req, self->set_rate_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2018 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -185,6 +186,72 @@ gboolean ril_config_get_enum(GKeyFile *file, const char *group,
return FALSE; return FALSE;
} }
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...)
{
char *str = ril_config_get_string(file, group, key);
gboolean ok = FALSE;
if (result) {
*result = 0;
}
if (str) {
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(str, '#');
char **values, **ptr;
if (comment) *comment = 0;
values = g_strsplit(str, "+", -1);
for (ok = TRUE, ptr = values; *ptr && ok; ptr++) {
const char* found_str = NULL;
const char* s = g_strstrip(*ptr);
if (!strcasecmp(s, name)) {
found_str = name;
if (result) {
*result |= value;
}
} else {
va_list args;
const char* known;
va_start(args, value);
while ((known = va_arg(args, char*)) != NULL) {
const int bit = va_arg(args, int);
if (!strcasecmp(s, known)) {
found_str = known;
if (result) {
*result |= bit;
}
break;
}
}
va_end(args);
}
if (!found_str) {
ofono_error("Unknown bit '%s' in %s", s, key);
ok = FALSE;
}
}
g_strfreev(values);
g_free(str);
}
if (!ok && result) {
*result = 0;
}
return ok;
}
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group, GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key) const char *key)
{ {
@@ -237,337 +304,6 @@ char *ril_config_ints_to_string(GUtilInts *ints, char separator)
return NULL; return NULL;
} }
/**
* The ril_config_merge_files() function does the following:
*
* 1. Loads the specified key file (say, "/etc/foo.conf")
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
* for the files with the same suffix as the main file (e.g. "*.conf")
* 3. Sorts the files from the subdirectory (alphabetically)
* 4. Merges the contents of the additional files with the main file
* according to their sort order.
*
* When the entries are merged, keys and groups overwrite the exising
* ones by default. Keys can be suffixed with special characters to
* remove or modify the existing entries instead:
*
* ':' Sets the (default) value if the key is missing
* '+' Appends values to the string list
* '?' Appends only new (non-existent) values to the string list
* '-' Removes the values from the string list
*
* Both keys and groups can be prefixed with '!' to remove the entire key
* or group.
*
* For example if we merge these two files:
*
* /etc/foo.conf:
*
* [foo]
* a=1
* b=2,3
* c=4
* d=5
* [bar]
* e=5
*
* /etc/foo.d/bar.conf:
*
* [foo]
* a+=2
* b-=2
* c=5
* !d
* [!bar]
*
* we end up with this:
*
* [foo]
* a=1
* b=2,3
* c=5
*
* Not that the list separator is assumed to be ',' (rather than default ';').
* The keyfile passed to ril_config_merge_files() should use the same list
* separator, because the default values are copied from the config files
* as is.
*/
static gint ril_config_sort_files(gconstpointer a, gconstpointer b)
{
/* The comparison function for g_ptr_array_sort() doesn't take
* the pointers from the array as arguments, it takes pointers
* to the pointers in the array. */
return strcmp(*(char**)a, *(char**)b);
}
static char **ril_config_collect_files(const char *path, const char *suffix)
{
/* Returns sorted list of regular files in the directory,
* optionally having the specified suffix (e.g. ".conf").
* Returns NULL if nothing appropriate has been found. */
char **files = NULL;
DIR *d = opendir(path);
if (d) {
GPtrArray *list = g_ptr_array_new();
const struct dirent *p;
while ((p = readdir(d)) != NULL) {
/* No need to even stat . and .. */
if (strcmp(p->d_name, ".") &&
strcmp(p->d_name, "..") && (!suffix ||
g_str_has_suffix(p->d_name, suffix))) {
struct stat st;
char *buf = g_strconcat(path, "/", p->d_name,
NULL);
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
g_ptr_array_add(list, buf);
} else {
g_free(buf);
}
}
}
if (list->len > 0) {
g_ptr_array_sort(list, ril_config_sort_files);
g_ptr_array_add(list, NULL);
files = (char**)g_ptr_array_free(list, FALSE);
} else {
g_ptr_array_free(list, TRUE);
}
closedir(d);
}
return files;
}
static int ril_config_list_find(char **list, gsize len, const char *value)
{
guint i;
for (i = 0; i < len; i++) {
if (!strcmp(list[i], value)) {
return i;
}
}
return -1;
}
static void ril_config_list_append(GKeyFile *conf, GKeyFile *k,
const char *group, const char *key,
char **values, gsize n, gboolean unique)
{
/* Note: will steal strings from values */
if (n > 0) {
int i;
gsize len = 0;
gchar **list = g_key_file_get_string_list(conf, group, key,
&len, NULL);
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
for (i = 0; i < (int)len; i++) {
g_ptr_array_add(newlist, list[i]);
}
for (i = 0; i < (int)n; i++) {
char *val = values[i];
if (!unique || ril_config_list_find((char**)
newlist->pdata, newlist->len, val) < 0) {
/* Move the string to the new list */
g_ptr_array_add(newlist, val);
memmove(values + i, values + i + 1,
sizeof(char*) * (n - i));
i--;
n--;
}
}
if (newlist->len > len) {
g_key_file_set_string_list(conf, group, key,
(const gchar * const *) newlist->pdata,
newlist->len);
}
/* Strings are deallocated by GPtrArray */
g_ptr_array_free(newlist, TRUE);
g_free(list);
}
}
static void ril_config_list_remove(GKeyFile *conf, GKeyFile *k,
const char *group, const char *key, char **values, gsize n)
{
if (n > 0) {
gsize len = 0;
gchar **list = g_key_file_get_string_list(conf, group, key,
&len, NULL);
if (len > 0) {
gsize i;
const gsize oldlen = len;
for (i = 0; i < n; i++) {
int pos;
/* Remove all matching values */
while ((pos = ril_config_list_find(list, len,
values[i])) >= 0) {
g_free(list[pos]);
memmove(list + pos, list + pos + 1,
sizeof(char*) * (len - pos));
len--;
}
}
if (len < oldlen) {
g_key_file_set_string_list(conf, group, key,
(const gchar * const *) list, len);
}
}
g_strfreev(list);
}
}
static void ril_config_merge_group(GKeyFile *conf, GKeyFile *k,
const char *group)
{
gsize i, n = 0;
char **keys = g_key_file_get_keys(k, group, &n, NULL);
for (i=0; i<n; i++) {
char *key = keys[i];
if (key[0] == '!') {
if (key[1]) {
g_key_file_remove_key(conf, group, key+1, NULL);
}
} else {
const gsize len = strlen(key);
const char last = (len > 0) ? key[len-1] : 0;
if (last == '+' || last == '?') {
gsize count = 0;
gchar **values = g_key_file_get_string_list(k,
group, key, &count, NULL);
key[len-1] = 0;
ril_config_list_append(conf, k, group, key,
values, count, last == '?');
g_strfreev(values);
} else if (last == '-') {
gsize count = 0;
gchar **values = g_key_file_get_string_list(k,
group, key, &count, NULL);
key[len-1] = 0;
ril_config_list_remove(conf, k, group, key,
values, count);
g_strfreev(values);
} else {
/* Overwrite the value (it must exist in k) */
gchar *value = g_key_file_get_value(k, group,
key, NULL);
if (last == ':') {
/* Default value */
key[len-1] = 0;
if (!g_key_file_has_key(conf,
group, key, NULL)) {
g_key_file_set_value(conf,
group, key, value);
}
} else {
g_key_file_set_value(conf, group, key,
value);
}
g_free(value);
}
}
}
g_strfreev(keys);
}
static void ril_config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
{
gsize i, n = 0;
char **groups = g_key_file_get_groups(k, &n);
for (i=0; i<n; i++) {
const char *group = groups[i];
if (group[0] == '!') {
g_key_file_remove_group(conf, group + 1, NULL);
} else {
ril_config_merge_group(conf, k, group);
}
}
g_strfreev(groups);
}
static void ril_config_merge_file(GKeyFile *conf, const char *file)
{
GKeyFile *k = g_key_file_new();
g_key_file_set_list_separator(k, ',');
if (g_key_file_load_from_file(k, file, 0, NULL)) {
ril_config_merge_keyfile(conf, k);
}
g_key_file_unref(k);
}
void ril_config_merge_files(GKeyFile *conf, const char *file)
{
if (conf && file && file[0]) {
char *dot = strrchr(file, '.');
const char *suffix;
char *dir;
char **files;
if (!dot) {
dir = g_strconcat(file, ".d", NULL);
suffix = NULL;
} else if (!dot[1]) {
dir = g_strconcat(file, "d", NULL);
suffix = NULL;
} else {
/* 2 bytes for ".d" and 1 for NULL terminator */
dir = g_malloc(dot - file + 3);
strncpy(dir, file, dot - file);
strcpy(dir + (dot - file), ".d");
suffix = dot + 1;
}
files = ril_config_collect_files(dir, suffix);
g_free(dir);
/* Load the main config */
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
DBG("Loading %s", file);
ril_config_merge_file(conf, file);
}
if (files) {
char **ptr;
for (ptr = files; *ptr; ptr++) {
DBG("Merging %s", *ptr);
ril_config_merge_file(conf, *ptr);
}
g_strfreev(files);
}
}
}
/* /*
* Local Variables: * Local Variables:
* mode: C * mode: C

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2018 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -22,8 +23,6 @@
#define RILCONF_SETTINGS_GROUP "Settings" #define RILCONF_SETTINGS_GROUP "Settings"
void ril_config_merge_files(GKeyFile *conf, const char *file);
char *ril_config_get_string(GKeyFile *file, const char *group, char *ril_config_get_string(GKeyFile *file, const char *group,
const char *key); const char *key);
char **ril_config_get_strings(GKeyFile *file, const char *group, char **ril_config_get_strings(GKeyFile *file, const char *group,
@@ -36,7 +35,12 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
const char *key, int flag, int *flags); const char *key, int flag, int *flags);
gboolean ril_config_get_enum(GKeyFile *file, const char *group, gboolean ril_config_get_enum(GKeyFile *file, const char *group,
const char *key, int *result, const char *key, int *result,
const char *name, int value, ...); const char *name, int value, ...)
G_GNUC_NULL_TERMINATED;
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...)
G_GNUC_NULL_TERMINATED;
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group, GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key); const char *key);
char *ril_config_ints_to_string(GUtilInts *ints, char separator); char *ril_config_ints_to_string(GUtilInts *ints, char separator);

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2013 Canonical Ltd. * Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2013-2019 Jolla Ltd. * Copyright (C) 2013-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -205,10 +205,44 @@ enum ril_data_call_fail_cause {
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22, PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
PDP_FAIL_NSAPI_IN_USE = 0x23, PDP_FAIL_NSAPI_IN_USE = 0x23,
PDP_FAIL_REGULAR_DEACTIVATION = 0x24, PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
PDP_FAIL_QOS_NOT_ACCEPTED = 0x25,
PDP_FAIL_NETWORK_FAILURE = 0x26,
PDP_FAIL_UMTS_REACTIVATION_REQ = 0x27,
PDP_FAIL_FEATURE_NOT_SUPP = 0x28,
PDP_FAIL_TFT_SEMANTIC_ERROR = 0x29,
PDP_FAIL_TFT_SYTAX_ERROR = 0x2A,
PDP_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
PDP_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
PDP_FAIL_FILTER_SYTAX_ERROR = 0x2D,
PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32, PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33, PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34, PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
PDP_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
PDP_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
PDP_FAIL_INVALID_TRANSACTION_ID = 0x51,
PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
PDP_FAIL_INVALID_MANDATORY_INFO = 0x60,
PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
PDP_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
PDP_FAIL_CONDITIONAL_IE_ERROR = 0x64,
PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
PDP_FAIL_PROTOCOL_ERRORS = 0x6F, PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
PDP_FAIL_APN_TYPE_CONFLICT = 0x70,
PDP_FAIL_INVALID_PCSCF_ADDR = 0x71,
PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
PDP_FAIL_EMM_ACCESS_BARRED = 0x73,
PDP_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
PDP_FAIL_IFACE_MISMATCH = 0x75,
PDP_FAIL_COMPANION_IFACE_IN_USE = 0x76,
PDP_FAIL_IP_ADDRESS_MISMATCH = 0x77,
PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1, PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
PDP_FAIL_DATA_REGISTRATION_FAIL = -2, PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
PDP_FAIL_SIGNAL_LOST = -3, PDP_FAIL_SIGNAL_LOST = -3,
@@ -341,6 +375,19 @@ enum ril_restricted_state {
#define RIL_FACILITY_UNLOCK "0" #define RIL_FACILITY_UNLOCK "0"
#define RIL_FACILITY_LOCK "1" #define RIL_FACILITY_LOCK "1"
/* See RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER (RIL_VERSION >= 15) */
enum ril_unsolicited_response_filter {
RIL_UR_SIGNAL_STRENGTH = 0x01,
RIL_UR_FULL_NETWORK_STATE = 0x02,
RIL_UR_DATA_CALL_DORMANCY_CHANGED = 0x04
};
/* RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE result */
enum ril_network_selection_mode {
RIL_NETWORK_SELECTION_MODE_AUTO = 0,
RIL_NETWORK_SELECTION_MODE_MANUAL = 1
};
#endif /*__RIL_CONSTANTS_H */ #endif /*__RIL_CONSTANTS_H */
/* /*

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2016-2019 Jolla Ltd. * Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -13,6 +14,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_data.h" #include "ril_data.h"
#include "ril_radio.h" #include "ril_radio.h"
#include "ril_network.h" #include "ril_network.h"
@@ -28,6 +31,8 @@
#include <grilio_parser.h> #include <grilio_parser.h>
#include <grilio_request.h> #include <grilio_request.h>
#include "common.h" /* ACCESS_TECHNOLOGY_EUTRAN */
/* Yes, it does sometimes take minutes in roaming */ /* Yes, it does sometimes take minutes in roaming */
#define SETUP_DATA_CALL_TIMEOUT (300*1000) /* ms */ #define SETUP_DATA_CALL_TIMEOUT (300*1000) /* ms */
@@ -76,6 +81,7 @@ typedef struct ril_data RilData;
enum ril_data_io_event_id { enum ril_data_io_event_id {
IO_EVENT_DATA_CALL_LIST_CHANGED, IO_EVENT_DATA_CALL_LIST_CHANGED,
IO_EVENT_RESTRICTED_STATE_CHANGED, IO_EVENT_RESTRICTED_STATE_CHANGED,
IO_EVENT_EOF,
IO_EVENT_COUNT IO_EVENT_COUNT
}; };
@@ -114,6 +120,7 @@ struct ril_data_priv {
gulong io_event_id[IO_EVENT_COUNT]; gulong io_event_id[IO_EVENT_COUNT];
gulong settings_event_id[SETTINGS_EVENT_COUNT]; gulong settings_event_id[SETTINGS_EVENT_COUNT];
GHashTable* grab; GHashTable* grab;
gboolean downgraded_tech; /* Status 55 workaround */
}; };
enum ril_data_signal { enum ril_data_signal {
@@ -184,9 +191,9 @@ struct ril_data_request_allow_data {
gboolean allow; gboolean allow;
}; };
static void ril_data_manager_check_data(struct ril_data_manager *dm);
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm); static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
static void ril_data_call_deact_cid(struct ril_data *data, int cid); static void ril_data_call_deact_cid(struct ril_data *data, int cid);
static void ril_data_cancel_all_requests(struct ril_data *self);
static void ril_data_power_update(struct ril_data *self); static void ril_data_power_update(struct ril_data *self);
static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id) static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
{ {
@@ -434,7 +441,7 @@ static gboolean ril_data_call_list_equal(const struct ril_data_call_list *l1,
if (!l1 && !l2) { if (!l1 && !l2) {
return TRUE; return TRUE;
} else if (l1 && l2) { } else if (l1 && l2) {
if (l1->version == l1->version && l1->num == l2->num) { if (l1->version == l2->version && l1->num == l2->num) {
GSList *p1 = l1->calls; GSList *p1 = l1->calls;
GSList *p2 = l2->calls; GSList *p2 = l2->calls;
@@ -815,6 +822,31 @@ static gboolean ril_data_call_setup_retry(void *user_data)
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
static gboolean ril_data_call_retry(struct ril_data_request_setup *setup)
{
struct ril_data_request *req = &setup->req;
const struct ril_data_options *options = &req->data->priv->options;
if (setup->retry_count < options->data_call_retry_limit) {
req->pending_id = 0;
GASSERT(!setup->retry_delay_id);
if (!setup->retry_count) {
/* No delay first time */
setup->retry_count++;
DBG("silent retry %u out of %u", setup->retry_count,
options->data_call_retry_limit);
req->submit(req);
} else {
const guint ms = options->data_call_retry_delay_ms;
DBG("silent retry scheduled in %u ms", ms);
setup->retry_delay_id = g_timeout_add(ms,
ril_data_call_setup_retry, setup);
}
return TRUE;
}
return FALSE;
}
static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status, static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data) const void *data, guint len, void *user_data)
{ {
@@ -839,33 +871,49 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
} }
} }
if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED && if (call) {
setup->retry_count < priv->options.data_call_retry_limit) { switch (call->status) {
/* /*
* According to the comment from ril.h we should silently * According to the comment from ril.h we should silently
* retry. First time we retry immediately and if that doedsn't * retry. First time we retry immediately and if that doesn't
* work, then after certain delay. * work, then after certain delay.
*/ */
req->pending_id = 0; case PDP_FAIL_ERROR_UNSPECIFIED:
GASSERT(!setup->retry_delay_id); if (ril_data_call_retry(setup)) {
if (!setup->retry_count) {
setup->retry_count++;
DBG("silent retry %u out of %u", setup->retry_count,
priv->options.data_call_retry_limit);
req->submit(req);
} else {
guint ms = priv->options.data_call_retry_delay_ms;
DBG("silent retry scheduled in %u ms", ms);
setup->retry_delay_id = g_timeout_add(ms,
ril_data_call_setup_retry, setup);
}
ril_data_call_list_free(list); ril_data_call_list_free(list);
return; return;
} }
break;
/*
* With some networks we sometimes start getting error 55
* (Multiple PDN connections for a given APN not allowed)
* when trying to setup an LTE data call and this error
* doesn't go away until we successfully establish a data
* call over 3G. Then we can switch back to LTE.
*/
case PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED:
if (priv->network->data.access_tech ==
ACCESS_TECHNOLOGY_EUTRAN &&
!priv->downgraded_tech) {
DBG("downgrading preferred technology");
priv->downgraded_tech = TRUE;
ril_data_manager_check_network_mode(priv->dm);
/* And let this call fail */
}
break;
default:
break;
}
}
ril_data_request_completed(req); ril_data_request_completed(req);
if (call && call->status == PDP_FAIL_NONE) { if (call && call->status == PDP_FAIL_NONE) {
if (priv->downgraded_tech) {
DBG("done with status 55 workaround");
priv->downgraded_tech = FALSE;
ril_data_manager_check_network_mode(priv->dm);
}
if (ril_data_call_list_move_calls(self->data_calls, list) > 0) { if (ril_data_call_list_move_calls(self->data_calls, list) > 0) {
DBG("data call(s) added"); DBG("data call(s) added");
ril_data_signal_emit(self, SIGNAL_CALLS_CHANGED); ril_data_signal_emit(self, SIGNAL_CALLS_CHANGED);
@@ -1151,6 +1199,11 @@ static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
/*==========================================================================* /*==========================================================================*
* ril_data * ril_data
*==========================================================================*/ *==========================================================================*/
static enum ofono_radio_access_mode ril_data_max_mode(struct ril_data *self)
{
return self->priv->downgraded_tech ? OFONO_RADIO_ACCESS_MODE_UMTS :
OFONO_RADIO_ACCESS_MODE_ANY;
}
gulong ril_data_add_allow_changed_handler(struct ril_data *self, gulong ril_data_add_allow_changed_handler(struct ril_data *self,
ril_data_cb_t cb, void *arg) ril_data_cb_t cb, void *arg)
@@ -1179,6 +1232,17 @@ static void ril_data_settings_changed(struct ril_sim_settings *settings,
ril_data_manager_check_network_mode(RIL_DATA(user_data)->priv->dm); ril_data_manager_check_network_mode(RIL_DATA(user_data)->priv->dm);
} }
static void ril_data_ril_disconnected_cb(GRilIoChannel *io, void *user_data)
{
struct ril_data *self = RIL_DATA(user_data);
struct ril_data_priv *priv = self->priv;
DBG_(self, "disconnected");
priv->flags = RIL_DATA_FLAG_NONE;
priv->restricted_state = 0;
ril_data_cancel_all_requests(self);
}
static gint ril_data_compare_cb(gconstpointer a, gconstpointer b) static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
{ {
const struct ril_data *d1 = a; const struct ril_data *d1 = a;
@@ -1238,6 +1302,9 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
grilio_channel_add_unsol_event_handler(io, grilio_channel_add_unsol_event_handler(io,
ril_data_restricted_state_changed_cb, ril_data_restricted_state_changed_cb,
RIL_UNSOL_RESTRICTED_STATE_CHANGED, self); RIL_UNSOL_RESTRICTED_STATE_CHANGED, self);
priv->io_event_id[IO_EVENT_EOF] =
grilio_channel_add_disconnected_handler(io,
ril_data_ril_disconnected_cb, self);
priv->settings_event_id[SETTINGS_EVENT_IMSI_CHANGED] = priv->settings_event_id[SETTINGS_EVENT_IMSI_CHANGED] =
ril_sim_settings_add_imsi_changed_handler(settings, ril_sim_settings_add_imsi_changed_handler(settings,
@@ -1364,6 +1431,20 @@ static void ril_data_cancel_requests(struct ril_data *self,
} }
} }
static void ril_data_cancel_all_requests(struct ril_data *self)
{
struct ril_data_priv *priv = self->priv;
struct ril_data_request *req = priv->req_queue;
ril_data_request_do_cancel(priv->pending_req);
while (req) {
struct ril_data_request *next = req->next;
ril_data_request_do_cancel(req);
req = next;
}
}
static void ril_data_disallow(struct ril_data *self) static void ril_data_disallow(struct ril_data *self)
{ {
struct ril_data_priv *priv = self->priv; struct ril_data_priv *priv = self->priv;
@@ -1535,24 +1616,11 @@ static void ril_data_dispose(GObject *object)
struct ril_data *self = RIL_DATA(object); struct ril_data *self = RIL_DATA(object);
struct ril_data_priv *priv = self->priv; struct ril_data_priv *priv = self->priv;
struct ril_data_manager *dm = priv->dm; struct ril_data_manager *dm = priv->dm;
struct ril_network *network = priv->network;
struct ril_sim_settings *settings = network->settings;
struct ril_data_request *req;
ril_sim_settings_remove_handlers(settings, priv->settings_event_id,
G_N_ELEMENTS(priv->settings_event_id));
grilio_channel_remove_all_handlers(priv->io, priv->io_event_id);
grilio_queue_cancel_all(priv->q, FALSE); grilio_queue_cancel_all(priv->q, FALSE);
priv->query_id = 0; priv->query_id = 0;
ril_data_request_do_cancel(priv->pending_req); ril_data_cancel_all_requests(self);
req = priv->req_queue;
while (req) {
struct ril_data_request *next = req->next;
ril_data_request_do_cancel(req);
req = next;
}
dm->data_list = g_slist_remove(dm->data_list, self); dm->data_list = g_slist_remove(dm->data_list, self);
ril_data_manager_check_data(dm); ril_data_manager_check_data(dm);
g_hash_table_destroy(priv->grab); g_hash_table_destroy(priv->grab);
@@ -1563,6 +1631,11 @@ static void ril_data_finalize(GObject *object)
{ {
struct ril_data *self = RIL_DATA(object); struct ril_data *self = RIL_DATA(object);
struct ril_data_priv *priv = self->priv; struct ril_data_priv *priv = self->priv;
struct ril_network *network = priv->network;
struct ril_sim_settings *settings = network->settings;
ril_sim_settings_remove_all_handlers(settings, priv->settings_event_id);
grilio_channel_remove_all_handlers(priv->io, priv->io_event_id);
g_free(priv->log_prefix); g_free(priv->log_prefix);
grilio_queue_unref(priv->q); grilio_queue_unref(priv->q);
@@ -1646,35 +1719,41 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
{ {
GSList *l; GSList *l;
if (ril_data_manager_handover(self)) { if ((self->flags & RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS) &&
struct ril_network *lte_network = NULL; ril_data_manager_handover(self)) {
int non_gsm_count = 0; struct ril_network *lte_network = NULL, *best_network = NULL;
enum ofono_radio_access_mode best_mode =
OFONO_RADIO_ACCESS_MODE_ANY;
/* /* Find a SIM for internet access */
* Count number of SIMs for which non-GSM mode is selected
*/
for (l= self->data_list; l; l = l->next) { for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data; struct ril_data *data = l->data;
struct ril_data_priv *priv = data->priv; struct ril_data_priv *priv = data->priv;
struct ril_network *network = priv->network; struct ril_network *network = priv->network;
struct ril_sim_settings *sim = network->settings; struct ril_sim_settings *sim = network->settings;
enum ofono_radio_access_mode mode;
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) { /* Select the first network with internet role */
non_gsm_count++; if ((sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) &&
if ((priv->flags & RIL_DATA_FLAG_MAX_SPEED) && (priv->flags & RIL_DATA_FLAG_MAX_SPEED)) {
!lte_network) {
lte_network = network; lte_network = network;
break;
} }
/* At the same time, look for a suitable slot */
mode = ril_network_max_supported_mode(network);
if (mode > best_mode) {
best_network = network;
best_mode = mode;
} }
} }
/* /*
* If there's no SIM selected for internet access * If there's no SIM selected for internet access
* then choose the first slot for LTE. * then use a slot with highest capabilities for LTE.
*/ */
if (!lte_network) { if (!lte_network) {
struct ril_data *data = self->data_list->data; lte_network = best_network;
lte_network = data->priv->network;
} }
for (l= self->data_list; l; l = l->next) { for (l= self->data_list; l; l = l->next) {
@@ -1683,7 +1762,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
ril_network_set_max_pref_mode(network, ril_network_set_max_pref_mode(network,
(network == lte_network) ? (network == lte_network) ?
OFONO_RADIO_ACCESS_MODE_ANY : ril_data_max_mode(data) :
OFONO_RADIO_ACCESS_MODE_GSM, OFONO_RADIO_ACCESS_MODE_GSM,
FALSE); FALSE);
} }
@@ -1693,7 +1772,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
for (l= self->data_list; l; l = l->next) { for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data; struct ril_data *data = l->data;
ril_network_set_max_pref_mode(data->priv->network, ril_network_set_max_pref_mode(data->priv->network,
OFONO_RADIO_ACCESS_MODE_ANY, FALSE); ril_data_max_mode(data), FALSE);
} }
} }
} }
@@ -1722,7 +1801,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
if (ril_data_manager_handover(self)) { if (ril_data_manager_handover(self)) {
ril_network_set_max_pref_mode(priv->network, ril_network_set_max_pref_mode(priv->network,
OFONO_RADIO_ACCESS_MODE_ANY, TRUE); ril_data_max_mode(data), TRUE);
} }
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) { if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
@@ -1735,7 +1814,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
} }
} }
static void ril_data_manager_check_data(struct ril_data_manager *self) void ril_data_manager_check_data(struct ril_data_manager *self)
{ {
/* /*
* Don't do anything if there any requests pending. * Don't do anything if there any requests pending.

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2016-2019 Jolla Ltd. * Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -54,7 +55,8 @@ struct ril_data {
}; };
enum ril_data_manager_flags { enum ril_data_manager_flags {
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01 RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01,
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS = 0x02
}; };
enum ril_data_allow_data_opt { enum ril_data_allow_data_opt {
@@ -77,16 +79,11 @@ struct ril_data_options {
unsigned int data_call_retry_delay_ms; unsigned int data_call_retry_delay_ms;
}; };
enum ril_data_role {
RIL_DATA_ROLE_NONE, /* Data not allowed */
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
RIL_DATA_ROLE_INTERNET /* Data is allowed at full speed */
};
struct ril_data_manager; struct ril_data_manager;
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg); struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm); struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
void ril_data_manager_unref(struct ril_data_manager *dm); void ril_data_manager_unref(struct ril_data_manager *dm);
void ril_data_manager_check_data(struct ril_data_manager *dm);
void ril_data_manager_assert_data_on(struct ril_data_manager *dm); void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg); typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2019 Jolla Ltd. * Copyright (C) 2019-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -50,11 +51,22 @@ struct ril_devmon *ril_devmon_ss_new(void);
*/ */
struct ril_devmon *ril_devmon_ds_new(void); struct ril_devmon *ril_devmon_ds_new(void);
/*
* This Device Monitor implementation controls network state updates
* by sending SET_UNSOLICITED_RESPONSE_FILTER.
*/
struct ril_devmon *ril_devmon_ur_new(void);
/* /*
* This one selects the type based on the RIL version. * This one selects the type based on the RIL version.
*/ */
struct ril_devmon *ril_devmon_auto_new(void); struct ril_devmon *ril_devmon_auto_new(void);
/*
* This one combines several methods. Takes ownership of ril_devmon objects.
*/
struct ril_devmon *ril_devmon_combine(struct ril_devmon *devmon[], guint n);
/* Utilities (NULL tolerant) */ /* Utilities (NULL tolerant) */
struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon, struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon,
GRilIoChannel *channel, struct sailfish_cell_info *cell_info); GRilIoChannel *channel, struct sailfish_cell_info *cell_info);

View File

@@ -0,0 +1,104 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_devmon.h"
#include <ofono/log.h>
typedef struct ril_devmon_combine {
struct ril_devmon pub;
struct ril_devmon **impl;
guint count;
} DevMon;
typedef struct ril_devmon_combine_io {
struct ril_devmon_io pub;
struct ril_devmon_io **impl;
guint count;
} DevMonIo;
static inline DevMon *ril_devmon_combine_cast(struct ril_devmon *dm)
{
return G_CAST(dm, DevMon, pub);
}
static inline DevMonIo *ril_devmon_ds_io_cast(struct ril_devmon_io *io)
{
return G_CAST(io, DevMonIo, pub);
}
static void ril_devmon_combine_io_free(struct ril_devmon_io *io)
{
guint i;
DevMonIo *self = ril_devmon_ds_io_cast(io);
for (i = 0; i < self->count; i++) {
ril_devmon_io_free(self->impl[i]);
}
g_free(self);
}
static struct ril_devmon_io *ril_devmon_combine_start_io(struct ril_devmon *dm,
GRilIoChannel *chan, struct sailfish_cell_info *ci)
{
guint i;
DevMon *self = ril_devmon_combine_cast(dm);
DevMonIo *io = g_malloc0(sizeof(DevMonIo) +
sizeof(struct ril_devmon_io *) * self->count);
io->pub.free = ril_devmon_combine_io_free;
io->impl = (struct ril_devmon_io**)(io + 1);
io->count = self->count;
for (i = 0; i < io->count; i++) {
io->impl[i] = ril_devmon_start_io(self->impl[i], chan, ci);
}
return &io->pub;
}
static void ril_devmon_combine_free(struct ril_devmon *dm)
{
DevMon *self = ril_devmon_combine_cast(dm);
guint i;
for (i = 0; i < self->count; i++) {
ril_devmon_free(self->impl[i]);
}
g_free(self);
}
struct ril_devmon *ril_devmon_combine(struct ril_devmon *dm[], guint n)
{
guint i;
DevMon *self = g_malloc0(sizeof(DevMon) +
sizeof(struct ril_devmon *) * n);
self->pub.free = ril_devmon_combine_free;
self->pub.start_io = ril_devmon_combine_start_io;
self->impl = (struct ril_devmon **)(self + 1);
self->count = n;
for (i = 0; i < n; i++) {
self->impl[i] = dm[i];
}
return &self->pub;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,254 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_devmon.h"
#include <ofono/log.h>
#include <ofono/ril-constants.h>
#include <mce_battery.h>
#include <mce_charger.h>
#include <mce_display.h>
#include <grilio_channel.h>
#include <grilio_request.h>
#include <gutil_macros.h>
#define RIL_UR_ENABLE_ALL (RIL_UR_SIGNAL_STRENGTH | \
RIL_UR_FULL_NETWORK_STATE | \
RIL_UR_DATA_CALL_DORMANCY_CHANGED)
enum ril_devmon_ur_battery_event {
BATTERY_EVENT_VALID,
BATTERY_EVENT_STATUS,
BATTERY_EVENT_COUNT
};
enum ril_devmon_ur_charger_event {
CHARGER_EVENT_VALID,
CHARGER_EVENT_STATE,
CHARGER_EVENT_COUNT
};
enum ril_devmon_ur_display_event {
DISPLAY_EVENT_VALID,
DISPLAY_EVENT_STATE,
DISPLAY_EVENT_COUNT
};
typedef struct ril_devmon_ur {
struct ril_devmon pub;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
} DevMon;
typedef struct ril_devmon_ur_io {
struct ril_devmon_io pub;
struct sailfish_cell_info *cell_info;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
GRilIoChannel *io;
gboolean display_on;
gboolean unsol_filter_supported;
gulong battery_event_id[BATTERY_EVENT_COUNT];
gulong charger_event_id[CHARGER_EVENT_COUNT];
gulong display_event_id[DISPLAY_EVENT_COUNT];
guint req_id;
} DevMonIo;
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
inline static DevMon *ril_devmon_ur_cast(struct ril_devmon *pub)
{
return G_CAST(pub, DevMon, pub);
}
inline static DevMonIo *ril_devmon_ur_io_cast(struct ril_devmon_io *pub)
{
return G_CAST(pub, DevMonIo, pub);
}
static inline gboolean ril_devmon_ur_battery_ok(MceBattery *battery)
{
return battery->valid && battery->status >= MCE_BATTERY_OK;
}
static inline gboolean ril_devmon_ur_charging(MceCharger *charger)
{
return charger->valid && charger->state == MCE_CHARGER_ON;
}
static gboolean ril_devmon_ur_display_on(MceDisplay *display)
{
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
}
static void ril_devmon_ur_io_unsol_response_filter_sent(GRilIoChannel *io,
int status, const void *data, guint len,
void *user_data)
{
DevMonIo *self = user_data;
self->req_id = 0;
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
/* This is a permanent failure */
DBG_(self, "Unsolicited response filter is not supported");
self->unsol_filter_supported = FALSE;
}
}
static void ril_devmon_ur_io_set_unsol_response_filter(DevMonIo *self)
{
if (self->unsol_filter_supported) {
const gint32 value = self->display_on ? RIL_UR_ENABLE_ALL : 0;
GRilIoRequest *req = grilio_request_array_int32_new(1, value);
DBG_(self, "Setting unsolicited response filter: %u", value);
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
self->req_id =
grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER,
ril_devmon_ur_io_unsol_response_filter_sent,
NULL, self);
grilio_request_unref(req);
}
}
static void ril_devmon_ur_io_set_cell_info_update_interval(DevMonIo *self)
{
sailfish_cell_info_set_update_interval(self->cell_info,
(self->display_on && (ril_devmon_ur_charging(self->charger) ||
ril_devmon_ur_battery_ok(self->battery))) ?
RIL_CELL_INFO_INTERVAL_SHORT_MS :
RIL_CELL_INFO_INTERVAL_LONG_MS);
}
static void ril_devmon_ur_io_battery_cb(MceBattery *battery, void *user_data)
{
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ur_io_charger_cb(MceCharger *charger, void *user_data)
{
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ur_io_display_cb(MceDisplay *display, void *user_data)
{
DevMonIo *self = user_data;
const gboolean display_on = ril_devmon_ur_display_on(display);
if (self->display_on != display_on) {
self->display_on = display_on;
ril_devmon_ur_io_set_unsol_response_filter(self);
ril_devmon_ur_io_set_cell_info_update_interval(self);
}
}
static void ril_devmon_ur_io_free(struct ril_devmon_io *devmon_io)
{
DevMonIo *self = ril_devmon_ur_io_cast(devmon_io);
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
mce_battery_unref(self->battery);
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
mce_charger_unref(self->charger);
mce_display_remove_all_handlers(self->display, self->display_event_id);
mce_display_unref(self->display);
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
grilio_channel_unref(self->io);
sailfish_cell_info_unref(self->cell_info);
g_free(self);
}
static struct ril_devmon_io *ril_devmon_ur_start_io(struct ril_devmon *devmon,
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
{
DevMon *ur = ril_devmon_ur_cast(devmon);
DevMonIo *self = g_new0(DevMonIo, 1);
self->pub.free = ril_devmon_ur_io_free;
self->unsol_filter_supported = TRUE;
self->io = grilio_channel_ref(io);
self->cell_info = sailfish_cell_info_ref(cell_info);
self->battery = mce_battery_ref(ur->battery);
self->battery_event_id[BATTERY_EVENT_VALID] =
mce_battery_add_valid_changed_handler(self->battery,
ril_devmon_ur_io_battery_cb, self);
self->battery_event_id[BATTERY_EVENT_STATUS] =
mce_battery_add_status_changed_handler(self->battery,
ril_devmon_ur_io_battery_cb, self);
self->charger = mce_charger_ref(ur->charger);
self->charger_event_id[CHARGER_EVENT_VALID] =
mce_charger_add_valid_changed_handler(self->charger,
ril_devmon_ur_io_charger_cb, self);
self->charger_event_id[CHARGER_EVENT_STATE] =
mce_charger_add_state_changed_handler(self->charger,
ril_devmon_ur_io_charger_cb, self);
self->display = mce_display_ref(ur->display);
self->display_on = ril_devmon_ur_display_on(self->display);
self->display_event_id[DISPLAY_EVENT_VALID] =
mce_display_add_valid_changed_handler(self->display,
ril_devmon_ur_io_display_cb, self);
self->display_event_id[DISPLAY_EVENT_STATE] =
mce_display_add_state_changed_handler(self->display,
ril_devmon_ur_io_display_cb, self);
ril_devmon_ur_io_set_unsol_response_filter(self);
ril_devmon_ur_io_set_cell_info_update_interval(self);
return &self->pub;
}
static void ril_devmon_ur_free(struct ril_devmon *devmon)
{
DevMon *self = ril_devmon_ur_cast(devmon);
mce_battery_unref(self->battery);
mce_charger_unref(self->charger);
mce_display_unref(self->display);
g_free(self);
}
struct ril_devmon *ril_devmon_ur_new()
{
DevMon *self = g_new0(DevMon, 1);
self->pub.free = ril_devmon_ur_free;
self->pub.start_io = ril_devmon_ur_start_io;
self->battery = mce_battery_new();
self->charger = mce_charger_new();
self->display = mce_display_new();
return &self->pub;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2016 Jolla Ltd. * Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -13,6 +14,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_ecclist.h" #include "ril_ecclist.h"
#include "ril_log.h" #include "ril_log.h"
@@ -47,6 +50,53 @@ G_DEFINE_TYPE(RilEccList, ril_ecclist, G_TYPE_OBJECT)
#define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ #define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
RIL_ECCLIST_TYPE, RilEccList)) RIL_ECCLIST_TYPE, RilEccList))
static char **ril_ecclist_parse(const char *content)
{
char **ptr;
char **list = NULL;
guint i;
/*
* Some MediaTek devices use ECC,CAT;ECC,CAT kind of syntax
*/
if (strchr(content, ';')) {
list = g_strsplit(content, ";", 0);
for (ptr = list; *ptr; ptr++) {
char* comma;
*ptr = g_strstrip(*ptr);
/* Strip service category */
comma = strchr(*ptr, ',');
if (comma) {
*comma = 0;
}
}
} else {
/* The right ECC,ECC syntax is handled here */
list = g_strsplit(content, ",", 0);
for (ptr = list; *ptr; ptr++) {
*ptr = g_strstrip(*ptr);
}
}
/* Sort the list */
gutil_strv_sort(list, TRUE);
/* Remove empty strings (those are at the beginning after sorting) */
while (list[0] && !list[0][0]) {
list = gutil_strv_remove_at(list, 0, TRUE);
}
/* Remove duplicates */
for (i = 0; list[i] && list[i+1]; i++) {
while (list[i+1] && !strcmp(list[i], list[i+1])) {
list = gutil_strv_remove_at(list, i+1, TRUE);
}
}
return list;
}
static char **ril_ecclist_read(struct ril_ecclist *self) static char **ril_ecclist_read(struct ril_ecclist *self)
{ {
struct ril_ecclist_priv *priv = self->priv; struct ril_ecclist_priv *priv = self->priv;
@@ -58,16 +108,9 @@ static char **ril_ecclist_read(struct ril_ecclist *self)
GError *error = NULL; GError *error = NULL;
if (g_file_get_contents(priv->path, &content, &len, &error)) { if (g_file_get_contents(priv->path, &content, &len, &error)) {
char **ptr;
DBG("%s = %s", priv->name, content); DBG("%s = %s", priv->name, content);
list = g_strsplit(content, ",", 0); list = ril_ecclist_parse(content);
for (ptr = list; *ptr; ptr++) { } else {
*ptr = g_strstrip(*ptr);
}
gutil_strv_sort(list, TRUE);
} else if (error) {
DBG("%s: %s", priv->path, GERRMSG(error)); DBG("%s: %s", priv->path, GERRMSG(error));
g_error_free(error); g_error_free(error);
} }
@@ -89,7 +132,8 @@ static void ril_ecclist_update(struct ril_ecclist *self)
DBG("%s changed", priv->name); DBG("%s changed", priv->name);
g_strfreev(self->list); g_strfreev(self->list);
self->list = list; self->list = list;
g_signal_emit(self, ril_ecclist_signals[SIGNAL_LIST_CHANGED], 0); g_signal_emit(self, ril_ecclist_signals
[SIGNAL_LIST_CHANGED], 0);
} else { } else {
g_strfreev(list); g_strfreev(list);
} }
@@ -121,11 +165,10 @@ static void ril_ecclist_dir_changed(GUtilInotifyWatch *watch, guint mask,
priv->file_watch = gutil_inotify_watch_callback_new(priv->path, priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
IN_MODIFY | IN_CLOSE_WRITE, IN_MODIFY | IN_CLOSE_WRITE,
ril_ecclist_changed, self); ril_ecclist_changed, self);
if (priv->file_watch) { DBG("%swatching %s", priv->file_watch ? "" : "not ",
DBG("watching %s", priv->path); priv->path);
ril_ecclist_update(self); ril_ecclist_update(self);
} }
}
if (mask & IN_IGNORED) { if (mask & IN_IGNORED) {
DBG("%s is gone", priv->dir); DBG("%s is gone", priv->dir);

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2019 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC. * Copyright (C) 2019 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "ril_sim_card.h" #include "ril_sim_card.h"
#include "ril_sim_settings.h" #include "ril_sim_settings.h"
#include "ril_cell_info.h" #include "ril_cell_info.h"
#include "ril_vendor.h"
#include "ril_data.h" #include "ril_data.h"
#include "ril_util.h" #include "ril_util.h"
#include "ril_log.h" #include "ril_log.h"
@@ -28,7 +29,6 @@
#include <ofono/watch.h> #include <ofono/watch.h>
#define MAX_PDP_CONTEXTS (2)
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */ #define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
enum ril_modem_power_state { enum ril_modem_power_state {
@@ -218,23 +218,22 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
static void ril_modem_update_radio_settings(struct ril_modem_data *md) static void ril_modem_update_radio_settings(struct ril_modem_data *md)
{ {
struct ril_modem *m = &md->modem; struct ril_modem *m = &md->modem;
if (m->radio->state == RADIO_STATE_ON && md->watch->imsi) { struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
if (md->watch->imsi) {
/* radio-settings.c assumes that IMSI is available */ /* radio-settings.c assumes that IMSI is available */
if (!ril_modem_radio_settings(m)) { if (!rs) {
DBG_(md, "initializing radio settings interface"); DBG_(md, "initializing radio settings interface");
ofono_radio_settings_create(m->ofono, 0, ofono_radio_settings_create(m->ofono, 0,
RILMODEM_DRIVER, md); RILMODEM_DRIVER, md);
} }
} else { } else if (rs) {
/* ofono core may remove radio settings atom internally */
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
if (rs) {
DBG_(md, "removing radio settings interface"); DBG_(md, "removing radio settings interface");
ofono_radio_settings_remove(rs); ofono_radio_settings_remove(rs);
} else { } else {
/* ofono core may remove radio settings atom internally */
DBG_(md, "radio settings interface is already gone"); DBG_(md, "radio settings interface is already gone");
} }
}
} }
static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data) static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
@@ -242,7 +241,6 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
struct ril_modem_data *md = data; struct ril_modem_data *md = data;
GASSERT(md->modem.radio == radio); GASSERT(md->modem.radio == radio);
ril_modem_update_radio_settings(md);
ril_modem_update_online_state(md); ril_modem_update_online_state(md);
} }
@@ -306,15 +304,22 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md); ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md); gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
if (gprs) { if (gprs) {
int i; guint i;
static const enum ofono_gprs_context_type ap_types[] = {
OFONO_GPRS_CONTEXT_TYPE_INTERNET,
OFONO_GPRS_CONTEXT_TYPE_MMS,
OFONO_GPRS_CONTEXT_TYPE_IMS
};
for (i = 0; i < MAX_PDP_CONTEXTS; i++) { /* Create a context for each type */
for (i = 0; i < G_N_ELEMENTS(ap_types); i++) {
struct ofono_gprs_context *gc = struct ofono_gprs_context *gc =
ofono_gprs_context_create(modem, 0, ofono_gprs_context_create(modem, 0,
RILMODEM_DRIVER, md); RILMODEM_DRIVER, md);
if (gc == NULL) if (gc == NULL)
break; break;
ofono_gprs_context_set_type(gc, ap_types[i]);
ofono_gprs_add_context(gprs, gc); ofono_gprs_add_context(gprs, gc);
} }
} }
@@ -416,7 +421,9 @@ static void ril_modem_remove(struct ofono_modem *ofono)
ofono_modem_set_data(ofono, NULL); ofono_modem_set_data(ofono, NULL);
ril_radio_remove_handler(modem->radio, md->radio_state_event_id); ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
ril_radio_set_online(modem->radio, FALSE);
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md)); ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
ril_radio_set_online(modem->radio, FALSE);
ril_radio_unref(modem->radio); ril_radio_unref(modem->radio);
ril_sim_settings_unref(modem->sim_settings); ril_sim_settings_unref(modem->sim_settings);
@@ -435,6 +442,7 @@ static void ril_modem_remove(struct ofono_modem *ofono)
g_source_remove(md->set_offline.timeout_id); g_source_remove(md->set_offline.timeout_id);
} }
ril_vendor_unref(modem->vendor);
ril_network_unref(modem->network); ril_network_unref(modem->network);
ril_sim_card_unref(modem->sim_card); ril_sim_card_unref(modem->sim_card);
ril_data_unref(modem->data); ril_data_unref(modem->data);
@@ -456,7 +464,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const char *ecclist_file, const struct ril_slot_config *config, const char *ecclist_file, const struct ril_slot_config *config,
struct ril_radio *radio, struct ril_network *network, struct ril_radio *radio, struct ril_network *network,
struct ril_sim_card *card, struct ril_data *data, struct ril_sim_card *card, struct ril_data *data,
struct ril_sim_settings *settings, struct ril_sim_settings *settings, struct ril_vendor *vendor,
struct sailfish_cell_info *cell_info) struct sailfish_cell_info *cell_info)
{ {
/* Skip the slash from the path, it looks like "/ril_0" */ /* Skip the slash from the path, it looks like "/ril_0" */
@@ -483,6 +491,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
g_strconcat(log_prefix, " ", NULL) : g_strdup(""); g_strconcat(log_prefix, " ", NULL) : g_strdup("");
modem->ofono = ofono; modem->ofono = ofono;
modem->vendor = ril_vendor_ref(vendor);
modem->radio = ril_radio_ref(radio); modem->radio = ril_radio_ref(radio);
modem->network = ril_network_ref(network); modem->network = ril_network_ref(network);
modem->sim_card = ril_sim_card_ref(card); modem->sim_card = ril_sim_card_ref(card);

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2019 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -16,12 +17,15 @@
#include "ril_plugin.h" #include "ril_plugin.h"
#include "ril_network.h" #include "ril_network.h"
#include "ril_util.h" #include "ril_util.h"
#include "ril_vendor.h"
#include "ril_log.h" #include "ril_log.h"
#include "ofono.h"
#include "common.h" #include "common.h"
#include "simutil.h" #include "simutil.h"
#define REGISTRATION_TIMEOUT (100*1000) /* ms */ #include <ofono/watch.h>
#define REGISTRATION_MAX_RETRIES (2) #define REGISTRATION_MAX_RETRIES (2)
enum ril_netreg_events { enum ril_netreg_events {
@@ -39,15 +43,21 @@ enum ril_netreg_network_events {
struct ril_netreg { struct ril_netreg {
GRilIoChannel *io; GRilIoChannel *io;
GRilIoQueue *q; GRilIoQueue *q;
gboolean replace_strange_oper;
gboolean network_selection_manual_0; gboolean network_selection_manual_0;
int signal_strength_dbm_weak;
int signal_strength_dbm_strong;
struct ofono_watch *watch;
struct ofono_netreg *netreg; struct ofono_netreg *netreg;
struct ril_network *network; struct ril_network *network;
struct ril_vendor *vendor;
char *log_prefix; char *log_prefix;
guint timer_id; guint timer_id;
guint notify_id; guint notify_id;
guint current_operator_id; guint current_operator_id;
gulong ril_event_id[NETREG_RIL_EVENT_COUNT]; gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT]; gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
int network_selection_timeout;
}; };
struct ril_netreg_cbd { struct ril_netreg_cbd {
@@ -187,11 +197,74 @@ static void ril_netreg_current_operator(struct ofono_netreg *netreg,
ril_netreg_cbd_free); ril_netreg_cbd_free);
} }
static gboolean ril_netreg_strange(const struct ofono_network_operator *op,
struct ofono_sim *sim)
{
gsize mcclen;
if (sim && op->status != OPERATOR_STATUS_CURRENT) {
const char *spn = ofono_sim_get_spn(sim);
const char *mcc = ofono_sim_get_mcc(sim);
const char *mnc = ofono_sim_get_mnc(sim);
if (spn && mcc && mnc && !strcmp(op->name, spn) &&
(strcmp(op->mcc, mcc) || strcmp(op->mnc, mnc))) {
/*
* Status is not "current", SPN matches the SIM, but
* MCC and/or MNC don't (e.g. Sony Xperia X where all
* operators could be reported with the same name
* which equals SPN).
*/
DBG("%s %s%s (sim spn?)", op->name, op->mcc, op->mnc);
return TRUE;
}
}
mcclen = strlen(op->mcc);
if (!strncmp(op->name, op->mcc, mcclen) &&
!strcmp(op->name + mcclen, op->mnc)) {
/* Some MediaTek RILs only report numeric operator name */
DBG("%s %s%s (numeric?)", op->name, op->mcc, op->mnc);
return TRUE;
}
return FALSE;
}
static void ril_netreg_process_operators(struct ril_netreg *nd,
struct ofono_network_operator *ops, int nops)
{
if (nd->replace_strange_oper) {
int i;
for (i = 0; i < nops; i++) {
struct ofono_network_operator *op = ops + i;
struct ofono_gprs_provision_data *prov = NULL;
int np = 0;
if (ril_netreg_strange(op, nd->watch->sim) &&
__ofono_gprs_provision_get_settings(op->mcc,
op->mnc, NULL, &prov, &np)) {
/* Use the first entry */
if (np > 0 && prov->provider_name &&
prov->provider_name[0]) {
DBG("%s %s%s -> %s", op->name, op->mcc,
op->mnc, prov->provider_name);
strncpy(op->name, prov->provider_name,
OFONO_MAX_OPERATOR_NAME_LENGTH);
}
__ofono_gprs_provision_free_settings(prov, np);
}
}
}
}
static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status, static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data) const void *data, guint len, void *user_data)
{ {
struct ril_netreg_cbd *cbd = user_data; struct ril_netreg_cbd *cbd = user_data;
ofono_netreg_operator_list_cb_t cb = cbd->cb.operator_list; ofono_netreg_operator_list_cb_t cb = cbd->cb.operator_list;
struct ril_netreg *nd = cbd->nd;
struct ofono_network_operator *list; struct ofono_network_operator *list;
struct ofono_error error; struct ofono_error error;
int noperators = 0, i; int noperators = 0, i;
@@ -233,21 +306,23 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
} }
/* Set the proper status */ /* Set the proper status */
if (!strcmp(status, "available")) { if (!status) {
list[i].status = OPERATOR_STATUS_AVAILABLE; op->status = OPERATOR_STATUS_UNKNOWN;
} else if (!strcmp(status, "available")) {
op->status = OPERATOR_STATUS_AVAILABLE;
} else if (!strcmp(status, "current")) { } else if (!strcmp(status, "current")) {
list[i].status = OPERATOR_STATUS_CURRENT; op->status = OPERATOR_STATUS_CURRENT;
} else if (!strcmp(status, "forbidden")) { } else if (!strcmp(status, "forbidden")) {
list[i].status = OPERATOR_STATUS_FORBIDDEN; op->status = OPERATOR_STATUS_FORBIDDEN;
} else { } else {
list[i].status = OPERATOR_STATUS_UNKNOWN; op->status = OPERATOR_STATUS_UNKNOWN;
} }
op->tech = -1; op->tech = -1;
ok = ril_parse_mcc_mnc(numeric, op); ok = ril_parse_mcc_mnc(numeric, op);
if (ok) { if (ok) {
if (op->tech < 0) { if (op->tech < 0) {
op->tech = cbd->nd->network->voice.access_tech; op->tech = nd->network->voice.access_tech;
} }
DBG("[operator=%s, %s, %s, status: %s]", op->name, DBG("[operator=%s, %s, %s, status: %s]", op->name,
op->mcc, op->mnc, status); op->mcc, op->mnc, status);
@@ -262,6 +337,7 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
} }
if (ok) { if (ok) {
ril_netreg_process_operators(nd, list, noperators);
cb(ril_error_ok(&error), noperators, list, cbd->data); cb(ril_error_ok(&error), noperators, list, cbd->data);
} else { } else {
cb(ril_error_failure(&error), 0, NULL, cbd->data); cb(ril_error_failure(&error), 0, NULL, cbd->data);
@@ -296,18 +372,55 @@ static void ril_netreg_register_cb(GRilIoChannel *io, int status,
} }
} }
static void ril_netreg_set_register_auto(struct ril_netreg *nd,
ofono_netreg_register_cb_t cb, void *data)
{
GRilIoRequest *req = grilio_request_new();
ofono_info("nw select automatic");
grilio_request_set_timeout(req, nd->network_selection_timeout);
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
ril_netreg_register_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, cb, data));
grilio_request_unref(req);
}
static void ril_netreg_query_register_auto_cb(GRilIoChannel *io, int status,
const void *data, guint len,
void *user_data)
{
struct ril_netreg_cbd *cbd = user_data;
ofono_netreg_register_cb_t cb = cbd->cb.reg;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
gint32 net_mode;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, NULL) /* Array length */ &&
grilio_parser_get_int32(&rilp, &net_mode) &&
net_mode == RIL_NETWORK_SELECTION_MODE_AUTO) {
struct ofono_error error;
ofono_info("nw selection is already auto");
cb(ril_error_ok(&error), cbd->data);
return;
}
}
ril_netreg_set_register_auto(cbd->nd, cb, cbd->data);
}
static void ril_netreg_register_auto(struct ofono_netreg *netreg, static void ril_netreg_register_auto(struct ofono_netreg *netreg,
ofono_netreg_register_cb_t cb, void *data) ofono_netreg_register_cb_t cb, void *data)
{ {
struct ril_netreg *nd = ril_netreg_get_data(netreg); struct ril_netreg *nd = ril_netreg_get_data(netreg);
GRilIoRequest *req = grilio_request_new(); GRilIoRequest *req = grilio_request_new();
ofono_info("nw select automatic");
grilio_request_set_timeout(req, REGISTRATION_TIMEOUT);
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
grilio_queue_send_request_full(nd->q, req, grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE,
ril_netreg_register_cb, ril_netreg_cbd_free, ril_netreg_query_register_auto_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, cb, data)); ril_netreg_cbd_new(nd, cb, data));
grilio_request_unref(req); grilio_request_unref(req);
} }
@@ -322,7 +435,7 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
ofono_info("nw select manual: %s%s%s", mcc, mnc, suffix); ofono_info("nw select manual: %s%s%s", mcc, mnc, suffix);
grilio_request_append_format(req, "%s%s%s", mcc, mnc, suffix); grilio_request_append_format(req, "%s%s%s", mcc, mnc, suffix);
grilio_request_set_timeout(req, REGISTRATION_TIMEOUT); grilio_request_set_timeout(req, nd->network_selection_timeout);
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES); grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
grilio_queue_send_request_full(nd->q, req, grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
@@ -331,100 +444,92 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
grilio_request_unref(req); grilio_request_unref(req);
} }
static int ril_netreg_dbm_to_percentage(int dbm) static int ril_netreg_qdbm_to_percentage(struct ril_netreg *nd, int qdbm)
{ {
const int min_dbm = -100; /* very weak signal, 0.0000000001 mW */ const int min_qdbm = 4 * nd->signal_strength_dbm_weak; /* 4*dBm */
const int max_dbm = -60; /* strong signal, 0.000001 mW */ const int max_qdbm = 4 * nd->signal_strength_dbm_strong; /* 4*dBm */
return (dbm <= min_dbm) ? 1 : return (qdbm <= min_qdbm) ? 1 :
(dbm >= max_dbm) ? 100 : (qdbm >= max_qdbm) ? 100 :
(100 * (dbm - min_dbm) / (max_dbm - min_dbm)); (100 * (qdbm - min_qdbm) / (max_qdbm - min_qdbm));
} }
static int ril_netreg_get_signal_strength(const void *data, guint len) static int ril_netreg_get_signal_strength(struct ril_netreg *nd,
const void *data, guint len)
{ {
GRilIoParser rilp; GRilIoParser rilp;
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0; struct ril_vendor_signal_strength signal;
int rsrp = 0, tdscdma_dbm = 0;
grilio_parser_init(&rilp, data, len); grilio_parser_init(&rilp, data, len);
signal.gsm = INT_MAX;
signal.lte = INT_MAX;
signal.qdbm = 0;
if (!ril_vendor_signal_strength_parse(nd->vendor, &signal, &rilp)) {
gint32 rsrp = 0, tdscdma_dbm = 0;
/* Apply default parsing algorithm */
grilio_parser_init(&rilp, data, len);
signal.gsm = INT_MAX;
signal.lte = INT_MAX;
signal.qdbm = 0;
/* GW_SignalStrength */ /* GW_SignalStrength */
grilio_parser_get_int32(&rilp, &gw_signal); grilio_parser_get_int32(&rilp, &signal.gsm);
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */ grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
/* CDMA_SignalStrength */ /* CDMA_SignalStrength */
grilio_parser_get_int32(&rilp, &cdma_dbm); grilio_parser_get_int32(&rilp, NULL); /* dbm */
grilio_parser_get_int32(&rilp, NULL); /* ecio */ grilio_parser_get_int32(&rilp, NULL); /* ecio */
/* EVDO_SignalStrength */ /* EVDO_SignalStrength */
grilio_parser_get_int32(&rilp, &evdo_dbm); grilio_parser_get_int32(&rilp, NULL); /* dbm */
grilio_parser_get_int32(&rilp, NULL); /* ecio */ grilio_parser_get_int32(&rilp, NULL); /* ecio */
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */ grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
/* LTE_SignalStrength */ /* LTE_SignalStrength */
grilio_parser_get_int32(&rilp, &lte_signal); grilio_parser_get_int32(&rilp, &signal.lte);
grilio_parser_get_int32(&rilp, &rsrp); grilio_parser_get_int32(&rilp, &rsrp);
/* Skip the rest of LTE_SignalStrength_v8 */ /* The rest is considered optional */
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */ if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */ grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
grilio_parser_get_int32(&rilp, NULL) && /* cqi */ grilio_parser_get_int32(&rilp, NULL) && /* cqi */
grilio_parser_get_int32(&rilp, NULL)) { /* timingAdvance */ grilio_parser_get_int32(&rilp, NULL) && /* timingAdv */
/* TD_SCDMA_SignalStrength */ /* TD_SCDMA_SignalStrength */
grilio_parser_get_int32(&rilp, &tdscdma_dbm); /* rscp */ grilio_parser_get_int32(&rilp, &tdscdma_dbm) &&
/* RSCP range: 25 to 120 dBm per 3GPP TS 25.123 */
tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
signal.qdbm = -4 * tdscdma_dbm;
} else if (signal.lte == 99 && rsrp >= 44 && rsrp <= 140) {
/* RSRP range: 44 to 140 dBm per 3GPP TS 36.133 */
signal.qdbm = -rsrp;
}
} }
if (rsrp == INT_MAX) { DBG("gw: %d, lte: %d, qdbm: %d", signal.gsm, signal.lte, signal.qdbm);
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d, tdscdma: %d",
gw_signal, cdma_dbm, evdo_dbm,
lte_signal, tdscdma_dbm);
} else {
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d, tdscdma: %d",
gw_signal, cdma_dbm, evdo_dbm,
lte_signal, rsrp, tdscdma_dbm);
}
/* Return the first valid one */ /* Return the first valid one */
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE /* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
* RSRP value. If we've got zero, don't report it just yet. */ * RSRP value. If we've got zero, don't report it just yet. */
if (gw_signal >= 1 && gw_signal <= 31) { if (signal.gsm >= 1 && signal.gsm <= 31) {
/* Valid values are (0-31, 99) as defined in TS 27.007 */ /* Valid values are (0-31, 99) as defined in TS 27.007 */
return (gw_signal * 100) / 31; return (signal.gsm * 100) / 31;
} }
/* Valid values are (0-31, 99) as defined in TS 27.007 */ /* Valid values are (0-31, 99) as defined in TS 27.007 */
if (lte_signal >= 0 && lte_signal <= 31) { if (signal.lte >= 0 && signal.lte <= 31) {
return (lte_signal * 100) / 31; return (signal.lte * 100) / 31;
} }
/* RSCP range: 25 to 120 dBm as defined in 3GPP TS 25.123 */ if (signal.qdbm < 0) {
if (tdscdma_dbm >= 25 && tdscdma_dbm <= 120) { return ril_netreg_qdbm_to_percentage(nd, signal.qdbm);
return ril_netreg_dbm_to_percentage(-tdscdma_dbm); } else if (signal.gsm == 0) {
}
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
return ril_netreg_dbm_to_percentage(-rsrp);
}
/* If we've got zero strength and no valid RSRP, then so be it */
if (gw_signal == 0) {
return 0; return 0;
} } else {
/* In case of dbm, return the value directly */
if (cdma_dbm != -1) {
return MIN(cdma_dbm, 100);
}
if (evdo_dbm != -1) {
return MIN(evdo_dbm, 100);
}
return -1; return -1;
}
} }
static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event, static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
@@ -434,9 +539,11 @@ static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
int strength; int strength;
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH); GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
strength = ril_netreg_get_signal_strength(data, len); strength = ril_netreg_get_signal_strength(nd, data, len);
DBG_(nd, "%d", strength); DBG_(nd, "%d", strength);
if (strength >= 0) {
ofono_netreg_strength_notify(nd->netreg, strength); ofono_netreg_strength_notify(nd->netreg, strength);
}
} }
static void ril_netreg_strength_cb(GRilIoChannel *io, int status, static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
@@ -447,8 +554,8 @@ static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
struct ofono_error error; struct ofono_error error;
if (status == RIL_E_SUCCESS) { if (status == RIL_E_SUCCESS) {
int strength = ril_netreg_get_signal_strength(data, len); cb(ril_error_ok(&error), ril_netreg_get_signal_strength
cb(ril_error_ok(&error), strength, cbd->data); (cbd->nd, data, len), cbd->data);
} else { } else {
ofono_error("Failed to retrive the signal strength: %s", ofono_error("Failed to retrive the signal strength: %s",
ril_error_to_string(status)); ril_error_to_string(status));
@@ -558,9 +665,15 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
DBG_(nd, "%p", netreg); DBG_(nd, "%p", netreg);
nd->io = grilio_channel_ref(ril_modem_io(modem)); nd->io = grilio_channel_ref(ril_modem_io(modem));
nd->q = grilio_queue_new(nd->io); nd->q = grilio_queue_new(nd->io);
nd->watch = ofono_watch_new(ril_modem_get_path(modem));
nd->vendor = ril_vendor_ref(modem->vendor);
nd->network = ril_network_ref(modem->network); nd->network = ril_network_ref(modem->network);
nd->netreg = netreg; nd->netreg = netreg;
nd->replace_strange_oper = config->replace_strange_oper;
nd->network_selection_manual_0 = config->network_selection_manual_0; nd->network_selection_manual_0 = config->network_selection_manual_0;
nd->signal_strength_dbm_weak = config->signal_strength_dbm_weak;
nd->signal_strength_dbm_strong = config->signal_strength_dbm_strong;
nd->network_selection_timeout = config->network_selection_timeout;
ofono_netreg_set_data(netreg, nd); ofono_netreg_set_data(netreg, nd);
nd->timer_id = g_idle_add(ril_netreg_register, nd); nd->timer_id = g_idle_add(ril_netreg_register, nd);
@@ -587,8 +700,10 @@ static void ril_netreg_remove(struct ofono_netreg *netreg)
g_source_remove(nd->current_operator_id); g_source_remove(nd->current_operator_id);
} }
ofono_watch_unref(nd->watch);
ril_network_remove_all_handlers(nd->network, nd->network_event_id); ril_network_remove_all_handlers(nd->network, nd->network_event_id);
ril_network_unref(nd->network); ril_network_unref(nd->network);
ril_vendor_unref(nd->vendor);
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id); grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
grilio_channel_unref(nd->io); grilio_channel_unref(nd->io);

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2019 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -13,8 +14,11 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_network.h" #include "ril_network.h"
#include "ril_radio.h" #include "ril_radio.h"
#include "ril_radio_caps.h"
#include "ril_sim_card.h" #include "ril_sim_card.h"
#include "ril_sim_settings.h" #include "ril_sim_settings.h"
#include "ril_vendor.h" #include "ril_vendor.h"
@@ -32,6 +36,7 @@
#include <ofono/watch.h> #include <ofono/watch.h>
#include <ofono/gprs.h> #include <ofono/gprs.h>
#include "ofono.h"
#include "common.h" #include "common.h"
#define SET_PREF_MODE_HOLDOFF_SEC RIL_RETRY_SECS #define SET_PREF_MODE_HOLDOFF_SEC RIL_RETRY_SECS
@@ -51,6 +56,12 @@ enum ril_network_radio_event {
RADIO_EVENT_COUNT RADIO_EVENT_COUNT
}; };
enum ril_network_radio_caps_mgr_events {
RADIO_CAPS_MGR_TX_DONE,
RADIO_CAPS_MGR_TX_ABORTED,
RADIO_CAPS_MGR_EVENT_COUNT
};
enum ril_network_sim_events { enum ril_network_sim_events {
SIM_EVENT_STATUS_CHANGED, SIM_EVENT_STATUS_CHANGED,
SIM_EVENT_IO_ACTIVE_CHANGED, SIM_EVENT_IO_ACTIVE_CHANGED,
@@ -59,7 +70,6 @@ enum ril_network_sim_events {
enum ril_network_unsol_event { enum ril_network_unsol_event {
UNSOL_EVENT_NETWORK_STATE, UNSOL_EVENT_NETWORK_STATE,
UNSOL_EVENT_RADIO_CAPABILITY,
UNSOL_EVENT_COUNT UNSOL_EVENT_COUNT
}; };
@@ -87,6 +97,7 @@ struct ril_network_priv {
GRilIoChannel *io; GRilIoChannel *io;
GRilIoQueue *q; GRilIoQueue *q;
struct ril_radio *radio; struct ril_radio *radio;
struct ril_radio_caps *caps;
struct ril_sim_card *simcard; struct ril_sim_card *simcard;
struct ril_vendor *vendor; struct ril_vendor *vendor;
struct ofono_watch *watch; struct ofono_watch *watch;
@@ -103,6 +114,8 @@ struct ril_network_priv {
gulong set_rat_id; gulong set_rat_id;
gulong unsol_event_id[UNSOL_EVENT_COUNT]; gulong unsol_event_id[UNSOL_EVENT_COUNT];
gulong settings_event_id; gulong settings_event_id;
gulong supported_modes_event_id;
gulong caps_mgr_event_id[RADIO_CAPS_MGR_EVENT_COUNT];
gulong radio_event_id[RADIO_EVENT_COUNT]; gulong radio_event_id[RADIO_EVENT_COUNT];
gulong simcard_event_id[SIM_EVENT_COUNT]; gulong simcard_event_id[SIM_EVENT_COUNT];
gulong watch_ids[WATCH_EVENT_COUNT]; gulong watch_ids[WATCH_EVENT_COUNT];
@@ -110,6 +123,7 @@ struct ril_network_priv {
gboolean set_initial_attach_apn; gboolean set_initial_attach_apn;
struct ofono_network_operator operator; struct ofono_network_operator operator;
gboolean assert_rat; gboolean assert_rat;
gboolean force_gsm_when_radio_off;
gboolean use_data_profiles; gboolean use_data_profiles;
int mms_data_profile_id; int mms_data_profile_id;
GSList *data_profiles; GSList *data_profiles;
@@ -121,7 +135,6 @@ enum ril_network_signal {
SIGNAL_VOICE_STATE_CHANGED, SIGNAL_VOICE_STATE_CHANGED,
SIGNAL_DATA_STATE_CHANGED, SIGNAL_DATA_STATE_CHANGED,
SIGNAL_PREF_MODE_CHANGED, SIGNAL_PREF_MODE_CHANGED,
SIGNAL_MAX_PREF_MODE_CHANGED,
SIGNAL_COUNT SIGNAL_COUNT
}; };
@@ -129,7 +142,6 @@ enum ril_network_signal {
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed" #define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed" #define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed" #define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
#define SIGNAL_MAX_PREF_MODE_CHANGED_NAME "ril-network-max-pref-mode-changed"
static guint ril_network_signals[SIGNAL_COUNT] = { 0 }; static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
@@ -415,6 +427,18 @@ static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
} }
} }
static gboolean ril_network_retry(GRilIoRequest* request, int ril_status,
const void* response_data, guint response_len, void* user_data)
{
switch (ril_status) {
case RIL_E_SUCCESS:
case RIL_E_RADIO_NOT_AVAILABLE:
return FALSE;
default:
return TRUE;
}
}
static guint ril_network_poll_and_retry(struct ril_network *self, guint id, static guint ril_network_poll_and_retry(struct ril_network *self, guint id,
int code, GRilIoChannelResponseFunc fn) int code, GRilIoChannelResponseFunc fn)
{ {
@@ -427,6 +451,7 @@ static guint ril_network_poll_and_retry(struct ril_network *self, guint id,
GRilIoRequest *req = grilio_request_new(); GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1); grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
grilio_request_set_retry_func(req, ril_network_retry);
id = grilio_queue_send_request_full(priv->q, req, code, fn, id = grilio_queue_send_request_full(priv->q, req, code, fn,
NULL, self); NULL, self);
grilio_request_unref(req); grilio_request_unref(req);
@@ -508,6 +533,17 @@ static int ril_network_mode_to_rat(struct ril_network *self,
} }
} }
enum ofono_radio_access_mode ril_network_max_supported_mode
(struct ril_network *self)
{
struct ril_sim_settings *settings = self->settings;
struct ril_network_priv *priv = self->priv;
const struct ril_radio_caps *caps = priv->caps;
return caps ? __ofono_radio_access_max_mode(caps->supported_modes) :
__ofono_radio_access_max_mode(settings->techs);
}
static enum ofono_radio_access_mode ril_network_actual_pref_mode static enum ofono_radio_access_mode ril_network_actual_pref_mode
(struct ril_network *self) (struct ril_network *self)
{ {
@@ -515,13 +551,12 @@ static enum ofono_radio_access_mode ril_network_actual_pref_mode
struct ril_network_priv *priv = self->priv; struct ril_network_priv *priv = self->priv;
/* /*
* On dual-SIM phones such as Jolla C only one slot at a time * On most dual-SIM phones only one slot at a time is allowed
* is allowed to use LTE. Even if the slot which has been using * to use LTE. On some phones (such as Jolla C), even if the
* LTE gets powered off, we still need to explicitely set its * slot which has been using LTE gets powered off, we still
* preferred mode to GSM, to make LTE machinery available to * need to explicitly set its preferred mode to GSM, to make
* the other slot. This sort of behaviour might not be necessary * LTE machinery available to the other slot. This behavior is
* on some hardware and can (should) be made configurable when * configurable.
* it becomes necessary.
*/ */
const enum ofono_radio_access_mode max_pref_mode = const enum ofono_radio_access_mode max_pref_mode =
(priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode : (priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
@@ -532,9 +567,16 @@ static enum ofono_radio_access_mode ril_network_actual_pref_mode
* and max_pref_mode are not ANY, we pick the smallest value. * and max_pref_mode are not ANY, we pick the smallest value.
* Otherwise we take any non-zero value if there is one. * Otherwise we take any non-zero value if there is one.
*/ */
return (settings->pref_mode && max_pref_mode) ? const enum ofono_radio_access_mode pref_mode =
(settings->pref_mode && max_pref_mode) ?
MIN(settings->pref_mode, max_pref_mode) : MIN(settings->pref_mode, max_pref_mode) :
settings->pref_mode ? settings->pref_mode : max_pref_mode; settings->pref_mode ? settings->pref_mode : max_pref_mode;
/* Do not try to set unsupported mode */
const enum ofono_radio_access_mode max_mode =
ril_network_max_supported_mode(self);
return pref_mode ? MIN(pref_mode, max_mode) : max_mode;
} }
static gboolean ril_network_need_initial_attach_apn(struct ril_network *self) static gboolean ril_network_need_initial_attach_apn(struct ril_network *self)
@@ -545,9 +587,9 @@ static gboolean ril_network_need_initial_attach_apn(struct ril_network *self)
if (watch->gprs && radio->state == RADIO_STATE_ON) { if (watch->gprs && radio->state == RADIO_STATE_ON) {
switch (ril_network_actual_pref_mode(self)) { switch (ril_network_actual_pref_mode(self)) {
case OFONO_RADIO_ACCESS_MODE_ANY:
case OFONO_RADIO_ACCESS_MODE_LTE: case OFONO_RADIO_ACCESS_MODE_LTE:
return TRUE; return TRUE;
case OFONO_RADIO_ACCESS_MODE_ANY:
case OFONO_RADIO_ACCESS_MODE_UMTS: case OFONO_RADIO_ACCESS_MODE_UMTS:
case OFONO_RADIO_ACCESS_MODE_GSM: case OFONO_RADIO_ACCESS_MODE_GSM:
break; break;
@@ -902,13 +944,25 @@ static void ril_network_check_pref_mode(struct ril_network *self,
gboolean immediate) gboolean immediate)
{ {
struct ril_network_priv *priv = self->priv; struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode expected_mode = struct ril_radio *radio = priv->radio;
/*
* On most dual-SIM phones only one slot at a time is allowed
* to use LTE. On some phones (such as Jolla C), even if the
* slot which has been using LTE gets powered off, we still
* need to explicitly set its preferred mode to GSM, to make
* LTE machinery available to the other slot. This behavior is
* configurable.
*/
if (radio->state == RADIO_STATE_ON || priv->force_gsm_when_radio_off) {
const enum ofono_radio_access_mode expected =
ril_network_actual_pref_mode(self); ril_network_actual_pref_mode(self);
const enum ofono_radio_access_mode current_mode = const enum ofono_radio_access_mode actual =
ril_network_rat_to_mode(priv->rat); ril_network_rat_to_mode(priv->rat);
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) { if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
ril_network_stop_timer(self, TIMER_FORCE_CHECK_PREF_MODE); ril_network_stop_timer(self,
TIMER_FORCE_CHECK_PREF_MODE);
/* /*
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by * TIMER_FORCE_CHECK_PREF_MODE is scheduled by
* ril_network_pref_mode_changed_cb and is meant * ril_network_pref_mode_changed_cb and is meant
@@ -917,18 +971,18 @@ static void ril_network_check_pref_mode(struct ril_network *self,
immediate = TRUE; immediate = TRUE;
} }
if (priv->rat >= 0 && current_mode != expected_mode) { if (priv->rat >= 0 && actual != expected) {
DBG_(self, "rat %d (%s), expected %s", priv->rat, DBG_(self, "rat %d (%s), expected %s", priv->rat,
ofono_radio_access_mode_to_string(current_mode), ofono_radio_access_mode_to_string(actual),
ofono_radio_access_mode_to_string(expected_mode)); ofono_radio_access_mode_to_string(expected));
} }
if (immediate) { if (immediate) {
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF); ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
} }
if (current_mode != expected_mode || priv->assert_rat) { if (actual != expected || priv->assert_rat) {
const int rat = ril_network_mode_to_rat(self, expected_mode); const int rat = ril_network_mode_to_rat(self, expected);
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) { if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
ril_network_set_pref_mode(self, rat); ril_network_set_pref_mode(self, rat);
@@ -937,6 +991,15 @@ static void ril_network_check_pref_mode(struct ril_network *self,
DBG_(self, "need to set rat mode %d", rat); DBG_(self, "need to set rat mode %d", rat);
} }
} }
}
}
static void ril_network_assert_pref_mode(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
priv->assert_rat = TRUE;
ril_network_check_pref_mode(self, FALSE);
} }
static int ril_network_parse_pref_resp(const void *data, guint len) static int ril_network_parse_pref_resp(const void *data, guint len)
@@ -968,10 +1031,10 @@ static void ril_network_startup_query_pref_mode_cb(GRilIoChannel *io,
} }
/* /*
* Unlike ril_network_query_pref_mode_cb, this one always * At startup, the device may have an inconsistency between
* checks the preferred mode. * voice and data network modes, so it needs to be asserted.
*/ */
ril_network_check_pref_mode(self, FALSE); ril_network_assert_pref_mode(self);
} }
} }
@@ -982,11 +1045,10 @@ static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
struct ril_network_priv *priv = self->priv; struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode pref_mode = self->pref_mode; const enum ofono_radio_access_mode pref_mode = self->pref_mode;
/* This request never fails because in case of error it gets retried */
GASSERT(status == RIL_E_SUCCESS);
GASSERT(priv->query_rat_id); GASSERT(priv->query_rat_id);
priv->query_rat_id = 0; priv->query_rat_id = 0;
if (status == RIL_E_SUCCESS) {
priv->rat = ril_network_parse_pref_resp(data, len); priv->rat = ril_network_parse_pref_resp(data, len);
self->pref_mode = ril_network_rat_to_mode(priv->rat); self->pref_mode = ril_network_rat_to_mode(priv->rat);
DBG_(self, "rat mode %d (%s)", priv->rat, DBG_(self, "rat mode %d (%s)", priv->rat,
@@ -999,6 +1061,7 @@ static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
if (ril_network_can_set_pref_mode(self)) { if (ril_network_can_set_pref_mode(self)) {
ril_network_check_pref_mode(self, FALSE); ril_network_check_pref_mode(self, FALSE);
} }
}
} }
static void ril_network_query_pref_mode(struct ril_network *self) static void ril_network_query_pref_mode(struct ril_network *self)
@@ -1007,6 +1070,7 @@ static void ril_network_query_pref_mode(struct ril_network *self)
GRilIoRequest *req = grilio_request_new(); GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1); grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
grilio_request_set_retry_func(req, ril_network_retry);
grilio_queue_cancel_request(priv->q, priv->query_rat_id, FALSE); grilio_queue_cancel_request(priv->q, priv->query_rat_id, FALSE);
priv->query_rat_id = grilio_queue_send_request_full(priv->q, req, priv->query_rat_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
@@ -1023,19 +1087,79 @@ void ril_network_set_max_pref_mode(struct ril_network *self,
DBG_(self, "rat mode %d (%s)", max_mode, DBG_(self, "rat mode %d (%s)", max_mode,
ofono_radio_access_mode_to_string(max_mode)); ofono_radio_access_mode_to_string(max_mode));
self->max_pref_mode = max_mode; self->max_pref_mode = max_mode;
ril_network_emit(self, SIGNAL_MAX_PREF_MODE_CHANGED);
ril_network_check_initial_attach_apn(self); ril_network_check_initial_attach_apn(self);
} }
ril_network_check_pref_mode(self, TRUE); ril_network_check_pref_mode(self, TRUE);
} }
} }
void ril_network_assert_pref_mode(struct ril_network *self, gboolean immediate) static void ril_network_supported_modes_handler(struct ril_radio_caps *caps,
void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
DBG_(self, "%s", ofono_radio_access_mode_to_string
(caps->supported_modes));
ril_network_check_pref_mode(self, TRUE);
}
static void ril_network_radio_capability_tx_done_cb
(struct ril_radio_caps_manager *mgr, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
DBG_(self, "");
ril_network_assert_pref_mode(self);
}
static void ril_network_release_radio_caps(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
struct ril_radio_caps *caps = priv->caps;
if (caps) {
ril_radio_caps_manager_remove_all_handlers(caps->mgr,
priv->caps_mgr_event_id);
ril_radio_caps_remove_handler(caps,
priv->supported_modes_event_id);
ril_radio_caps_unref(caps);
priv->caps = NULL;
priv->supported_modes_event_id = 0;
}
}
static void ril_network_attach_radio_caps(struct ril_network *self,
struct ril_radio_caps *caps)
{ {
struct ril_network_priv *priv = self->priv; struct ril_network_priv *priv = self->priv;
priv->assert_rat = TRUE; priv->caps = ril_radio_caps_ref(caps);
ril_network_check_pref_mode(self, immediate); priv->supported_modes_event_id =
ril_radio_caps_add_supported_modes_handler(caps,
ril_network_supported_modes_handler, self);
priv->caps_mgr_event_id[RADIO_CAPS_MGR_TX_DONE] =
ril_radio_caps_manager_add_tx_done_handler(caps->mgr,
ril_network_radio_capability_tx_done_cb, self);
priv->caps_mgr_event_id[RADIO_CAPS_MGR_TX_ABORTED] =
ril_radio_caps_manager_add_tx_aborted_handler(caps->mgr,
ril_network_radio_capability_tx_done_cb, self);
}
void ril_network_set_radio_caps(struct ril_network *self,
struct ril_radio_caps *caps)
{
if (self) {
struct ril_network_priv *priv = self->priv;
if (priv->caps != caps) {
ril_network_release_radio_caps(self);
if (caps) {
ril_network_attach_radio_caps(self, caps);
}
ril_network_check_pref_mode(self, TRUE);
}
}
} }
gulong ril_network_add_operator_changed_handler(struct ril_network *self, gulong ril_network_add_operator_changed_handler(struct ril_network *self,
@@ -1066,13 +1190,6 @@ gulong ril_network_add_pref_mode_changed_handler(struct ril_network *self,
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0; SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
} }
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_MAX_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_network_remove_handler(struct ril_network *self, gulong id) void ril_network_remove_handler(struct ril_network *self, gulong id)
{ {
if (G_LIKELY(self) && G_LIKELY(id)) { if (G_LIKELY(self) && G_LIKELY(id)) {
@@ -1095,16 +1212,6 @@ static void ril_network_state_changed_cb(GRilIoChannel *io, guint code,
ril_network_poll_state(self); ril_network_poll_state(self);
} }
static void ril_network_radio_capability_changed_cb(GRilIoChannel *io,
guint code, const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
DBG_(self, "");
GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
ril_network_assert_pref_mode(self, FALSE);
}
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data) static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
{ {
struct ril_network *self = RIL_NETWORK(data); struct ril_network *self = RIL_NETWORK(data);
@@ -1228,6 +1335,7 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
priv->lte_network_mode = config->lte_network_mode; priv->lte_network_mode = config->lte_network_mode;
priv->umts_network_mode = config->umts_network_mode; priv->umts_network_mode = config->umts_network_mode;
priv->network_mode_timeout = config->network_mode_timeout; priv->network_mode_timeout = config->network_mode_timeout;
priv->force_gsm_when_radio_off = config->force_gsm_when_radio_off;
priv->use_data_profiles = config->use_data_profiles; priv->use_data_profiles = config->use_data_profiles;
priv->mms_data_profile_id = config->mms_data_profile_id; priv->mms_data_profile_id = config->mms_data_profile_id;
@@ -1236,10 +1344,6 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
grilio_channel_add_unsol_event_handler(priv->io, grilio_channel_add_unsol_event_handler(priv->io,
ril_network_state_changed_cb, ril_network_state_changed_cb,
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self); RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
priv->unsol_event_id[UNSOL_EVENT_RADIO_CAPABILITY] =
grilio_channel_add_unsol_event_handler(priv->io,
ril_network_radio_capability_changed_cb,
RIL_UNSOL_RADIO_CAPABILITY, self);
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] = priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
ril_radio_add_state_changed_handler(priv->radio, ril_radio_add_state_changed_handler(priv->radio,
@@ -1334,6 +1438,7 @@ static void ril_network_finalize(GObject *object)
grilio_channel_remove_all_handlers(priv->io, priv->unsol_event_id); grilio_channel_remove_all_handlers(priv->io, priv->unsol_event_id);
grilio_channel_unref(priv->io); grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q); grilio_queue_unref(priv->q);
ril_network_release_radio_caps(self);
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id); ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
ril_radio_unref(priv->radio); ril_radio_unref(priv->radio);
ril_sim_card_remove_all_handlers(priv->simcard, priv->simcard_event_id); ril_sim_card_remove_all_handlers(priv->simcard, priv->simcard_event_id);
@@ -1355,7 +1460,6 @@ static void ril_network_class_init(RilNetworkClass *klass)
RIL_NETWORK_SIGNAL(klass, VOICE_STATE); RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
RIL_NETWORK_SIGNAL(klass, DATA_STATE); RIL_NETWORK_SIGNAL(klass, DATA_STATE);
RIL_NETWORK_SIGNAL(klass, PREF_MODE); RIL_NETWORK_SIGNAL(klass, PREF_MODE);
RIL_NETWORK_SIGNAL(klass, MAX_PREF_MODE);
} }
/* /*

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2019 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -21,6 +22,7 @@
#include <glib-object.h> #include <glib-object.h>
struct ofono_network_operator; struct ofono_network_operator;
struct ril_radio_caps;
struct ril_registration_state { struct ril_registration_state {
int status; /* enum network_registration_status */ int status; /* enum network_registration_status */
@@ -42,7 +44,6 @@ struct ril_network {
struct ril_sim_settings *settings; struct ril_sim_settings *settings;
}; };
struct ofono_sim;
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg); typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io, struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
@@ -54,10 +55,13 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
struct ril_network *ril_network_ref(struct ril_network *net); struct ril_network *ril_network_ref(struct ril_network *net);
void ril_network_unref(struct ril_network *net); void ril_network_unref(struct ril_network *net);
void ril_network_set_radio_caps(struct ril_network *net,
struct ril_radio_caps *caps);
void ril_network_set_max_pref_mode(struct ril_network *net, void ril_network_set_max_pref_mode(struct ril_network *net,
enum ofono_radio_access_mode max_pref_mode, enum ofono_radio_access_mode max_pref_mode,
gboolean force_check); gboolean force_check);
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate); enum ofono_radio_access_mode ril_network_max_supported_mode
(struct ril_network *self);
void ril_network_query_registration_state(struct ril_network *net); void ril_network_query_registration_state(struct ril_network *net);
gulong ril_network_add_operator_changed_handler(struct ril_network *net, gulong ril_network_add_operator_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg); ril_network_cb_t cb, void *arg);
@@ -67,8 +71,6 @@ gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg); ril_network_cb_t cb, void *arg);
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net, gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg); ril_network_cb_t cb, void *arg);
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
void ril_network_remove_handler(struct ril_network *net, gulong id); void ril_network_remove_handler(struct ril_network *net, gulong id);
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n); void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2017 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -32,6 +33,11 @@ struct ril_oem_raw {
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args) #define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
static void ril_oem_raw_send_done(void *msg)
{
dbus_message_unref(msg);
}
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status, static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data) const void *data, guint len, void *user_data)
{ {
@@ -40,20 +46,13 @@ static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
if (ril_status == RIL_E_SUCCESS) { if (ril_status == RIL_E_SUCCESS) {
DBusMessageIter it, array; DBusMessageIter it, array;
const guchar* bytes = data;
guint i;
reply = dbus_message_new_method_return(msg); reply = dbus_message_new_method_return(msg);
dbus_message_iter_init_append(reply, &it); dbus_message_iter_init_append(reply, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING, &array); DBUS_TYPE_BYTE_AS_STRING, &array);
dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
for (i = 0; i < len; i++) { &data, len);
guchar byte = bytes[i];
dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE,
&byte);
}
dbus_message_iter_close_container(&it, &array); dbus_message_iter_close_container(&it, &array);
} else if (ril_status == GRILIO_STATUS_TIMEOUT) { } else if (ril_status == GRILIO_STATUS_TIMEOUT) {
DBG("Timed out"); DBG("Timed out");
@@ -63,7 +62,7 @@ static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
reply = __ofono_error_failed(msg); reply = __ofono_error_failed(msg);
} }
__ofono_dbus_pending_reply(&msg, reply); g_dbus_send_message(ofono_dbus_get_connection(), reply);
} }
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg, static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
@@ -72,6 +71,12 @@ static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
DBusMessageIter it; DBusMessageIter it;
struct ril_oem_raw *oem = user_data; struct ril_oem_raw *oem = user_data;
if (!__ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
OFONO_DBUS_ACCESS_INTF_OEMRAW,
OFONO_DBUS_ACCESS_OEMRAW_SEND, NULL)) {
return __ofono_error_access_denied(msg);
}
dbus_message_iter_init(msg, &it); dbus_message_iter_init(msg, &it);
if (dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY && if (dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY &&
dbus_message_iter_get_element_type(&it) == DBUS_TYPE_BYTE) { dbus_message_iter_get_element_type(&it) == DBUS_TYPE_BYTE) {
@@ -94,7 +99,7 @@ static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
grilio_request_append_bytes(req, data, data_len); grilio_request_append_bytes(req, data, data_len);
grilio_queue_send_request_full(oem->q, req, grilio_queue_send_request_full(oem->q, req,
RIL_REQUEST_OEM_HOOK_RAW, ril_oem_raw_send_cb, RIL_REQUEST_OEM_HOOK_RAW, ril_oem_raw_send_cb,
NULL, dbus_message_ref(msg)); ril_oem_raw_send_done, dbus_message_ref(msg));
grilio_request_unref(req); grilio_request_unref(req);
return NULL; return NULL;
} else { } else {

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2019 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -27,7 +28,10 @@
#include "ril_devmon.h" #include "ril_devmon.h"
#include "ril_log.h" #include "ril_log.h"
#include <ofono/sailfish_manager.h> #include "ofono.h"
#include "sailfish_manager.h"
#include <ofono/storage.h>
#include <ofono/watch.h> #include <ofono/watch.h>
#include <grilio_transport.h> #include <grilio_transport.h>
@@ -60,7 +64,7 @@
#define RIL_SUB_SIZE 4 #define RIL_SUB_SIZE 4
#define RILMODEM_CONF_FILE CONFIGDIR "/ril_subscription.conf" #define RILMODEM_CONF_FILE "ril_subscription.conf"
#define RILMODEM_DEFAULT_IDENTITY "radio:radio" #define RILMODEM_DEFAULT_IDENTITY "radio:radio"
#define RILMODEM_DEFAULT_SOCK "/dev/socket/rild" #define RILMODEM_DEFAULT_SOCK "/dev/socket/rild"
#define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2" #define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2"
@@ -69,6 +73,9 @@
#define RILMODEM_DEFAULT_LTE_MODE PREF_NET_TYPE_LTE_GSM_WCDMA #define RILMODEM_DEFAULT_LTE_MODE PREF_NET_TYPE_LTE_GSM_WCDMA
#define RILMODEM_DEFAULT_UMTS_MODE PREF_NET_TYPE_GSM_WCDMA_AUTO #define RILMODEM_DEFAULT_UMTS_MODE PREF_NET_TYPE_GSM_WCDMA_AUTO
#define RILMODEM_DEFAULT_NETWORK_MODE_TIMEOUT (20*1000) /* ms */ #define RILMODEM_DEFAULT_NETWORK_MODE_TIMEOUT (20*1000) /* ms */
#define RILMODEM_DEFAULT_NETWORK_SELECTION_TIMEOUT (100*1000) /* ms */
#define RILMODEM_DEFAULT_DBM_WEAK (-100) /* very weak, 0.0000000001 mW */
#define RILMODEM_DEFAULT_DBM_STRONG (-60) /* strong signal, 0.000001 mW */
#define RILMODEM_DEFAULT_ENABLE_VOICECALL TRUE #define RILMODEM_DEFAULT_ENABLE_VOICECALL TRUE
#define RILMODEM_DEFAULT_ENABLE_CBS TRUE #define RILMODEM_DEFAULT_ENABLE_CBS TRUE
#define RILMODEM_DEFAULT_ENABLE_STK TRUE #define RILMODEM_DEFAULT_ENABLE_STK TRUE
@@ -76,7 +83,8 @@
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */ #define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND #define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
#define RILMODEM_DEFAULT_DATA_OPT RIL_ALLOW_DATA_AUTO #define RILMODEM_DEFAULT_DATA_OPT RIL_ALLOW_DATA_AUTO
#define RILMODEM_DEFAULT_DM_FLAGS RIL_DATA_MANAGER_3GLTE_HANDOVER #define RILMODEM_DEFAULT_DM_FLAGS (RIL_DATA_MANAGER_3GLTE_HANDOVER | \
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS)
#define RILMODEM_DEFAULT_START_TIMEOUT 20000 /* ms */ #define RILMODEM_DEFAULT_START_TIMEOUT 20000 /* ms */
#define RILMODEM_DEFAULT_DATA_CALL_FORMAT RIL_DATA_CALL_FORMAT_AUTO #define RILMODEM_DEFAULT_DATA_CALL_FORMAT RIL_DATA_CALL_FORMAT_AUTO
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT 4 #define RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT 4
@@ -86,7 +94,9 @@
#define RILMODEM_DEFAULT_LEGACY_IMEI_QUERY FALSE #define RILMODEM_DEFAULT_LEGACY_IMEI_QUERY FALSE
#define RILMODEM_DEFAULT_RADIO_POWER_CYCLE TRUE #define RILMODEM_DEFAULT_RADIO_POWER_CYCLE TRUE
#define RILMODEM_DEFAULT_CONFIRM_RADIO_POWER_ON TRUE #define RILMODEM_DEFAULT_CONFIRM_RADIO_POWER_ON TRUE
#define RILMODEM_DEFAULT_REPLACE_STRANGE_OPER FALSE
#define RILMODEM_DEFAULT_NETWORK_SELECTION_MANUAL_0 TRUE #define RILMODEM_DEFAULT_NETWORK_SELECTION_MANUAL_0 TRUE
#define RILMODEM_DEFAULT_FORCE_GSM_WHEN_RADIO_OFF TRUE
#define RILMODEM_DEFAULT_USE_DATA_PROFILES FALSE #define RILMODEM_DEFAULT_USE_DATA_PROFILES FALSE
#define RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID RIL_DATA_PROFILE_IMS #define RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID RIL_DATA_PROFILE_IMS
#define RILMODEM_DEFAULT_SLOT_FLAGS SAILFISH_SLOT_NO_FLAGS #define RILMODEM_DEFAULT_SLOT_FLAGS SAILFISH_SLOT_NO_FLAGS
@@ -106,6 +116,7 @@
#define RILCONF_SETTINGS_EMPTY "EmptyConfig" #define RILCONF_SETTINGS_EMPTY "EmptyConfig"
#define RILCONF_SETTINGS_IDENTITY "Identity" #define RILCONF_SETTINGS_IDENTITY "Identity"
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover" #define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
#define RILCONF_SETTINGS_GSM_NON_DATA_SLOTS "ForceGsmForNonDataSlots"
#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability" #define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
#define RILCONF_MODEM_PREFIX "ril_" #define RILCONF_MODEM_PREFIX "ril_"
@@ -125,6 +136,8 @@
#define RILCONF_LTE_MODE "lteNetworkMode" #define RILCONF_LTE_MODE "lteNetworkMode"
#define RILCONF_UMTS_MODE "umtsNetworkMode" #define RILCONF_UMTS_MODE "umtsNetworkMode"
#define RILCONF_NETWORK_MODE_TIMEOUT "networkModeTimeout" #define RILCONF_NETWORK_MODE_TIMEOUT "networkModeTimeout"
#define RILCONF_NETWORK_SELECTION_TIMEOUT "networkSelectionTimeout"
#define RILCONF_SIGNAL_STRENGTH_RANGE "signalStrengthRange"
#define RILCONF_UICC_WORKAROUND "uiccWorkaround" #define RILCONF_UICC_WORKAROUND "uiccWorkaround"
#define RILCONF_ECCLIST_FILE "ecclistFile" #define RILCONF_ECCLIST_FILE "ecclistFile"
#define RILCONF_ALLOW_DATA_REQ "allowDataReq" #define RILCONF_ALLOW_DATA_REQ "allowDataReq"
@@ -139,7 +152,9 @@
#define RILCONF_RADIO_POWER_CYCLE "radioPowerCycle" #define RILCONF_RADIO_POWER_CYCLE "radioPowerCycle"
#define RILCONF_CONFIRM_RADIO_POWER_ON "confirmRadioPowerOn" #define RILCONF_CONFIRM_RADIO_POWER_ON "confirmRadioPowerOn"
#define RILCONF_SINGLE_DATA_CONTEXT "singleDataContext" #define RILCONF_SINGLE_DATA_CONTEXT "singleDataContext"
#define RILCONF_REPLACE_STRANGE_OPER "replaceStrangeOperatorNames"
#define RILCONF_NETWORK_SELECTION_MANUAL_0 "networkSelectionManual0" #define RILCONF_NETWORK_SELECTION_MANUAL_0 "networkSelectionManual0"
#define RILCONF_FORCE_GSM_WHEN_RADIO_OFF "forceGsmWhenRadioOff"
#define RILCONF_USE_DATA_PROFILES "useDataProfiles" #define RILCONF_USE_DATA_PROFILES "useDataProfiles"
#define RILCONF_MMS_DATA_PROFILE_ID "mmsDataProfileId" #define RILCONF_MMS_DATA_PROFILE_ID "mmsDataProfileId"
#define RILCONF_DEVMON "deviceStateTracking" #define RILCONF_DEVMON "deviceStateTracking"
@@ -168,10 +183,9 @@ enum ril_set_radio_cap_opt {
}; };
enum ril_devmon_opt { enum ril_devmon_opt {
RIL_DEVMON_NONE, RIL_DEVMON_SS = 0x01,
RIL_DEVMON_AUTO, RIL_DEVMON_DS = 0x02,
RIL_DEVMON_SS, RIL_DEVMON_UR = 0x04
RIL_DEVMON_DS
}; };
struct ril_plugin_identity { struct ril_plugin_identity {
@@ -216,6 +230,7 @@ typedef struct sailfish_slot_impl {
struct ril_modem *modem; struct ril_modem *modem;
struct ril_radio *radio; struct ril_radio *radio;
struct ril_radio_caps *caps; struct ril_radio_caps *caps;
struct ril_radio_caps_request *caps_req;
struct ril_network *network; struct ril_network *network;
struct ril_sim_card *sim_card; struct ril_sim_card *sim_card;
struct ril_sim_settings *sim_settings; struct ril_sim_settings *sim_settings;
@@ -352,6 +367,7 @@ static void ril_plugin_remove_slot_handler(ril_slot *slot, int id)
static void ril_plugin_shutdown_slot(ril_slot *slot, gboolean kill_io) static void ril_plugin_shutdown_slot(ril_slot *slot, gboolean kill_io)
{ {
if (slot->modem) { if (slot->modem) {
ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
ril_modem_delete(slot->modem); ril_modem_delete(slot->modem);
/* The above call is expected to result in /* The above call is expected to result in
* ril_plugin_modem_removed getting called * ril_plugin_modem_removed getting called
@@ -371,12 +387,16 @@ static void ril_plugin_shutdown_slot(ril_slot *slot, gboolean kill_io)
} }
if (slot->cell_info) { if (slot->cell_info) {
sailfish_manager_set_cell_info(slot->handle, NULL);
sailfish_cell_info_unref(slot->cell_info); sailfish_cell_info_unref(slot->cell_info);
slot->cell_info = NULL; slot->cell_info = NULL;
} }
if (slot->caps) { if (slot->caps) {
ril_radio_caps_unref(slot->caps); ril_network_set_radio_caps(slot->network, NULL);
ril_radio_caps_request_free(slot->caps_req);
ril_radio_caps_drop(slot->caps);
slot->caps_req = NULL;
slot->caps = NULL; slot->caps = NULL;
} }
@@ -833,7 +853,7 @@ static void ril_plugin_create_modem(ril_slot *slot)
modem = ril_modem_create(slot->io, log_prefix, slot->path, slot->imei, modem = ril_modem_create(slot->io, log_prefix, slot->path, slot->imei,
slot->imeisv, slot->ecclist_file, &slot->config, slot->radio, slot->imeisv, slot->ecclist_file, &slot->config, slot->radio,
slot->network, slot->sim_card, slot->data, slot->sim_settings, slot->network, slot->sim_card, slot->data, slot->sim_settings,
slot->cell_info); slot->vendor, slot->cell_info);
if (modem) { if (modem) {
slot->modem = modem; slot->modem = modem;
@@ -890,7 +910,7 @@ static void ril_plugin_radio_caps_cb(const struct ril_radio_capability *cap,
plugin->caps_manager = ril_radio_caps_manager_new plugin->caps_manager = ril_radio_caps_manager_new
(plugin->data_manager); (plugin->data_manager);
plugin->caps_manager_event_id = plugin->caps_manager_event_id =
ril_radio_caps_manager_add_aborted_handler( ril_radio_caps_manager_add_tx_aborted_handler(
plugin->caps_manager, plugin->caps_manager,
ril_plugin_caps_switch_aborted, ril_plugin_caps_switch_aborted,
plugin); plugin);
@@ -898,15 +918,17 @@ static void ril_plugin_radio_caps_cb(const struct ril_radio_capability *cap,
GASSERT(!slot->caps); GASSERT(!slot->caps);
slot->caps = ril_radio_caps_new(plugin->caps_manager, slot->caps = ril_radio_caps_new(plugin->caps_manager,
ril_plugin_log_prefix(slot), slot->io, slot->data, ril_plugin_log_prefix(slot), slot->io, slot->watch,
slot->radio, slot->sim_card, slot->network, slot->data, slot->radio, slot->sim_card,
&slot->config, cap); slot->sim_settings, &slot->config, cap);
ril_network_set_radio_caps(slot->network, slot->caps);
} }
} }
static void ril_plugin_manager_started(ril_plugin *plugin) static void ril_plugin_manager_started(ril_plugin *plugin)
{ {
ril_plugin_drop_orphan_slots(plugin); ril_plugin_drop_orphan_slots(plugin);
ril_data_manager_check_data(plugin->data_manager);
sailfish_slot_manager_started(plugin->handle); sailfish_slot_manager_started(plugin->handle);
} }
@@ -1027,13 +1049,13 @@ static void ril_plugin_slot_connected(ril_slot *slot)
slot->path, slot->config.techs, slot->imei, slot->path, slot->config.techs, slot->imei,
slot->imeisv, ril_plugin_sim_state(slot), slot->imeisv, ril_plugin_sim_state(slot),
slot->slot_flags); slot->slot_flags);
sailfish_manager_set_cell_info(slot->handle, slot->cell_info);
grilio_channel_set_enabled(slot->io, slot->handle->enabled); grilio_channel_set_enabled(slot->io, slot->handle->enabled);
/* Check if this was the last slot we were waiting for */ /* Check if this was the last slot we were waiting for */
ril_plugin_check_if_started(plugin); ril_plugin_check_if_started(plugin);
} }
sailfish_manager_set_cell_info(slot->handle, slot->cell_info);
ril_plugin_check_modem(slot); ril_plugin_check_modem(slot);
ril_plugin_check_ready(slot); ril_plugin_check_ready(slot);
} }
@@ -1049,8 +1071,11 @@ static void ril_plugin_slot_connected_cb(GRilIoChannel *io, void *user_data)
static void ril_plugin_init_io(ril_slot *slot) static void ril_plugin_init_io(ril_slot *slot)
{ {
if (!slot->io) { if (!slot->io) {
slot->io = grilio_channel_new(ofono_ril_transport_connect struct grilio_transport *transport =
(slot->transport_name, slot->transport_params)); ofono_ril_transport_connect(slot->transport_name,
slot->transport_params);
slot->io = grilio_channel_new(transport);
if (slot->io) { if (slot->io) {
ril_debug_trace_update(slot); ril_debug_trace_update(slot);
ril_debug_dump_update(slot); ril_debug_dump_update(slot);
@@ -1082,6 +1107,7 @@ static void ril_plugin_init_io(ril_slot *slot)
slot); slot);
} }
} }
grilio_transport_unref(transport);
} }
if (!slot->io) { if (!slot->io) {
@@ -1127,6 +1153,8 @@ static void ril_plugin_slot_modem_changed(struct ofono_watch *w,
slot->modem = NULL; slot->modem = NULL;
ril_data_allow(slot->data, RIL_DATA_ROLE_NONE); ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
ril_radio_caps_request_free(slot->caps_req);
slot->caps_req = NULL;
} }
} }
@@ -1181,6 +1209,11 @@ static ril_slot *ril_plugin_slot_new_take(char *transport,
config->techs = RILMODEM_DEFAULT_TECHS; config->techs = RILMODEM_DEFAULT_TECHS;
config->lte_network_mode = RILMODEM_DEFAULT_LTE_MODE; config->lte_network_mode = RILMODEM_DEFAULT_LTE_MODE;
config->umts_network_mode = RILMODEM_DEFAULT_UMTS_MODE; config->umts_network_mode = RILMODEM_DEFAULT_UMTS_MODE;
config->network_mode_timeout = RILMODEM_DEFAULT_NETWORK_MODE_TIMEOUT;
config->network_selection_timeout =
RILMODEM_DEFAULT_NETWORK_SELECTION_TIMEOUT;
config->signal_strength_dbm_weak = RILMODEM_DEFAULT_DBM_WEAK;
config->signal_strength_dbm_strong = RILMODEM_DEFAULT_DBM_STRONG;
config->empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY; config->empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
config->radio_power_cycle = RILMODEM_DEFAULT_RADIO_POWER_CYCLE; config->radio_power_cycle = RILMODEM_DEFAULT_RADIO_POWER_CYCLE;
config->confirm_radio_power_on = config->confirm_radio_power_on =
@@ -1190,8 +1223,11 @@ static ril_slot *ril_plugin_slot_new_take(char *transport,
config->enable_stk = RILMODEM_DEFAULT_ENABLE_STK; config->enable_stk = RILMODEM_DEFAULT_ENABLE_STK;
config->query_available_band_mode = config->query_available_band_mode =
RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE; RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE;
config->replace_strange_oper = RILMODEM_DEFAULT_REPLACE_STRANGE_OPER;
config->network_selection_manual_0 = config->network_selection_manual_0 =
RILMODEM_DEFAULT_NETWORK_SELECTION_MANUAL_0; RILMODEM_DEFAULT_NETWORK_SELECTION_MANUAL_0;
config->force_gsm_when_radio_off =
RILMODEM_DEFAULT_FORCE_GSM_WHEN_RADIO_OFF;
config->use_data_profiles = RILMODEM_DEFAULT_USE_DATA_PROFILES; config->use_data_profiles = RILMODEM_DEFAULT_USE_DATA_PROFILES;
config->mms_data_profile_id = RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID; config->mms_data_profile_id = RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID;
slot->timeout = RILMODEM_DEFAULT_TIMEOUT; slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
@@ -1228,6 +1264,9 @@ static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
defaults.empty_pin_query = config->empty_pin_query; defaults.empty_pin_query = config->empty_pin_query;
defaults.mms_data_profile_id = config->mms_data_profile_id; defaults.mms_data_profile_id = config->mms_data_profile_id;
defaults.use_data_profiles = config->use_data_profiles; defaults.use_data_profiles = config->use_data_profiles;
defaults.replace_strange_oper = config->replace_strange_oper;
defaults.force_gsm_when_radio_off =
config->force_gsm_when_radio_off;
defaults.query_available_band_mode = defaults.query_available_band_mode =
config->query_available_band_mode; config->query_available_band_mode;
@@ -1238,6 +1277,9 @@ static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
config->empty_pin_query = defaults.empty_pin_query; config->empty_pin_query = defaults.empty_pin_query;
config->use_data_profiles = defaults.use_data_profiles; config->use_data_profiles = defaults.use_data_profiles;
config->mms_data_profile_id = defaults.mms_data_profile_id; config->mms_data_profile_id = defaults.mms_data_profile_id;
config->replace_strange_oper = defaults.replace_strange_oper;
config->force_gsm_when_radio_off =
defaults.force_gsm_when_radio_off;
config->query_available_band_mode = config->query_available_band_mode =
defaults.query_available_band_mode; defaults.query_available_band_mode;
} }
@@ -1347,6 +1389,7 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
char *sval; char *sval;
char **strv; char **strv;
char *modem; char *modem;
GUtilInts *ints;
GHashTable *transport_params = g_hash_table_new_full(g_str_hash, GHashTable *transport_params = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, g_free); g_str_equal, g_free, g_free);
char *transport = NULL; char *transport = NULL;
@@ -1458,6 +1501,14 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
config->enable_stk ? "yes" : "no"); config->enable_stk ? "yes" : "no");
} }
/* replaceStrangeOperatorNames */
if (ril_config_get_boolean(file, group,
RILCONF_REPLACE_STRANGE_OPER,
&config->replace_strange_oper)) {
DBG("%s: " RILCONF_REPLACE_STRANGE_OPER " %s", group,
config->replace_strange_oper ? "yes" : "no");
}
/* networkSelectionManual0 */ /* networkSelectionManual0 */
if (ril_config_get_boolean(file, group, if (ril_config_get_boolean(file, group,
RILCONF_NETWORK_SELECTION_MANUAL_0, RILCONF_NETWORK_SELECTION_MANUAL_0,
@@ -1466,6 +1517,14 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
config->network_selection_manual_0 ? "yes" : "no"); config->network_selection_manual_0 ? "yes" : "no");
} }
/* forceGsmWhenRadioOff */
if (ril_config_get_boolean(file, group,
RILCONF_FORCE_GSM_WHEN_RADIO_OFF,
&config->force_gsm_when_radio_off)) {
DBG("%s: " RILCONF_FORCE_GSM_WHEN_RADIO_OFF " %s", group,
config->force_gsm_when_radio_off ? "yes" : "no");
}
/* useDataProfiles */ /* useDataProfiles */
if (ril_config_get_boolean(file, group, RILCONF_USE_DATA_PROFILES, if (ril_config_get_boolean(file, group, RILCONF_USE_DATA_PROFILES,
&config->use_data_profiles)) { &config->use_data_profiles)) {
@@ -1536,6 +1595,29 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
config->network_mode_timeout); config->network_mode_timeout);
} }
/* networkSelectionTimeout */
if (ril_config_get_integer(file, group,
RILCONF_NETWORK_SELECTION_TIMEOUT,
&config->network_selection_timeout)) {
DBG("%s: " RILCONF_NETWORK_SELECTION_TIMEOUT " %d", group,
config->network_selection_timeout);
}
/* signalStrengthRange */
ints = ril_config_get_ints(file, group, RILCONF_SIGNAL_STRENGTH_RANGE);
if (gutil_ints_get_count(ints) == 2) {
const int* dbms = gutil_ints_get_data(ints, NULL);
/* MIN,MAX */
if (dbms[0] < dbms[1]) {
DBG("%s: " RILCONF_SIGNAL_STRENGTH_RANGE " [%d,%d]",
group, dbms[0], dbms[1]);
config->signal_strength_dbm_weak = dbms[0];
config->signal_strength_dbm_strong = dbms[1];
}
}
gutil_ints_unref(ints);
/* enable4G (deprecated but still supported) */ /* enable4G (deprecated but still supported) */
ival = config->techs; ival = config->techs;
if (ril_config_get_flag(file, group, RILCONF_4G, if (ril_config_get_flag(file, group, RILCONF_4G,
@@ -1661,23 +1743,32 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
} }
/* deviceStateTracking */ /* deviceStateTracking */
if (ril_config_get_enum(file, group, RILCONF_DEVMON, &ival, if (ril_config_get_mask(file, group, RILCONF_DEVMON, &ival,
"none", RIL_DEVMON_NONE,
"auto", RIL_DEVMON_AUTO,
"ds", RIL_DEVMON_DS, "ds", RIL_DEVMON_DS,
"ss", RIL_DEVMON_SS, NULL)) { "ss", RIL_DEVMON_SS,
DBG("%s: " RILCONF_DEVMON " %s", group, "ur", RIL_DEVMON_UR, NULL) && ival) {
ival == RIL_DEVMON_NONE ? "off" : int n = 0;
ival == RIL_DEVMON_DS ? "on" : struct ril_devmon *devmon[3];
ival == RIL_DEVMON_SS ? "legacy" :
"auto"); if (ival & RIL_DEVMON_DS) devmon[n++] = ril_devmon_ds_new();
if (ival != RIL_DEVMON_AUTO) { if (ival & RIL_DEVMON_SS) devmon[n++] = ril_devmon_ss_new();
/* Default is automatic, reallocate the object */ if (ival & RIL_DEVMON_UR) devmon[n++] = ril_devmon_ur_new();
DBG("%s: " RILCONF_DEVMON " 0x%x", group, ival);
ril_devmon_free(slot->devmon); ril_devmon_free(slot->devmon);
slot->devmon = slot->devmon = ril_devmon_combine(devmon, n);
(ival == RIL_DEVMON_DS ? ril_devmon_ds_new() : } else {
ival == RIL_DEVMON_SS ? ril_devmon_ss_new() : /* Try special values */
NULL); sval = ril_config_get_string(file, group, RILCONF_DEVMON);
if (sval) {
if (!g_ascii_strcasecmp(sval, "none")) {
DBG("%s: " RILCONF_DEVMON " %s", group, sval);
ril_devmon_free(slot->devmon);
slot->devmon = NULL;
} else if (!g_ascii_strcasecmp(sval, "auto")) {
DBG("%s: " RILCONF_DEVMON " %s", group, sval);
/* This is the default */
}
g_free(sval);
} }
} }
@@ -1817,6 +1908,12 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
RIL_DATA_MANAGER_3GLTE_HANDOVER, RIL_DATA_MANAGER_3GLTE_HANDOVER,
&ps->dm_flags); &ps->dm_flags);
/* ForceGsmForNonDataSlots */
ril_config_get_flag(file, group,
RILCONF_SETTINGS_GSM_NON_DATA_SLOTS,
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS,
&ps->dm_flags);
/* SetRadioCapability */ /* SetRadioCapability */
if (ril_config_get_enum(file, group, if (ril_config_get_enum(file, group,
RILCONF_SETTINGS_SET_RADIO_CAP, &ival, RILCONF_SETTINGS_SET_RADIO_CAP, &ival,
@@ -1856,7 +1953,7 @@ static GSList *ril_plugin_load_config(const char *path,
GKeyFile *file = g_key_file_new(); GKeyFile *file = g_key_file_new();
gboolean empty = FALSE; gboolean empty = FALSE;
ril_config_merge_files(file, path); config_merge_files(file, path);
if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP, if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP,
RILCONF_SETTINGS_EMPTY, &empty) && empty) { RILCONF_SETTINGS_EMPTY, &empty) && empty) {
DBG("Empty config"); DBG("Empty config");
@@ -2042,12 +2139,15 @@ static guint ril_plugin_manager_start(ril_plugin *plugin)
{ {
struct ril_plugin_settings *ps = &plugin->settings; struct ril_plugin_settings *ps = &plugin->settings;
guint start_timeout = 0; guint start_timeout = 0;
char* config_file = g_build_filename(ofono_config_dir(),
RILMODEM_CONF_FILE, NULL);
DBG(""); DBG("");
GASSERT(!plugin->start_timeout_id); GASSERT(!plugin->start_timeout_id);
plugin->slots = ril_plugin_load_config(RILMODEM_CONF_FILE, ps); plugin->slots = ril_plugin_load_config(config_file, ps);
plugin->data_manager = ril_data_manager_new(ps->dm_flags); plugin->data_manager = ril_data_manager_new(ps->dm_flags);
ril_plugin_init_slots(plugin); ril_plugin_init_slots(plugin);
g_free(config_file);
ofono_modem_driver_register(&ril_modem_driver); ofono_modem_driver_register(&ril_modem_driver);
ofono_sim_driver_register(&ril_sim_driver); ofono_sim_driver_register(&ril_sim_driver);
@@ -2099,10 +2199,24 @@ static void ril_plugin_manager_free(ril_plugin *plugin)
static void ril_slot_set_data_role(ril_slot *slot, enum sailfish_data_role r) static void ril_slot_set_data_role(ril_slot *slot, enum sailfish_data_role r)
{ {
ril_data_allow(slot->data, enum ril_data_role role =
(r == SAILFISH_DATA_ROLE_INTERNET) ? RIL_DATA_ROLE_INTERNET : (r == SAILFISH_DATA_ROLE_INTERNET) ? RIL_DATA_ROLE_INTERNET :
(r == SAILFISH_DATA_ROLE_MMS) ? RIL_DATA_ROLE_MMS : (r == SAILFISH_DATA_ROLE_MMS) ? RIL_DATA_ROLE_MMS :
RIL_DATA_ROLE_NONE); RIL_DATA_ROLE_NONE;
ril_data_allow(slot->data, role);
ril_radio_caps_request_free(slot->caps_req);
if (role == RIL_DATA_ROLE_NONE) {
slot->caps_req = NULL;
} else {
const enum ofono_radio_access_mode mode =
(r == SAILFISH_DATA_ROLE_MMS) ?
OFONO_RADIO_ACCESS_MODE_GSM :
__ofono_radio_access_max_mode
(slot->sim_settings->techs);
slot->caps_req = ril_radio_caps_request_new
(slot->caps, mode, role);
}
} }
static void ril_slot_enabled_changed(struct sailfish_slot_impl *s) static void ril_slot_enabled_changed(struct sailfish_slot_impl *s)

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2017 Jolla Ltd. * Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -52,6 +53,7 @@ struct ril_modem {
const char *ecclist_file; const char *ecclist_file;
struct ofono_modem *ofono; struct ofono_modem *ofono;
struct sailfish_cell_info *cell_info; struct sailfish_cell_info *cell_info;
struct ril_vendor *vendor;
struct ril_radio *radio; struct ril_radio *radio;
struct ril_data *data; struct ril_data *data;
struct ril_network *network; struct ril_network *network;
@@ -70,7 +72,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const char *ecclist_file, const struct ril_slot_config *config, const char *ecclist_file, const struct ril_slot_config *config,
struct ril_radio *radio, struct ril_network *network, struct ril_radio *radio, struct ril_network *network,
struct ril_sim_card *card, struct ril_data *data, struct ril_sim_card *card, struct ril_data *data,
struct ril_sim_settings *settings, struct ril_sim_settings *settings, struct ril_vendor *vendor,
struct sailfish_cell_info *cell_info); struct sailfish_cell_info *cell_info);
void ril_modem_delete(struct ril_modem *modem); void ril_modem_delete(struct ril_modem *modem);
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem); struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2019 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -13,6 +13,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_radio.h" #include "ril_radio.h"
#include "ril_util.h" #include "ril_util.h"
#include "ril_log.h" #include "ril_log.h"
@@ -239,7 +241,19 @@ static void ril_radio_power_request(struct ril_radio *self, gboolean on,
void ril_radio_confirm_power_on(struct ril_radio *self) void ril_radio_confirm_power_on(struct ril_radio *self)
{ {
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) { if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
ril_radio_power_request(self, TRUE, TRUE); struct ril_radio_priv *priv = self->priv;
if (priv->pending_id) {
if (!priv->next_state) {
/* Wait for the pending request to complete */
priv->next_state_valid = TRUE;
priv->next_state = TRUE;
DBG_(self, "on (queued)");
}
} else {
DBG_(self, "on");
ril_radio_submit_power_request(self, TRUE);
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2017 Jolla Ltd. * Copyright (C) 2017-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -19,12 +19,16 @@
#include "ril_types.h" #include "ril_types.h"
struct ril_data_manager; struct ril_data_manager;
struct ril_sim_settings;
struct ril_radio_caps; struct ril_radio_caps;
struct ril_radio_caps_manager; struct ril_radio_caps_manager;
struct ril_radio_capability; struct ril_radio_capability;
struct ril_radio_caps_request;
typedef void (*ril_radio_caps_cb_t)(struct ril_radio_caps *caps, void *arg);
typedef void (*ril_radio_caps_manager_cb_t)(struct ril_radio_caps_manager *mgr, typedef void (*ril_radio_caps_manager_cb_t)(struct ril_radio_caps_manager *mgr,
void *user_data); void *user_data);
/* ril_radio_capability pointer is NULL if functionality is unsupported */ /* ril_radio_capability pointer is NULL if functionality is unsupported */
typedef void (*ril_radio_caps_check_cb_t) typedef void (*ril_radio_caps_check_cb_t)
(const struct ril_radio_capability *cap, void *user_data); (const struct ril_radio_capability *cap, void *user_data);
@@ -39,21 +43,47 @@ struct ril_radio_caps_manager *ril_radio_caps_manager_new
struct ril_radio_caps_manager *ril_radio_caps_manager_ref struct ril_radio_caps_manager *ril_radio_caps_manager_ref
(struct ril_radio_caps_manager *mgr); (struct ril_radio_caps_manager *mgr);
void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr); void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr);
gulong ril_radio_caps_manager_add_aborted_handler gulong ril_radio_caps_manager_add_tx_aborted_handler
(struct ril_radio_caps_manager *mgr,
ril_radio_caps_manager_cb_t cb, void *arg);
gulong ril_radio_caps_manager_add_tx_done_handler
(struct ril_radio_caps_manager *mgr, (struct ril_radio_caps_manager *mgr,
ril_radio_caps_manager_cb_t cb, void *arg); ril_radio_caps_manager_cb_t cb, void *arg);
void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *mgr, void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *mgr,
gulong id); gulong id);
void ril_radio_caps_manager_remove_handlers(struct ril_radio_caps_manager *mgr,
gulong *ids, int count);
#define ril_radio_caps_manager_remove_all_handlers(mgr, ids) \
ril_radio_caps_manager_remove_handlers(mgr, ids, G_N_ELEMENTS(ids))
/* And one ril_radio_caps object per modem */ /* And one ril_radio_caps object per modem */
struct ril_radio_caps {
struct ril_radio_caps_manager *mgr;
enum ofono_radio_access_mode supported_modes;
};
struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr, struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
const char *log_prefix, GRilIoChannel *io, const char *log_prefix, GRilIoChannel *io,
struct ofono_watch *watch,
struct ril_data *data, struct ril_radio *radio, struct ril_data *data, struct ril_radio *radio,
struct ril_sim_card *sim, struct ril_network *net, struct ril_sim_card *sim, struct ril_sim_settings *settings,
const struct ril_slot_config *config, const struct ril_slot_config *config,
const struct ril_radio_capability *cap); const struct ril_radio_capability *cap);
struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps); struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps);
void ril_radio_caps_unref(struct ril_radio_caps *caps); void ril_radio_caps_unref(struct ril_radio_caps *caps);
void ril_radio_caps_drop(struct ril_radio_caps *caps);
gulong ril_radio_caps_add_supported_modes_handler
(struct ril_radio_caps *caps,
ril_radio_caps_cb_t cb, void *arg);
void ril_radio_caps_remove_handler(struct ril_radio_caps *caps, gulong id);
/* Data requests */
struct ril_radio_caps_request *ril_radio_caps_request_new
(struct ril_radio_caps *caps, enum ofono_radio_access_mode mode,
enum ril_data_role role);
void ril_radio_caps_request_free(struct ril_radio_caps_request *req);
#endif /* RIL_RADIO_CAPS_H */ #endif /* RIL_RADIO_CAPS_H */

View File

@@ -1131,9 +1131,9 @@ static void ril_sim_pin_change_state_status_cb(struct ril_sim_card *sc,
} else { } else {
DBG_(sd, "success, passwd_state=%d", ps); DBG_(sd, "success, passwd_state=%d", ps);
cbd->cb(ril_error_ok(&error), cbd->data); cbd->cb(ril_error_ok(&error), cbd->data);
ofono_sim_initialized_notify(sd->sim);
} }
ofono_sim_initialized_notify(sd->sim);
sd->pin_cbd_list = g_list_remove(sd->pin_cbd_list, cbd); sd->pin_cbd_list = g_list_remove(sd->pin_cbd_list, cbd);
ril_sim_pin_cbd_free(cbd); ril_sim_pin_cbd_free(cbd);
} else { } else {
@@ -1172,7 +1172,10 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
ril_sim_check_perm_lock(sd); ril_sim_check_perm_lock(sd);
cbd->ril_status = ril_status; cbd->ril_status = ril_status;
if (cbd->card_status_id && (!cbd->state_event_count ||
/* RIL_E_PASSWORD_INCORRECT is the final result, no need to wait */
if (ril_status != RIL_E_PASSWORD_INCORRECT &&
cbd->card_status_id && (!cbd->state_event_count ||
ril_sim_app_in_transient_state(sd))) { ril_sim_app_in_transient_state(sd))) {
GASSERT(!g_list_find(sd->pin_cbd_list, cbd)); GASSERT(!g_list_find(sd->pin_cbd_list, cbd));
@@ -1207,6 +1210,9 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
cbd->card_status_id); cbd->card_status_id);
cbd->card_status_id = 0; cbd->card_status_id = 0;
} }
/* Tell the core that we are ready to accept more requests */
ofono_sim_initialized_notify(sd->sim);
} }
} }

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2018 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -13,6 +13,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_sim_card.h" #include "ril_sim_card.h"
#include "ril_radio.h" #include "ril_radio.h"
#include "ril_util.h" #include "ril_util.h"

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2016-2019 Jolla Ltd. * Copyright (C) 2016-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -13,6 +13,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_sim_settings.h" #include "ril_sim_settings.h"
#include "ril_log.h" #include "ril_log.h"

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2016-2018 Jolla Ltd. * Copyright (C) 2016-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -45,6 +45,8 @@ gulong ril_sim_settings_add_pref_mode_changed_handler(struct ril_sim_settings *s
void ril_sim_settings_remove_handler(struct ril_sim_settings *s, gulong id); void ril_sim_settings_remove_handler(struct ril_sim_settings *s, gulong id);
void ril_sim_settings_remove_handlers(struct ril_sim_settings *s, gulong *ids, void ril_sim_settings_remove_handlers(struct ril_sim_settings *s, gulong *ids,
int count); int count);
#define ril_sim_settings_remove_all_handlers(s,ids) \
ril_sim_settings_remove_handlers(s, ids, G_N_ELEMENTS(ids))
#endif /* RIL_SIM_SETTINGS_H */ #endif /* RIL_SIM_SETTINGS_H */

View File

@@ -42,6 +42,13 @@
# #
#3GLTEHandover=true #3GLTEHandover=true
# If this option is on, preferred technology is set to GSM for non-data
# slots.
#
# Default true (for historical reasons)
#
#ForceGsmForNonDataSlots=true
# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL. # RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
# This option allows you to forcibly enable or disable use of this request. # This option allows you to forcibly enable or disable use of this request.
# It's involved in 3G/LTE handover between the modems, meaning that it only # It's involved in 3G/LTE handover between the modems, meaning that it only
@@ -230,6 +237,24 @@ socket=/dev/socket/rild
# #
#networkModeTimeout=20000 #networkModeTimeout=20000
# Timeout for RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC and
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, in milliseconds.
#
# Default 100000 (100 seconds)
#
#networkSelectionTimeout=100000
# Comma-separated signal strength range, in dBm.
#
# These values are used for translating dBm values returned by the modem in
# LTE mode into signal strength percentage. If you are getting significantly
# different signal strength readings in GSM and LTE modes, you may need to
# tweak those.
#
# Default -100,-60
#
#signalStrengthRange=-100,-60
# Cycle radio power at startup. # Cycle radio power at startup.
# #
# Default true (cycle the power) # Default true (cycle the power)
@@ -257,6 +282,16 @@ socket=/dev/socket/rild
# #
#singleDataContext=false #singleDataContext=false
# With some RILs, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS returns strange
# operator names, i.e. numeric MCC+MNC values or the same name for all
# operators (which is actually SPN fetched from the SIM). Such strange
# names can be replaced with operator names from MBPI database, based
# on the operator's MCC and MNC. That may not be 100% accurate, though.
#
# Default false (i.e. trust RIL to report the actual names)
#
#replaceStrangeOperatorNames=false
# Configures whether +0 is added to MCCMNC string passed to # Configures whether +0 is added to MCCMNC string passed to
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL. Some Qualcomm RILs # RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL. Some Qualcomm RILs
# require it, some MediaTek RILs don't like it. # require it, some MediaTek RILs don't like it.
@@ -284,9 +319,23 @@ socket=/dev/socket/rild
# #
# ss = Use legacy device state management (RIL_REQUEST_SCREEN_STATE) # ss = Use legacy device state management (RIL_REQUEST_SCREEN_STATE)
# ds = Use newer device state management (RIL_REQUEST_SEND_DEVICE_STATE) # ds = Use newer device state management (RIL_REQUEST_SEND_DEVICE_STATE)
# auto = Choose one of the above based on the RIL version # ur = Use URC filter (RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER)
# This may be useful on devices with RIL version >= 15 if auto
# method fails
# auto = Choose ss or ds based on the RIL version
# none = Disable device state management # none = Disable device state management
# #
# In addition to specifying ss, ds or ur method, one can specify a
# combination of methods, e.g. ds+ur
#
# Default auto # Default auto
# #
#deviceStateTracking=auto #deviceStateTracking=auto
# On some phones (such as Jolla C), even if the slot which has been
# using LTE gets powered off, we still need to explicitely set its
# preferred mode to GSM, to make LTE machinery available to the other slot.
#
# Default true (false for MTK RILs)
#
#forceGsmWhenRadioOff=true

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2019 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -23,6 +24,7 @@
#include <grilio_types.h> #include <grilio_types.h>
#include <gutil_macros.h> #include <gutil_macros.h>
struct ofono_watch;
struct ofono_modem; struct ofono_modem;
struct ofono_sim; struct ofono_sim;
@@ -48,12 +50,21 @@ struct ril_network;
struct ril_sim_card; struct ril_sim_card;
struct ril_vendor; struct ril_vendor;
enum ril_data_role {
RIL_DATA_ROLE_NONE, /* Mobile data not required */
RIL_DATA_ROLE_MMS, /* Data is needed at any speed */
RIL_DATA_ROLE_INTERNET /* Data is needed at full speed */
};
struct ril_slot_config { struct ril_slot_config {
guint slot; guint slot;
enum ofono_radio_access_mode techs; enum ofono_radio_access_mode techs;
enum ril_pref_net_type lte_network_mode; enum ril_pref_net_type lte_network_mode;
enum ril_pref_net_type umts_network_mode; enum ril_pref_net_type umts_network_mode;
int network_mode_timeout; int network_mode_timeout;
int network_selection_timeout;
int signal_strength_dbm_weak;
int signal_strength_dbm_strong;
gboolean query_available_band_mode; gboolean query_available_band_mode;
gboolean empty_pin_query; gboolean empty_pin_query;
gboolean radio_power_cycle; gboolean radio_power_cycle;
@@ -61,7 +72,9 @@ struct ril_slot_config {
gboolean enable_voicecall; gboolean enable_voicecall;
gboolean enable_cbs; gboolean enable_cbs;
gboolean enable_stk; gboolean enable_stk;
gboolean replace_strange_oper;
gboolean network_selection_manual_0; gboolean network_selection_manual_0;
gboolean force_gsm_when_radio_off;
gboolean use_data_profiles; gboolean use_data_profiles;
guint mms_data_profile_id; guint mms_data_profile_id;
GUtilInts *local_hangup_reasons; GUtilInts *local_hangup_reasons;

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2015-2018 Jolla Ltd. * Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -20,48 +21,77 @@
#include "smsutil.h" #include "smsutil.h"
#include "util.h" #include "util.h"
#define USSD_REQUEST_TIMEOUT_SEC (30)
#define USSD_CANCEL_TIMEOUT_SEC (20) #define USSD_CANCEL_TIMEOUT_SEC (20)
struct ril_ussd { struct ril_ussd {
struct ofono_ussd *ussd; struct ofono_ussd *ussd;
GRilIoChannel *io; GRilIoChannel *io;
GRilIoQueue *q; GRilIoQueue *q;
guint request_id;
guint cancel_id;
guint timer_id; guint timer_id;
gulong event_id; gulong event_id;
}; };
struct ril_ussd_cbd { struct ril_ussd_cbd {
struct ril_ussd *ud;
ofono_ussd_cb_t cb; ofono_ussd_cb_t cb;
gpointer data; gpointer data;
}; };
#define ril_ussd_cbd_free g_free
static inline struct ril_ussd *ril_ussd_get_data(struct ofono_ussd *ussd) static inline struct ril_ussd *ril_ussd_get_data(struct ofono_ussd *ussd)
{ {
return ofono_ussd_get_data(ussd); return ofono_ussd_get_data(ussd);
} }
static struct ril_ussd_cbd *ril_ussd_cbd_new(ofono_ussd_cb_t cb, void *data) static struct ril_ussd_cbd *ril_ussd_cbd_new(struct ril_ussd *ud,
ofono_ussd_cb_t cb, void *data)
{ {
struct ril_ussd_cbd *cbd = g_new0(struct ril_ussd_cbd, 1); struct ril_ussd_cbd *cbd = g_slice_new(struct ril_ussd_cbd);
cbd->ud = ud;
cbd->cb = cb; cbd->cb = cb;
cbd->data = data; cbd->data = data;
return cbd; return cbd;
} }
static void ril_ussd_cbd_free(void *cbd)
{
g_slice_free(struct ril_ussd_cbd, cbd);
}
static void ril_ussd_cancel_cb(GRilIoChannel *io, int status, static void ril_ussd_cancel_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data) const void *data, guint len, void *user_data)
{ {
struct ofono_error error; struct ofono_error error;
struct ril_ussd_cbd *cbd = user_data; struct ril_ussd_cbd *cbd = user_data;
struct ril_ussd *ud = cbd->ud;
/* Always report sucessful completion, otherwise ofono may get /* Always report sucessful completion, otherwise ofono may get
* stuck in the USSD_STATE_ACTIVE state */ * stuck in the USSD_STATE_ACTIVE state */
GASSERT(ud->cancel_id);
ud->cancel_id = 0;
cbd->cb(ril_error_ok(&error), cbd->data); cbd->cb(ril_error_ok(&error), cbd->data);
} }
static void ril_ussd_response(GRilIoChannel* channel, int status,
const void* data, guint len, void* user_data)
{
struct ofono_error error;
struct ril_ussd_cbd *cbd = user_data;
struct ril_ussd *ud = cbd->ud;
GASSERT(ud->request_id);
ud->request_id = 0;
if (status == RIL_E_SUCCESS) {
ril_error_init_ok(&error);
} else {
ril_error_init_failure(&error);
}
cbd->cb(&error, cbd->data);
}
static void ril_ussd_request(struct ofono_ussd *ussd, int dcs, static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
const unsigned char *pdu, int len, ofono_ussd_cb_t cb, void *data) const unsigned char *pdu, int len, ofono_ussd_cb_t cb, void *data)
{ {
@@ -70,6 +100,12 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
struct ril_ussd *ud = ril_ussd_get_data(ussd); struct ril_ussd *ud = ril_ussd_get_data(ussd);
ofono_info("send ussd, len:%d", len); ofono_info("send ussd, len:%d", len);
GASSERT(!ud->request_id);
if (ud->request_id) {
grilio_queue_cancel_request(ud->q, ud->request_id, FALSE);
ud->request_id = 0;
}
if (cbs_dcs_decode(dcs, NULL, NULL, &charset, NULL, NULL, NULL)) { if (cbs_dcs_decode(dcs, NULL, NULL, &charset, NULL, NULL, NULL)) {
if (charset == SMS_CHARSET_7BIT) { if (charset == SMS_CHARSET_7BIT) {
unsigned char unpacked_buf[182]; unsigned char unpacked_buf[182];
@@ -100,10 +136,15 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
} }
grilio_request_append_utf8_chars(req, (char*) grilio_request_append_utf8_chars(req, (char*)
unpacked_buf, length); unpacked_buf, length);
grilio_queue_send_request(ud->q, req, grilio_request_set_timeout(req,
RIL_REQUEST_SEND_USSD); USSD_REQUEST_TIMEOUT_SEC * 1000);
ud->request_id =
grilio_queue_send_request_full(ud->q,
req, RIL_REQUEST_SEND_USSD,
ril_ussd_response,
ril_ussd_cbd_free,
ril_ussd_cbd_new(ud, cb, data));
grilio_request_unref(req); grilio_request_unref(req);
cb(ril_error_ok(&error), data);
return; return;
} }
} }
@@ -119,10 +160,12 @@ static void ril_ussd_cancel(struct ofono_ussd *ussd,
GRilIoRequest *req = grilio_request_new(); GRilIoRequest *req = grilio_request_new();
ofono_info("send ussd cancel"); ofono_info("send ussd cancel");
GASSERT(!ud->cancel_id);
grilio_queue_cancel_request(ud->q, ud->cancel_id, FALSE);
grilio_request_set_timeout(req, USSD_CANCEL_TIMEOUT_SEC * 1000); grilio_request_set_timeout(req, USSD_CANCEL_TIMEOUT_SEC * 1000);
grilio_queue_send_request_full(ud->q, req, RIL_REQUEST_CANCEL_USSD, ud->cancel_id = grilio_queue_send_request_full(ud->q, req,
ril_ussd_cancel_cb, ril_ussd_cbd_free, RIL_REQUEST_CANCEL_USSD, ril_ussd_cancel_cb,
ril_ussd_cbd_new(cb, data)); ril_ussd_cbd_free, ril_ussd_cbd_new(ud, cb, data));
grilio_request_unref(req); grilio_request_unref(req);
} }

View File

@@ -409,6 +409,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA; access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
break; break;
case RADIO_TECH_LTE: case RADIO_TECH_LTE:
case RADIO_TECH_LTE_CA:
access_tech = ACCESS_TECHNOLOGY_EUTRAN; access_tech = ACCESS_TECHNOLOGY_EUTRAN;
break; break;
default: default:

View File

@@ -2,6 +2,7 @@
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2019 Jolla Ltd. * Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -116,6 +117,14 @@ gboolean ril_vendor_data_call_parse(RilVendor *self,
data_call_parse(self, call, ver, rilp); data_call_parse(self, call, ver, rilp);
} }
gboolean ril_vendor_signal_strength_parse(RilVendor *self,
struct ril_vendor_signal_strength *signal_strength,
GRilIoParser *rilp)
{
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
signal_strength_parse(self, signal_strength, rilp);
}
static void ril_vendor_default_set_network(RilVendor *self, static void ril_vendor_default_set_network(RilVendor *self,
struct ril_network *network) struct ril_network *network)
{ {
@@ -160,6 +169,13 @@ static gboolean ril_vendor_default_data_call_parse(RilVendor *self,
return FALSE; return FALSE;
} }
static gboolean ril_vendor_default_signal_strength_parse(RilVendor *self,
struct ril_vendor_signal_strength *signal_strength,
GRilIoParser *rilp)
{
return FALSE;
}
void ril_vendor_init_base(RilVendor *self, GRilIoChannel *io) void ril_vendor_init_base(RilVendor *self, GRilIoChannel *io)
{ {
self->io = grilio_channel_ref(io); self->io = grilio_channel_ref(io);
@@ -190,6 +206,7 @@ static void ril_vendor_class_init(RilVendorClass* klass)
klass->set_attach_apn_req = ril_vendor_default_set_attach_apn_req; klass->set_attach_apn_req = ril_vendor_default_set_attach_apn_req;
klass->data_call_req = ril_vendor_default_data_call_req; klass->data_call_req = ril_vendor_default_data_call_req;
klass->data_call_parse = ril_vendor_default_data_call_parse; klass->data_call_parse = ril_vendor_default_data_call_parse;
klass->signal_strength_parse = ril_vendor_default_signal_strength_parse;
} }
/* /*

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2016-2019 Jolla Ltd. * Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -23,8 +24,10 @@ struct ril_vendor_defaults {
gboolean legacy_imei_query; gboolean legacy_imei_query;
gboolean enable_cbs; gboolean enable_cbs;
gboolean enable_stk; gboolean enable_stk;
gboolean replace_strange_oper;
gboolean query_available_band_mode; gboolean query_available_band_mode;
gboolean use_data_profiles; gboolean use_data_profiles;
gboolean force_gsm_when_radio_off;
guint mms_data_profile_id; guint mms_data_profile_id;
}; };
@@ -37,6 +40,12 @@ struct ril_vendor_driver {
const struct ril_slot_config *cfg); const struct ril_slot_config *cfg);
}; };
struct ril_vendor_signal_strength {
gint32 gsm; /* (0-31, 99) per TS 27.007 8.5 */
gint32 lte; /* (0-31, 99) per TS 27.007 8.5 */
gint32 qdbm; /* 4*dBm, 0 if none */
};
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name); const struct ril_vendor_driver *ril_vendor_find_driver(const char *name);
struct ril_vendor *ril_vendor_create struct ril_vendor *ril_vendor_create
(const struct ril_vendor_driver *vendor, GRilIoChannel *io, (const struct ril_vendor_driver *vendor, GRilIoChannel *io,
@@ -63,6 +72,9 @@ GRilIoRequest *ril_vendor_data_call_req(struct ril_vendor *vendor, int tech,
gboolean ril_vendor_data_call_parse(struct ril_vendor *vendor, gboolean ril_vendor_data_call_parse(struct ril_vendor *vendor,
struct ril_data_call *call, int version, struct ril_data_call *call, int version,
GRilIoParser *rilp); GRilIoParser *rilp);
gboolean ril_vendor_signal_strength_parse(struct ril_vendor *vendor,
struct ril_vendor_signal_strength *signal_strength,
GRilIoParser *rilp);
/* Put vendor driver descriptors to the "__vendor" section */ /* Put vendor driver descriptors to the "__vendor" section */
#define RIL_VENDOR_DRIVER_DEFINE(name) const struct ril_vendor_driver name \ #define RIL_VENDOR_DRIVER_DEFINE(name) const struct ril_vendor_driver name \

View File

@@ -2,6 +2,7 @@
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2019 Jolla Ltd. * Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -42,6 +43,9 @@ typedef struct ril_vendor_class {
gboolean (*data_call_parse)(RilVendor *vendor, gboolean (*data_call_parse)(RilVendor *vendor,
struct ril_data_call *call, int version, struct ril_data_call *call, int version,
GRilIoParser *rilp); GRilIoParser *rilp);
gboolean (*signal_strength_parse)(RilVendor *vendor,
struct ril_vendor_signal_strength *signal_strength,
GRilIoParser *rilp);
} RilVendorClass; } RilVendorClass;
GType ril_vendor_get_type(void); GType ril_vendor_get_type(void);

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony - RIL-based devices * oFono - Open Source Telephony - RIL-based devices
* *
* Copyright (C) 2016-2019 Jolla Ltd. * Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -79,6 +80,8 @@ struct ril_mtk_flavor {
enum ril_auth auth, const char *proto); enum ril_auth auth, const char *proto);
gboolean (*data_call_parse_fn)(struct ril_data_call *call, gboolean (*data_call_parse_fn)(struct ril_data_call *call,
int version, GRilIoParser *rilp); int version, GRilIoParser *rilp);
gboolean (*signal_strength_fn)(struct ril_vendor_signal_strength *sig,
GRilIoParser *rilp);
}; };
/* MTK specific RIL messages (actual codes differ from model to model!) */ /* MTK specific RIL messages (actual codes differ from model to model!) */
@@ -401,6 +404,96 @@ static gboolean ril_vendor_mtk_data_call_parse(RilVendor *vendor,
data_call_parse(vendor, call, version, rilp); data_call_parse(vendor, call, version, rilp);
} }
static gboolean ril_vendor_mtk_signal_strength_1
(struct ril_vendor_signal_strength *signal, GRilIoParser *rilp)
{
if (grilio_parser_bytes_remaining(rilp) == 64) {
gint32 rsrp = 0, rssi = 0;
/* GW_SignalStrength */
grilio_parser_get_int32(rilp, &signal->gsm);
grilio_parser_get_int32(rilp, NULL); /* bitErrorRate */
/* CDMA_SignalStrength */
grilio_parser_get_int32(rilp, NULL); /* dbm */
grilio_parser_get_int32(rilp, NULL); /* ecio */
/* EVDO_SignalStrength */
grilio_parser_get_int32(rilp, NULL); /* dbm */
grilio_parser_get_int32(rilp, NULL); /* ecio */
grilio_parser_get_int32(rilp, NULL); /* signalNoiseRatio */
/* LTE_SignalStrength */
grilio_parser_get_int32(rilp, &signal->lte);
grilio_parser_get_int32(rilp, &rsrp); /* rsrp */
grilio_parser_get_int32(rilp, NULL); /* rsrq */
grilio_parser_get_int32(rilp, NULL); /* rssnr */
grilio_parser_get_int32(rilp, NULL); /* cqi */
/* ???? */
grilio_parser_get_int32(rilp, NULL);
grilio_parser_get_int32(rilp, &rssi);
grilio_parser_get_int32(rilp, NULL);
grilio_parser_get_int32(rilp, NULL);
signal->qdbm = (rssi > 0 && rssi != INT_MAX) ? (-4 * rssi) :
(rsrp >= 44 && rsrp <= 140) ? (-4 * rsrp) : 0;
return TRUE;
}
return FALSE;
}
static gboolean ril_vendor_mtk_signal_strength_2
(struct ril_vendor_signal_strength *signal, GRilIoParser *rilp)
{
if (grilio_parser_bytes_remaining(rilp) == 64) {
gint32 rsrp = 0, is_gsm = 0, rssi_qdbm = 0;
/* GW_SignalStrength */
grilio_parser_get_int32(rilp, &signal->gsm);
grilio_parser_get_int32(rilp, NULL); /* bitErrorRate */
/* CDMA_SignalStrength */
grilio_parser_get_int32(rilp, NULL); /* dbm */
grilio_parser_get_int32(rilp, NULL); /* ecio */
/* EVDO_SignalStrength */
grilio_parser_get_int32(rilp, NULL); /* dbm */
grilio_parser_get_int32(rilp, NULL); /* ecio */
grilio_parser_get_int32(rilp, NULL); /* signalNoiseRatio */
/* LTE_SignalStrength */
grilio_parser_get_int32(rilp, &signal->lte);
grilio_parser_get_int32(rilp, &rsrp); /* rsrp */
grilio_parser_get_int32(rilp, NULL); /* rsrq */
grilio_parser_get_int32(rilp, NULL); /* rssnr */
grilio_parser_get_int32(rilp, NULL); /* cqi */
/* WCDMA_SignalStrength */
grilio_parser_get_int32(rilp, &is_gsm); /* isGsm */
grilio_parser_get_int32(rilp, &rssi_qdbm); /* rssiQdbm */
grilio_parser_get_int32(rilp, NULL); /* rscpQdbm */
grilio_parser_get_int32(rilp, NULL); /* Ecn0Qdbm*/
signal->qdbm = (is_gsm == 1 && rssi_qdbm < 0) ? rssi_qdbm :
(rsrp >= 44 && rsrp <= 140) ? (-4 * rsrp) : 0;
return TRUE;
}
return FALSE;
}
static gboolean ril_vendor_mtk_signal_strength_parse(RilVendor *vendor,
struct ril_vendor_signal_strength *signal,
GRilIoParser *rilp)
{
const struct ril_mtk_flavor *flavor = RIL_VENDOR_MTK(vendor)->flavor;
return flavor->signal_strength_fn ?
flavor->signal_strength_fn(signal, rilp) :
RIL_VENDOR_CLASS(ril_vendor_mtk_parent_class)->
signal_strength_parse(vendor, signal, rilp);
}
static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults) static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
{ {
/* /*
@@ -415,6 +508,8 @@ static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
defaults->query_available_band_mode = FALSE; defaults->query_available_band_mode = FALSE;
defaults->empty_pin_query = FALSE; defaults->empty_pin_query = FALSE;
defaults->legacy_imei_query = TRUE; defaults->legacy_imei_query = TRUE;
defaults->force_gsm_when_radio_off = FALSE;
defaults->replace_strange_oper = TRUE;
} }
static void ril_vendor_mtk_base_init(RilVendorMtk *self, GRilIoChannel *io, static void ril_vendor_mtk_base_init(RilVendorMtk *self, GRilIoChannel *io,
@@ -496,20 +591,23 @@ static void ril_vendor_mtk_class_init(RilVendorMtkClass* klass)
klass->set_attach_apn_req = ril_vendor_mtk_set_attach_apn_req; klass->set_attach_apn_req = ril_vendor_mtk_set_attach_apn_req;
klass->data_call_req = ril_vendor_mtk_data_call_req; klass->data_call_req = ril_vendor_mtk_data_call_req;
klass->data_call_parse = ril_vendor_mtk_data_call_parse; klass->data_call_parse = ril_vendor_mtk_data_call_parse;
klass->signal_strength_parse = ril_vendor_mtk_signal_strength_parse;
} }
static const struct ril_mtk_flavor ril_mtk_flavor1 = { static const struct ril_mtk_flavor ril_mtk_flavor1 = {
.name = "mtk1", .name = "mtk1",
.msg = &msg_mtk1, .msg = &msg_mtk1,
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_1, .build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_1,
.data_call_parse_fn = NULL .data_call_parse_fn = NULL,
.signal_strength_fn = &ril_vendor_mtk_signal_strength_1
}; };
static const struct ril_mtk_flavor ril_mtk_flavor2 = { static const struct ril_mtk_flavor ril_mtk_flavor2 = {
.name = "mtk2", .name = "mtk2",
.msg = &msg_mtk2, .msg = &msg_mtk2,
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_2, .build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_2,
.data_call_parse_fn = &ril_vendor_mtk_data_call_parse_v6 .data_call_parse_fn = &ril_vendor_mtk_data_call_parse_v6,
.signal_strength_fn = &ril_vendor_mtk_signal_strength_2
}; };
#define DEFAULT_MTK_TYPE (&ril_mtk_flavor1) #define DEFAULT_MTK_TYPE (&ril_mtk_flavor1)

0
ofono/drivers/xmm7modem/ims.c Executable file → Normal file
View File

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2019 Jolla Ltd. * Copyright (C) 2019-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -25,7 +26,7 @@ extern "C" {
enum ofono_dbus_access { enum ofono_dbus_access {
OFONO_DBUS_ACCESS_DENY, /* Deny access */ OFONO_DBUS_ACCESS_DENY, /* Deny access */
OFONO_DBUS_ACCESS_ALLOW, /* Allow access */ OFONO_DBUS_ACCESS_ALLOW, /* Allow access */
OFONO_DBUS_ACCESS_DONT_CARE, /* No decision */ OFONO_DBUS_ACCESS_DONT_CARE /* No decision */
}; };
enum ofono_dbus_access_intf { enum ofono_dbus_access_intf {
@@ -38,6 +39,8 @@ enum ofono_dbus_access_intf {
OFONO_DBUS_ACCESS_INTF_SIMMGR, /* org.ofono.SimManager */ OFONO_DBUS_ACCESS_INTF_SIMMGR, /* org.ofono.SimManager */
OFONO_DBUS_ACCESS_INTF_MODEM, /* org.ofono.Modem */ OFONO_DBUS_ACCESS_INTF_MODEM, /* org.ofono.Modem */
OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS, /* org.ofono.RadioSettings */ OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS, /* org.ofono.RadioSettings */
OFONO_DBUS_ACCESS_INTF_STK, /* org.ofono.SimToolkit */
OFONO_DBUS_ACCESS_INTF_OEMRAW, /* org.ofono.OemRaw */
OFONO_DBUS_ACCESS_INTF_COUNT OFONO_DBUS_ACCESS_INTF_COUNT
}; };
@@ -116,6 +119,18 @@ enum ofono_dbus_access_radiosettings_method {
OFONO_DBUS_ACCESS_RADIOSETTINGS_METHOD_COUNT OFONO_DBUS_ACCESS_RADIOSETTINGS_METHOD_COUNT
}; };
/* OFONO_DBUS_ACCESS_INTF_STK */
enum ofono_dbus_access_stk_method {
OFONO_DBUS_ACCESS_STK_REGISTER_AGENT,
OFONO_DBUS_ACCESS_STK_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_OEMRAW */
enum ofono_dbus_access_oemraw_method {
OFONO_DBUS_ACCESS_OEMRAW_SEND,
OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT
};
#define OFONO_DBUS_ACCESS_PRIORITY_LOW (-100) #define OFONO_DBUS_ACCESS_PRIORITY_LOW (-100)
#define OFONO_DBUS_ACCESS_PRIORITY_DEFAULT (0) #define OFONO_DBUS_ACCESS_PRIORITY_DEFAULT (0)
#define OFONO_DBUS_ACCESS_PRIORITY_HIGH (100) #define OFONO_DBUS_ACCESS_PRIORITY_HIGH (100)

View File

@@ -139,7 +139,12 @@ struct ofono_voicecall_driver {
/* Dials the last number again, this handles the hfp profile last number /* Dials the last number again, this handles the hfp profile last number
* dialing with the +BLDN AT command * dialing with the +BLDN AT command
*/ */
void (*dial_last)(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data); void (*dial_last)(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
void *data);
/* dials a number at a given memory location */
void (*dial_memory)(struct ofono_voicecall *vc,
unsigned int memory_location, ofono_voicecall_cb_t cb,
void *data);
}; };
void ofono_voicecall_en_list_notify(struct ofono_voicecall *vc, void ofono_voicecall_en_list_notify(struct ofono_voicecall *vc,

View File

@@ -43,6 +43,7 @@
#include <ofono/ussd.h> #include <ofono/ussd.h>
#include <ofono/gprs.h> #include <ofono/gprs.h>
#include <ofono/gprs-context.h> #include <ofono/gprs-context.h>
#include <ofono/lte.h>
#include <ofono/radio-settings.h> #include <ofono/radio-settings.h>
#include <ofono/location-reporting.h> #include <ofono/location-reporting.h>
#include <ofono/log.h> #include <ofono/log.h>
@@ -483,6 +484,8 @@ static void gobi_post_sim(struct ofono_modem *modem)
DBG("%p", modem); DBG("%p", modem);
ofono_lte_create(modem, "qmimodem", data->device);
if (data->features & GOBI_CAT) if (data->features & GOBI_CAT)
ofono_stk_create(modem, 0, "qmimodem", data->device); ofono_stk_create(modem, 0, "qmimodem", data->device);
else if (data->features & GOBI_CAT_OLD) else if (data->features & GOBI_CAT_OLD)

View File

@@ -3,7 +3,7 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2017 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -60,6 +60,7 @@ const char *mbpi_database = MBPI_DATABASE;
*/ */
enum ofono_gprs_proto mbpi_default_internet_proto = OFONO_GPRS_PROTO_IPV4V6; enum ofono_gprs_proto mbpi_default_internet_proto = OFONO_GPRS_PROTO_IPV4V6;
enum ofono_gprs_proto mbpi_default_mms_proto = OFONO_GPRS_PROTO_IP; enum ofono_gprs_proto mbpi_default_mms_proto = OFONO_GPRS_PROTO_IP;
enum ofono_gprs_proto mbpi_default_ims_proto = OFONO_GPRS_PROTO_IPV4V6;
enum ofono_gprs_proto mbpi_default_proto = OFONO_GPRS_PROTO_IP; enum ofono_gprs_proto mbpi_default_proto = OFONO_GPRS_PROTO_IP;
enum ofono_gprs_auth_method mbpi_default_auth_method = OFONO_GPRS_AUTH_METHOD_ANY; enum ofono_gprs_auth_method mbpi_default_auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
@@ -246,6 +247,9 @@ static void usage_start(GMarkupParseContext *context,
} else if (strcmp(text, "mms") == 0) { } else if (strcmp(text, "mms") == 0) {
apn->type = OFONO_GPRS_CONTEXT_TYPE_MMS; apn->type = OFONO_GPRS_CONTEXT_TYPE_MMS;
apn->proto = mbpi_default_mms_proto; apn->proto = mbpi_default_mms_proto;
} else if (strcmp(text, "ims") == 0) {
apn->type = OFONO_GPRS_CONTEXT_TYPE_IMS;
apn->proto = mbpi_default_ims_proto;
} else if (strcmp(text, "wap") == 0) } else if (strcmp(text, "wap") == 0)
apn->type = OFONO_GPRS_CONTEXT_TYPE_WAP; apn->type = OFONO_GPRS_CONTEXT_TYPE_WAP;
else else

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -22,6 +23,7 @@
extern const char *mbpi_database; extern const char *mbpi_database;
extern enum ofono_gprs_proto mbpi_default_internet_proto; extern enum ofono_gprs_proto mbpi_default_internet_proto;
extern enum ofono_gprs_proto mbpi_default_mms_proto; extern enum ofono_gprs_proto mbpi_default_mms_proto;
extern enum ofono_gprs_proto mbpi_default_ims_proto;
extern enum ofono_gprs_proto mbpi_default_proto; extern enum ofono_gprs_proto mbpi_default_proto;
extern enum ofono_gprs_auth_method mbpi_default_auth_method; extern enum ofono_gprs_auth_method mbpi_default_auth_method;

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2017-2019 Jolla Ltd. * Copyright (C) 2017-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -22,6 +23,7 @@
#include <gutil_macros.h> #include <gutil_macros.h>
#include <string.h> #include <string.h>
#include <ofono/storage.h>
#include <ofono/watch.h> #include <ofono/watch.h>
#include "src/ofono.h" #include "src/ofono.h"
@@ -44,6 +46,12 @@ enum ofono_watch_events {
WATCH_EVENT_COUNT WATCH_EVENT_COUNT
}; };
enum sim_auto_select {
SIM_AUTO_SELECT_OFF,
SIM_AUTO_SELECT_ON,
SIM_AUTO_SELECT_ONCE
};
struct sailfish_manager_priv { struct sailfish_manager_priv {
struct sailfish_manager pub; /* Public part */ struct sailfish_manager pub; /* Public part */
struct sailfish_slot_driver_reg *drivers; struct sailfish_slot_driver_reg *drivers;
@@ -52,6 +60,8 @@ struct sailfish_manager_priv {
struct sailfish_slot_priv *data_slot; struct sailfish_slot_priv *data_slot;
struct sailfish_slot_priv *mms_slot; struct sailfish_slot_priv *mms_slot;
sailfish_slot_ptr *slots; sailfish_slot_ptr *slots;
enum sim_auto_select auto_data_sim;
gboolean auto_data_sim_done;
int slot_count; int slot_count;
guint init_countdown; guint init_countdown;
guint init_id; guint init_id;
@@ -99,6 +109,11 @@ struct sailfish_slot_priv {
int index; int index;
}; };
/* Read-only config */
#define SF_CONFIG_FILE "main.conf"
#define SF_CONFIG_GROUP "ModemManager"
#define SF_CONFIG_KEY_AUTO_DATA_SIM "AutoSelectDataSim"
/* "ril" is used for historical reasons */ /* "ril" is used for historical reasons */
#define SF_STORE "ril" #define SF_STORE "ril"
#define SF_STORE_GROUP "Settings" #define SF_STORE_GROUP "Settings"
@@ -106,6 +121,7 @@ struct sailfish_slot_priv {
#define SF_STORE_DEFAULT_VOICE_SIM "DefaultVoiceSim" #define SF_STORE_DEFAULT_VOICE_SIM "DefaultVoiceSim"
#define SF_STORE_DEFAULT_DATA_SIM "DefaultDataSim" #define SF_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
#define SF_STORE_SLOTS_SEP "," #define SF_STORE_SLOTS_SEP ","
#define SF_STORE_AUTO_DATA_SIM_DONE "AutoSelectDataSimDone"
/* The file where error statistics is stored. Again "rilerror" is historical */ /* The file where error statistics is stored. Again "rilerror" is historical */
#define SF_ERROR_STORAGE "rilerror" /* File name */ #define SF_ERROR_STORAGE "rilerror" /* File name */
@@ -145,6 +161,50 @@ static inline void sailfish_slot_set_data_role(struct sailfish_slot_priv *s,
} }
} }
static gboolean sailfish_config_get_enum(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...)
{
char *str = g_key_file_get_string(file, group, key, NULL);
if (str) {
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(str, '#');
if (comment) *comment = 0;
g_strstrip(str);
if (strcasecmp(str, name)) {
va_list args;
va_start(args, value);
while ((name = va_arg(args, char*)) != NULL) {
value = va_arg(args, int);
if (!strcasecmp(str, name)) {
break;
}
}
va_end(args);
}
if (!name) {
ofono_error("Invalid %s config value (%s)", key, str);
}
g_free(str);
if (name) {
if (result) {
*result = value;
}
return TRUE;
}
}
return FALSE;
}
/* Update modem paths and emit D-Bus signal if necessary */ /* Update modem paths and emit D-Bus signal if necessary */
static void sailfish_manager_update_modem_paths_full static void sailfish_manager_update_modem_paths_full
(struct sailfish_manager_priv *p) (struct sailfish_manager_priv *p)
@@ -588,6 +648,27 @@ static struct sailfish_slot_priv *sailfish_manager_find_slot_imsi
} }
} }
static gboolean sailfish_manager_all_sims_are_initialized_proc
(struct sailfish_slot_priv *s, void *user_data)
{
if (s->pub.sim_present && s->pub.enabled && !s->watch->imsi) {
*((gboolean*)user_data) = FALSE;
return SF_LOOP_DONE;
} else {
return SF_LOOP_CONTINUE;
}
}
static gboolean sailfish_manager_all_sims_are_initialized
(struct sailfish_manager_priv *p)
{
gboolean result = TRUE;
sailfish_manager_foreach_slot(p,
sailfish_manager_all_sims_are_initialized_proc, &result);
return result;
}
/* Returns the event mask to be passed to sailfish_manager_dbus_signal. /* Returns the event mask to be passed to sailfish_manager_dbus_signal.
* The caller has a chance to OR it with other bits */ * The caller has a chance to OR it with other bits */
static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p) static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
@@ -615,7 +696,7 @@ static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
* previously selected voice SIM is inserted, we will switch * previously selected voice SIM is inserted, we will switch
* back to it. * back to it.
* *
* There is no such fallback for the data. * A similar behavior can be configured for data SIM too.
*/ */
if (!slot) { if (!slot) {
slot = sailfish_manager_find_slot_imsi(p, NULL); slot = sailfish_manager_find_slot_imsi(p, NULL);
@@ -648,13 +729,52 @@ static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
slot = sailfish_manager_find_slot_imsi(p, NULL); slot = sailfish_manager_find_slot_imsi(p, NULL);
} }
} else { } else {
/*
* Should we automatically select the default data sim
* on a multisim phone that has only one sim inserted?
*/
slot = NULL; slot = NULL;
} }
/* Check if we need to auto-select data SIM (always or once) */
if (!slot && (p->auto_data_sim == SIM_AUTO_SELECT_ON ||
(p->auto_data_sim == SIM_AUTO_SELECT_ONCE &&
!p->auto_data_sim_done))) {
/*
* To actually make a selection we need all present SIMs
* to be initialized. Otherwise we may end up endlessly
* switching data SIMs back and forth.
*/
if (sailfish_manager_all_sims_are_initialized(p)) {
slot = sailfish_manager_find_slot_imsi(p, NULL);
if (slot && slot->watch->imsi && slot->watch->online &&
p->auto_data_sim == SIM_AUTO_SELECT_ONCE) {
const char *imsi = slot->watch->imsi;
/*
* Data SIM only needs to be auto-selected
* once and it's done. Write that down.
*/
DBG("Default data sim set to %s once", imsi);
p->auto_data_sim_done = TRUE;
g_key_file_set_boolean(p->storage,
SF_STORE_GROUP,
SF_STORE_AUTO_DATA_SIM_DONE,
p->auto_data_sim_done);
g_free(p->default_data_imsi);
p->pub.default_data_imsi =
p->default_data_imsi = g_strdup(imsi);
g_key_file_set_string(p->storage,
SF_STORE_GROUP,
SF_STORE_DEFAULT_DATA_SIM,
imsi);
storage_sync(NULL, SF_STORE, p->storage);
sailfish_manager_dbus_signal(p->dbus,
SAILFISH_MANAGER_SIGNAL_DATA_IMSI);
}
} else {
DBG("Skipping auto-selection of data SIM");
}
}
if (slot && !slot->watch->online) { if (slot && !slot->watch->online) {
slot = NULL; slot = NULL;
} }
@@ -1274,6 +1394,29 @@ static struct sailfish_manager_priv *sailfish_manager_priv_new()
struct sailfish_manager_priv *p = struct sailfish_manager_priv *p =
g_slice_new0(struct sailfish_manager_priv); g_slice_new0(struct sailfish_manager_priv);
GKeyFile *conf = g_key_file_new();
char* fn = g_build_filename(ofono_config_dir(), SF_CONFIG_FILE, NULL);
/* Load config */
if (g_key_file_load_from_file(conf, fn, 0, NULL)) {
int ival;
DBG("Loading configuration file %s", fn);
if (sailfish_config_get_enum(conf, SF_CONFIG_GROUP,
SF_CONFIG_KEY_AUTO_DATA_SIM, &ival,
"off", SIM_AUTO_SELECT_OFF,
"once", SIM_AUTO_SELECT_ONCE,
"always", SIM_AUTO_SELECT_ON,
"on", SIM_AUTO_SELECT_ON, NULL)) {
DBG("Automatic data SIM selection: %s",
ival == SIM_AUTO_SELECT_ONCE ? "once":
ival == SIM_AUTO_SELECT_ON ? "on":
"off");
p->auto_data_sim = ival;
}
}
g_key_file_free(conf);
g_free(fn);
/* Load settings */ /* Load settings */
p->storage = storage_open(NULL, SF_STORE); p->storage = storage_open(NULL, SF_STORE);
@@ -1283,6 +1426,8 @@ static struct sailfish_manager_priv *sailfish_manager_priv_new()
p->pub.default_data_imsi = p->default_data_imsi = p->pub.default_data_imsi = p->default_data_imsi =
g_key_file_get_string(p->storage, SF_STORE_GROUP, g_key_file_get_string(p->storage, SF_STORE_GROUP,
SF_STORE_DEFAULT_DATA_SIM, NULL); SF_STORE_DEFAULT_DATA_SIM, NULL);
p->auto_data_sim_done = g_key_file_get_boolean(p->storage,
SF_STORE_GROUP, SF_STORE_AUTO_DATA_SIM_DONE, NULL);
DBG("Default voice sim is %s", p->default_voice_imsi ? DBG("Default voice sim is %s", p->default_voice_imsi ?
p->default_voice_imsi : "(auto)"); p->default_voice_imsi : "(auto)");

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2017-2019 Jolla Ltd. * Copyright (C) 2017-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -13,6 +13,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif #endif

View File

@@ -2,7 +2,7 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2017 Jolla Ltd. * Copyright (C) 2013-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -136,38 +136,56 @@ static GSList *provision_pick_best_ap(GSList *list, const char *spn,
} }
} }
/* Returns the list containing exactly one INTERNET and one MMS access point */ /**
* Returns the list containing INTERNET, MMS and IMS access points,
* always all three of them and always in this order.
*/
static GSList *provision_normalize_apn_list(GSList *apns, const char *spn) static GSList *provision_normalize_apn_list(GSList *apns, const char *spn)
{ {
static const struct provision_ap_defaults internet_defaults = static const struct provision_ap_defaults internet_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" }; { OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
static const struct provision_ap_defaults mms_defaults = static const struct provision_ap_defaults mms_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" }; { OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
static const struct provision_ap_defaults ims_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_IMS, "IMS", "ims" };
GSList *internet_apns = NULL; GSList *internet_apns = NULL;
GSList *mms_apns = NULL; GSList *mms_apns = NULL;
GSList *ims_apns = NULL;
/* Split internet and mms apns, delete all others */ /* Build separate apn list for each type */
while (apns) { while (apns) {
GSList *link = apns; GSList *link = apns;
struct ofono_gprs_provision_data *ap = link->data; struct ofono_gprs_provision_data *ap = link->data;
apns = g_slist_remove_link(apns, link); apns = g_slist_remove_link(apns, link);
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) { switch (ap->type) {
case OFONO_GPRS_CONTEXT_TYPE_INTERNET:
internet_apns = g_slist_concat(internet_apns, link); internet_apns = g_slist_concat(internet_apns, link);
} else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) { break;
case OFONO_GPRS_CONTEXT_TYPE_MMS:
mms_apns = g_slist_concat(mms_apns, link); mms_apns = g_slist_concat(mms_apns, link);
} else { break;
case OFONO_GPRS_CONTEXT_TYPE_IMS:
ims_apns = g_slist_concat(ims_apns, link);
break;
default:
g_slist_free_full(link, provision_free_ap); g_slist_free_full(link, provision_free_ap);
break;
} }
} }
/* Pick the best ap of each type and concatenate them */ /* Pick the best ap of each type */
return g_slist_concat( internet_apns = provision_pick_best_ap(internet_apns, spn,
provision_pick_best_ap(internet_apns, spn, mbpi_default_internet_proto, &internet_defaults);
mbpi_default_internet_proto, &internet_defaults), mms_apns = provision_pick_best_ap(mms_apns, spn,
provision_pick_best_ap(mms_apns, spn, mbpi_default_mms_proto, &mms_defaults);
mbpi_default_mms_proto, &mms_defaults)); ims_apns = provision_pick_best_ap(ims_apns, spn,
mbpi_default_ims_proto, &ims_defaults);
/* And concatenate them in the right order */
return g_slist_concat(internet_apns, g_slist_concat(mms_apns,
ims_apns));
} }
int provision_get_settings(const char *mcc, const char *mnc, int provision_get_settings(const char *mcc, const char *mnc,

View File

@@ -4,6 +4,7 @@
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013 Jolla Ltd. All rights reserved. * Copyright (C) 2013 Jolla Ltd. All rights reserved.
* Copyright (C) 2020 Open Mobile Platform LLС. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -26,6 +27,7 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h>
#include <glib.h> #include <glib.h>
#include <gdbus.h> #include <gdbus.h>
@@ -40,58 +42,42 @@
#define SMS_HISTORY_INTERFACE "org.ofono.SmsHistory" #define SMS_HISTORY_INTERFACE "org.ofono.SmsHistory"
gboolean sms_history_interface_registered = FALSE;
static const GDBusSignalTable sms_history_signals[] = { static const GDBusSignalTable sms_history_signals[] = {
{ GDBUS_SIGNAL("StatusReport", { GDBUS_SIGNAL("StatusReport",
GDBUS_ARGS({ "message", "s" }, { "Delivered", "a{b}" })) }, GDBUS_ARGS({ "message", "s" }, { "Delivered", "a{b}" })) },
{ } { }
}; };
static void sms_history_cleanup(gpointer user) static int sms_history_probe(struct ofono_history_context *context)
{ {
struct ofono_modem *modem = user;
DBG("modem %p", modem);
ofono_modem_remove_interface(modem, SMS_HISTORY_INTERFACE);
sms_history_interface_registered = FALSE;
}
static gboolean sms_history_ensure_interface(
struct ofono_modem *modem) {
if (sms_history_interface_registered)
return TRUE;
/* Late initialization of the D-Bus interface */
DBusConnection *conn = ofono_dbus_get_connection(); DBusConnection *conn = ofono_dbus_get_connection();
if (conn == NULL) struct ofono_modem *modem = context->modem;
return FALSE;
ofono_debug("SMS History Probe for modem: %p", modem);
if (!g_dbus_register_interface(conn, if (!g_dbus_register_interface(conn,
ofono_modem_get_path(modem), ofono_modem_get_path(modem),
SMS_HISTORY_INTERFACE, SMS_HISTORY_INTERFACE,
NULL, sms_history_signals, NULL, NULL, sms_history_signals,
modem, sms_history_cleanup)) { NULL, NULL, NULL)) {
ofono_error("Could not create %s interface", ofono_error("Could not create %s interface",
SMS_HISTORY_INTERFACE); SMS_HISTORY_INTERFACE);
return FALSE; return -EIO;
} }
sms_history_interface_registered = TRUE;
ofono_modem_add_interface(modem, SMS_HISTORY_INTERFACE); ofono_modem_add_interface(modem, SMS_HISTORY_INTERFACE);
return TRUE;
}
static int sms_history_probe(struct ofono_history_context *context)
{
ofono_debug("SMS History Probe for modem: %p", context->modem);
sms_history_ensure_interface(context->modem);
return 0; return 0;
} }
static void sms_history_remove(struct ofono_history_context *context) static void sms_history_remove(struct ofono_history_context *context)
{ {
ofono_debug("SMS History Remove for modem: %p", context->modem); DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = context->modem;
ofono_debug("SMS History remove for modem: %p", modem);
ofono_modem_remove_interface(modem, SMS_HISTORY_INTERFACE);
g_dbus_unregister_interface(conn, ofono_modem_get_path(modem),
SMS_HISTORY_INTERFACE);
} }
static void sms_history_sms_send_status( static void sms_history_sms_send_status(
@@ -102,9 +88,6 @@ static void sms_history_sms_send_status(
{ {
DBG(""); DBG("");
if (!sms_history_ensure_interface(context->modem))
return;
if ((s == OFONO_HISTORY_SMS_STATUS_DELIVERED) if ((s == OFONO_HISTORY_SMS_STATUS_DELIVERED)
|| (s == OFONO_HISTORY_SMS_STATUS_DELIVER_FAILED)) { || (s == OFONO_HISTORY_SMS_STATUS_DELIVER_FAILED)) {
@@ -174,4 +157,3 @@ static void sms_history_exit(void)
OFONO_PLUGIN_DEFINE(sms_history, "SMS History Plugin", OFONO_PLUGIN_DEFINE(sms_history, "SMS History Plugin",
VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT, VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
sms_history_init, sms_history_exit) sms_history_init, sms_history_exit)

View File

@@ -1731,6 +1731,8 @@ static gboolean create_modem(gpointer key, gpointer value, gpointer user_data)
continue; continue;
if (driver_list[i].setup(modem) == TRUE) { if (driver_list[i].setup(modem) == TRUE) {
ofono_modem_set_string(modem->modem, "SystemPath",
syspath);
ofono_modem_register(modem->modem); ofono_modem_register(modem->modem);
return FALSE; return FALSE;
} }

365
ofono/src/config.c Normal file
View File

@@ -0,0 +1,365 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "ofono.h"
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
/**
* The config_merge_files() function does the following:
*
* 1. Loads the specified key file (say, "/etc/foo.conf")
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
* for the files with the same suffix as the main file (e.g. "*.conf")
* 3. Sorts the files from the subdirectory (alphabetically)
* 4. Merges the contents of the additional files with the main file
* according to their sort order.
*
* When the entries are merged, keys and groups overwrite the exising
* ones by default. Keys can be suffixed with special characters to
* remove or modify the existing entries instead:
*
* ':' Sets the (default) value if the key is missing
* '+' Appends values to the string list
* '?' Appends only new (non-existent) values to the string list
* '-' Removes the values from the string list
*
* Both keys and groups can be prefixed with '!' to remove the entire key
* or group.
*
* For example if we merge these two files:
*
* /etc/foo.conf:
*
* [foo]
* a=1
* b=2,3
* c=4
* d=5
* [bar]
* e=5
*
* /etc/foo.d/bar.conf:
*
* [foo]
* a+=2
* b-=2
* c=5
* !d
* [!bar]
*
* we end up with this:
*
* [foo]
* a=1
* b=2,3
* c=5
*
* Note that the list separator is assumed to be ',' (rather than default ';').
* The keyfile passed to config_merge_files() should use the same list
* separator, because the default values are copied from the config files
* as is.
*/
static gint config_sort_files(gconstpointer a, gconstpointer b)
{
/* The comparison function for g_ptr_array_sort() doesn't take
* the pointers from the array as arguments, it takes pointers
* to the pointers in the array. */
return strcmp(*(char**)a, *(char**)b);
}
static char **config_collect_files(const char *path, const char *suffix)
{
/* Returns sorted list of regular files in the directory,
* optionally having the specified suffix (e.g. ".conf").
* Returns NULL if nothing appropriate has been found. */
char **files = NULL;
DIR *d = opendir(path);
if (d) {
GPtrArray *list = g_ptr_array_new();
const struct dirent *p;
while ((p = readdir(d)) != NULL) {
/* No need to even stat . and .. */
if (strcmp(p->d_name, ".") &&
strcmp(p->d_name, "..") && (!suffix ||
g_str_has_suffix(p->d_name, suffix))) {
struct stat st;
char *buf = g_strconcat(path, "/", p->d_name,
NULL);
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
g_ptr_array_add(list, buf);
} else {
g_free(buf);
}
}
}
if (list->len > 0) {
g_ptr_array_sort(list, config_sort_files);
g_ptr_array_add(list, NULL);
files = (char**)g_ptr_array_free(list, FALSE);
} else {
g_ptr_array_free(list, TRUE);
}
closedir(d);
}
return files;
}
static int config_list_find(char **list, gsize len, const char *value)
{
guint i;
for (i = 0; i < len; i++) {
if (!strcmp(list[i], value)) {
return i;
}
}
return -1;
}
static void config_list_append(GKeyFile *conf, GKeyFile *k,
const char *group, const char *key,
char **values, gsize n, gboolean unique)
{
/* Note: will steal strings from values */
if (n > 0) {
int i;
gsize len = 0;
gchar **list = g_key_file_get_string_list(conf, group, key,
&len, NULL);
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
for (i = 0; i < (int)len; i++) {
g_ptr_array_add(newlist, list[i]);
}
for (i = 0; i < (int)n; i++) {
char *val = values[i];
if (!unique || config_list_find((char**)
newlist->pdata, newlist->len, val) < 0) {
/* Move the string to the new list */
g_ptr_array_add(newlist, val);
memmove(values + i, values + i + 1,
sizeof(char*) * (n - i));
i--;
n--;
}
}
if (newlist->len > len) {
g_key_file_set_string_list(conf, group, key,
(const gchar * const *) newlist->pdata,
newlist->len);
}
/* Strings are deallocated by GPtrArray */
g_ptr_array_free(newlist, TRUE);
g_free(list);
}
}
static void config_list_remove(GKeyFile *conf, GKeyFile *k,
const char *group, const char *key, char **values, gsize n)
{
if (n > 0) {
gsize len = 0;
gchar **list = g_key_file_get_string_list(conf, group, key,
&len, NULL);
if (len > 0) {
gsize i;
const gsize oldlen = len;
for (i = 0; i < n; i++) {
int pos;
/* Remove all matching values */
while ((pos = config_list_find(list, len,
values[i])) >= 0) {
g_free(list[pos]);
memmove(list + pos, list + pos + 1,
sizeof(char*) * (len - pos));
len--;
}
}
if (len < oldlen) {
g_key_file_set_string_list(conf, group, key,
(const gchar * const *) list, len);
}
}
g_strfreev(list);
}
}
static void config_merge_group(GKeyFile *conf, GKeyFile *k,
const char *group)
{
gsize i, n = 0;
char **keys = g_key_file_get_keys(k, group, &n, NULL);
for (i=0; i<n; i++) {
char *key = keys[i];
if (key[0] == '!') {
if (key[1]) {
g_key_file_remove_key(conf, group, key+1, NULL);
}
} else {
const gsize len = strlen(key);
const char last = (len > 0) ? key[len-1] : 0;
if (last == '+' || last == '?') {
gsize count = 0;
gchar **values = g_key_file_get_string_list(k,
group, key, &count, NULL);
key[len-1] = 0;
config_list_append(conf, k, group, key,
values, count, last == '?');
g_strfreev(values);
} else if (last == '-') {
gsize count = 0;
gchar **values = g_key_file_get_string_list(k,
group, key, &count, NULL);
key[len-1] = 0;
config_list_remove(conf, k, group, key,
values, count);
g_strfreev(values);
} else {
/* Overwrite the value (it must exist in k) */
gchar *value = g_key_file_get_value(k, group,
key, NULL);
if (last == ':') {
/* Default value */
key[len-1] = 0;
if (!g_key_file_has_key(conf,
group, key, NULL)) {
g_key_file_set_value(conf,
group, key, value);
}
} else {
g_key_file_set_value(conf, group, key,
value);
}
g_free(value);
}
}
}
g_strfreev(keys);
}
static void config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
{
gsize i, n = 0;
char **groups = g_key_file_get_groups(k, &n);
for (i=0; i<n; i++) {
const char *group = groups[i];
if (group[0] == '!') {
g_key_file_remove_group(conf, group + 1, NULL);
} else {
config_merge_group(conf, k, group);
}
}
g_strfreev(groups);
}
static void config_merge_file(GKeyFile *conf, const char *file)
{
GKeyFile *k = g_key_file_new();
g_key_file_set_list_separator(k, ',');
if (g_key_file_load_from_file(k, file, 0, NULL)) {
config_merge_keyfile(conf, k);
}
g_key_file_unref(k);
}
void config_merge_files(GKeyFile *conf, const char *file)
{
if (conf && file && file[0]) {
char *dot = strrchr(file, '.');
const char *suffix;
char *dir;
char **files;
if (!dot) {
dir = g_strconcat(file, ".d", NULL);
suffix = NULL;
} else if (!dot[1]) {
dir = g_strconcat(file, "d", NULL);
suffix = NULL;
} else {
/* 2 bytes for ".d" and 1 for NULL terminator */
dir = g_malloc(dot - file + 3);
strncpy(dir, file, dot - file);
strcpy(dir + (dot - file), ".d");
suffix = dot + 1;
}
files = config_collect_files(dir, suffix);
g_free(dir);
/* Load the main config */
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
DBG("Loading %s", file);
config_merge_file(conf, file);
}
if (files) {
char **ptr;
for (ptr = files; *ptr; ptr++) {
DBG("Merging %s", *ptr);
config_merge_file(conf, *ptr);
}
g_strfreev(files);
}
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2019 Jolla Ltd. * Copyright (C) 2019-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -41,6 +42,10 @@ const char *ofono_dbus_access_intf_name(enum ofono_dbus_access_intf intf)
return OFONO_MODEM_INTERFACE; return OFONO_MODEM_INTERFACE;
case OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS: case OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS:
return OFONO_RADIO_SETTINGS_INTERFACE; return OFONO_RADIO_SETTINGS_INTERFACE;
case OFONO_DBUS_ACCESS_INTF_STK:
return OFONO_STK_INTERFACE;
case OFONO_DBUS_ACCESS_INTF_OEMRAW:
return "org.ofono.OemRaw";
case OFONO_DBUS_ACCESS_INTF_COUNT: case OFONO_DBUS_ACCESS_INTF_COUNT:
break; break;
} }
@@ -165,6 +170,22 @@ const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
break; break;
} }
break; break;
case OFONO_DBUS_ACCESS_INTF_STK:
switch ((enum ofono_dbus_access_stk_method)method) {
case OFONO_DBUS_ACCESS_STK_REGISTER_AGENT:
return "RegisterAgent";
case OFONO_DBUS_ACCESS_STK_METHOD_COUNT:
break;
}
break;
case OFONO_DBUS_ACCESS_INTF_OEMRAW:
switch ((enum ofono_dbus_access_oemraw_method)method) {
case OFONO_DBUS_ACCESS_OEMRAW_SEND:
return "Send";
case OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT:
break;
}
break;
case OFONO_DBUS_ACCESS_INTF_COUNT: case OFONO_DBUS_ACCESS_INTF_COUNT:
break; break;
} }

View File

@@ -3,7 +3,7 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2019 Jolla Ltd. * Copyright (C) 2015-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -2874,12 +2874,53 @@ static void provision_contexts(struct ofono_gprs *gprs, const char *mcc,
return; return;
} }
for (i = 0; i < count; i++) for (i = 0; i < count; i++) {
provision_context(&settings[i], gprs); const struct ofono_gprs_provision_data *ap = settings + i;
if (!ofono_gprs_context_settings_by_type(gprs, ap->type)) {
provision_context(ap, gprs);
}
}
__ofono_gprs_provision_free_settings(settings, count); __ofono_gprs_provision_free_settings(settings, count);
} }
static gboolean all_contexts_configured(struct ofono_gprs *gprs)
{
GSList *l;
for (l = gprs->context_drivers; l; l = l->next) {
struct ofono_gprs_context *gc = l->data;
if (gc->type != OFONO_GPRS_CONTEXT_TYPE_ANY &&
!ofono_gprs_context_settings_by_type(gprs, gc->type)) {
return FALSE; /* Not yet */
}
}
return TRUE;
}
static void configure_remaining_contexts(struct ofono_gprs *gprs)
{
GSList *l;
for (l = gprs->context_drivers; l; l = l->next) {
struct ofono_gprs_context *gc = l->data;
if (gc->type != OFONO_GPRS_CONTEXT_TYPE_ANY &&
!ofono_gprs_context_settings_by_type(gprs, gc->type)) {
add_context(gprs, NULL, gc->type);
}
}
/* Make sure internet context is there */
if (!ofono_gprs_context_settings_by_type(gprs,
OFONO_GPRS_CONTEXT_TYPE_INTERNET)) {
add_context(gprs, NULL, OFONO_GPRS_CONTEXT_TYPE_INTERNET);
}
}
static void remove_non_active_context(struct ofono_gprs *gprs, static void remove_non_active_context(struct ofono_gprs *gprs,
struct pri_context *ctx, DBusConnection *conn) struct pri_context *ctx, DBusConnection *conn)
{ {
@@ -2960,8 +3001,7 @@ static DBusMessage *gprs_reset_contexts(DBusConnection *conn,
provision_contexts(gprs, ofono_sim_get_mcc(sim), provision_contexts(gprs, ofono_sim_get_mcc(sim),
ofono_sim_get_mnc(sim), ofono_sim_get_spn(sim)); ofono_sim_get_mnc(sim), ofono_sim_get_spn(sim));
if (gprs->contexts == NULL) /* Automatic provisioning failed */ configure_remaining_contexts(gprs);
add_context(gprs, NULL, OFONO_GPRS_CONTEXT_TYPE_INTERNET);
for (l = gprs->contexts; l; l = l->next) { for (l = gprs->contexts; l; l = l->next) {
struct pri_context *ctx = l->data; struct pri_context *ctx = l->data;
@@ -3832,8 +3872,7 @@ static void ofono_gprs_finish_register(struct ofono_gprs *gprs)
struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom); struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom);
const char *path = __ofono_atom_get_path(gprs->atom); const char *path = __ofono_atom_get_path(gprs->atom);
if (gprs->contexts == NULL) /* Automatic provisioning failed */ configure_remaining_contexts(gprs);
add_context(gprs, NULL, OFONO_GPRS_CONTEXT_TYPE_INTERNET);
if (!g_dbus_register_interface(conn, path, if (!g_dbus_register_interface(conn, path,
OFONO_CONNECTION_MANAGER_INTERFACE, OFONO_CONNECTION_MANAGER_INTERFACE,
@@ -3856,56 +3895,14 @@ static void ofono_gprs_finish_register(struct ofono_gprs *gprs)
__ofono_atom_register(gprs->atom, gprs_unregister); __ofono_atom_register(gprs->atom, gprs_unregister);
} }
static gboolean mms_context_configured(struct ofono_gprs *gprs)
{
GSList *l;
for (l = gprs->contexts; l; l = l->next) {
struct pri_context *ctx = l->data;
if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS)
return TRUE;
}
return FALSE;
}
static void provision_mms_context(struct ofono_gprs *gprs, const char *mcc,
const char *mnc, const char *spn)
{
struct ofono_gprs_provision_data *settings;
int count;
int i;
if (__ofono_gprs_provision_get_settings(mcc, mnc, spn,
&settings, &count) == FALSE) {
ofono_warn("Provisioning failed");
return;
}
for (i = 0; i < count; i++) {
if (settings[i].type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
provision_context(&settings[i], gprs);
break;
}
}
__ofono_gprs_provision_free_settings(settings, count);
}
static void spn_read_cb(const char *spn, const char *dc, void *data) static void spn_read_cb(const char *spn, const char *dc, void *data)
{ {
struct ofono_gprs *gprs = data; struct ofono_gprs *gprs = data;
struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom); struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom);
struct ofono_sim *sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem); struct ofono_sim *sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
if (gprs->contexts == NULL) {
provision_contexts(gprs, ofono_sim_get_mcc(sim), provision_contexts(gprs, ofono_sim_get_mcc(sim),
ofono_sim_get_mnc(sim), spn); ofono_sim_get_mnc(sim), spn);
} else if (!mms_context_configured(gprs)) {
provision_mms_context(gprs, ofono_sim_get_mcc(sim),
ofono_sim_get_mnc(sim), spn);
}
ofono_sim_remove_spn_watch(sim, &gprs->spn_watch); ofono_sim_remove_spn_watch(sim, &gprs->spn_watch);
@@ -3927,7 +3924,7 @@ void ofono_gprs_register(struct ofono_gprs *gprs)
gprs_load_settings(gprs, ofono_sim_get_imsi(sim)); gprs_load_settings(gprs, ofono_sim_get_imsi(sim));
if (mms_context_configured(gprs)) if (all_contexts_configured(gprs))
goto finish; goto finish;
ofono_sim_add_spn_watch(sim, &gprs->spn_watch, spn_read_cb, gprs, NULL); ofono_sim_add_spn_watch(sim, &gprs->spn_watch, spn_read_cb, gprs, NULL);

View File

@@ -805,6 +805,7 @@ void __ofono_modem_append_properties(struct ofono_modem *modem,
struct ofono_devinfo *info; struct ofono_devinfo *info;
dbus_bool_t emergency = ofono_modem_get_emergency_mode(modem); dbus_bool_t emergency = ofono_modem_get_emergency_mode(modem);
const char *strtype; const char *strtype;
const char *system_path;
ofono_dbus_dict_append(dict, "Online", DBUS_TYPE_BOOLEAN, ofono_dbus_dict_append(dict, "Online", DBUS_TYPE_BOOLEAN,
&modem->online); &modem->online);
@@ -845,6 +846,11 @@ void __ofono_modem_append_properties(struct ofono_modem *modem,
&info->svn); &info->svn);
} }
system_path = ofono_modem_get_string(modem, "SystemPath");
if (system_path)
ofono_dbus_dict_append(dict, "SystemPath", DBUS_TYPE_STRING,
&system_path);
interfaces = g_new0(char *, g_slist_length(modem->interface_list) + 1); interfaces = g_new0(char *, g_slist_length(modem->interface_list) + 1);
for (i = 0, l = modem->interface_list; l; l = l->next, i++) for (i = 0, l = modem->interface_list; l; l = l->next, i++)
interfaces[i] = l->data; interfaces[i] = l->data;

View File

@@ -4,6 +4,7 @@
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2019 Jolla Ltd. * Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -282,6 +283,10 @@ enum ofono_gprs_context_type __ofono_gprs_context_get_assigned_type(
struct ofono_gprs_context *gc); struct ofono_gprs_context *gc);
#include <ofono/radio-settings.h> #include <ofono/radio-settings.h>
enum ofono_radio_access_mode __ofono_radio_access_max_mode(
enum ofono_radio_access_mode modes);
#include <ofono/audio-settings.h> #include <ofono/audio-settings.h>
#include <ofono/ctm.h> #include <ofono/ctm.h>
#include <ofono/location-reporting.h> #include <ofono/location-reporting.h>
@@ -684,3 +689,6 @@ int mnclength(int mcc, int mnc);
#include <ofono/netmon.h> #include <ofono/netmon.h>
#include <ofono/lte.h> #include <ofono/lte.h>
#include <ofono/ims.h> #include <ofono/ims.h>
void __ofono_set_config_dir(const char *dir);
void config_merge_files(GKeyFile *conf, const char *file);

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2014-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -61,10 +62,22 @@ struct ofono_radio_settings {
struct ofono_atom *atom; struct ofono_atom *atom;
}; };
enum ofono_radio_access_mode __ofono_radio_access_max_mode(
enum ofono_radio_access_mode mask)
{
return (mask & OFONO_RADIO_ACCESS_MODE_LTE) ?
OFONO_RADIO_ACCESS_MODE_LTE :
(mask & OFONO_RADIO_ACCESS_MODE_UMTS) ?
OFONO_RADIO_ACCESS_MODE_UMTS :
(mask & OFONO_RADIO_ACCESS_MODE_GSM) ?
OFONO_RADIO_ACCESS_MODE_GSM :
OFONO_RADIO_ACCESS_MODE_ANY;
}
#define radio_access_mode_to_string ofono_radio_access_mode_to_string #define radio_access_mode_to_string ofono_radio_access_mode_to_string
const char *ofono_radio_access_mode_to_string(enum ofono_radio_access_mode m) const char *ofono_radio_access_mode_to_string(enum ofono_radio_access_mode m)
{ {
switch (m) { switch (__ofono_radio_access_max_mode(m)) {
case OFONO_RADIO_ACCESS_MODE_ANY: case OFONO_RADIO_ACCESS_MODE_ANY:
return "any"; return "any";
case OFONO_RADIO_ACCESS_MODE_GSM: case OFONO_RADIO_ACCESS_MODE_GSM:
@@ -76,6 +89,10 @@ const char *ofono_radio_access_mode_to_string(enum ofono_radio_access_mode m)
default: default:
return NULL; return NULL;
} }
return (m == OFONO_RADIO_ACCESS_MODE_ANY) ? "any" :
(m & OFONO_RADIO_ACCESS_MODE_LTE) ? "lte" :
(m & OFONO_RADIO_ACCESS_MODE_UMTS) ? "umts" :
(m & OFONO_RADIO_ACCESS_MODE_GSM) ? "gsm" : NULL;
} }
#define radio_access_mode_from_string ofono_radio_access_mode_from_string #define radio_access_mode_from_string ofono_radio_access_mode_from_string
ofono_bool_t ofono_radio_access_mode_from_string(const char *str, ofono_bool_t ofono_radio_access_mode_from_string(const char *str,

View File

@@ -139,8 +139,17 @@ static void sim_auth_unregister(struct ofono_atom *atom)
struct ofono_sim_auth *sa = __ofono_atom_get_data(atom); struct ofono_sim_auth *sa = __ofono_atom_get_data(atom);
free_apps(sa); free_apps(sa);
g_free(sa->nai);
if (sa->pending) {
__ofono_dbus_pending_reply(&sa->pending->msg,
__ofono_error_sim_not_ready(sa->pending->msg));
__ofono_sim_remove_session_watch(sa->pending->session,
sa->pending->watch_id);
g_free(sa->pending); g_free(sa->pending);
sa->pending = NULL;
}
} }
static void sim_auth_remove(struct ofono_atom *atom) static void sim_auth_remove(struct ofono_atom *atom)

View File

@@ -95,13 +95,6 @@ struct sim_fs {
static void sim_fs_op_free(gpointer pointer) static void sim_fs_op_free(gpointer pointer)
{ {
struct sim_fs_op *node = pointer; struct sim_fs_op *node = pointer;
struct sim_fs *fs = node->context->fs;
/* only release the session if there are no pending reads */
if (fs->session && g_queue_is_empty(fs->op_q)) {
__ofono_sim_remove_session_watch(fs->session, fs->watch_id);
fs->watch_id = 0;
}
g_free(node->buffer); g_free(node->buffer);
g_free(node); g_free(node);
@@ -129,6 +122,9 @@ void sim_fs_free(struct sim_fs *fs)
while (fs->contexts) while (fs->contexts)
sim_fs_context_free(fs->contexts->data); sim_fs_context_free(fs->contexts->data);
if (fs->watch_id)
__ofono_sim_remove_session_watch(fs->session, fs->watch_id);
g_free(fs); g_free(fs);
} }
@@ -199,6 +195,7 @@ void sim_fs_context_free(struct ofono_sim_context *context)
if (n == 0) { if (n == 0) {
op->cb = NULL; op->cb = NULL;
op->context = NULL;
n += 1; n += 1;
continue; continue;
@@ -274,6 +271,8 @@ static void sim_fs_end_current(struct sim_fs *fs)
if (g_queue_get_length(fs->op_q) > 0) if (g_queue_get_length(fs->op_q) > 0)
fs->op_source = g_idle_add(sim_fs_op_next, fs); fs->op_source = g_idle_add(sim_fs_op_next, fs);
else if (fs->watch_id) /* release the session if no pending reads */
__ofono_sim_remove_session_watch(fs->session, fs->watch_id);
if (fs->fd != -1) { if (fs->fd != -1) {
TFR(close(fs->fd)); TFR(close(fs->fd));
@@ -923,6 +922,13 @@ static void session_read_info_cb(const struct ofono_error *error,
} }
} }
static void session_destroy_cb(void *userdata)
{
struct sim_fs *fs = userdata;
fs->watch_id = 0;
}
static void get_session_cb(ofono_bool_t active, int session_id, static void get_session_cb(ofono_bool_t active, int session_id,
void *data) void *data)
{ {
@@ -999,7 +1005,7 @@ static gboolean sim_fs_op_next(gpointer user_data)
else else
fs->watch_id = __ofono_sim_add_session_watch( fs->watch_id = __ofono_sim_add_session_watch(
fs->session, get_session_cb, fs->session, get_session_cb,
fs, NULL); fs, session_destroy_cb);
} }
} else { } else {
switch (op->structure) { switch (op->structure) {

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -1757,7 +1758,7 @@ gboolean sms_udh_iter_init_from_cbs(const struct cbs *cbs,
return FALSE; return FALSE;
hdr = cbs->ud; hdr = cbs->ud;
max_ud_len = 82; max_ud_len = cbs->udlen;
/* Must have at least one information-element if udhi is true */ /* Must have at least one information-element if udhi is true */
if (hdr[0] < 2) if (hdr[0] < 2)
@@ -3856,8 +3857,8 @@ gboolean cbs_dcs_decode(guint8 dcs, gboolean *udhi, enum sms_class *cls,
gboolean cbs_decode(const unsigned char *pdu, int len, struct cbs *out) gboolean cbs_decode(const unsigned char *pdu, int len, struct cbs *out)
{ {
/* CBS is always a fixed length of 88 bytes */ /* CBS is (almost) always a fixed length of 88 bytes */
if (len != 88) if (len < 6 || len > 88)
return FALSE; return FALSE;
out->gs = (enum cbs_geo_scope) ((pdu[0] >> 6) & 0x03); out->gs = (enum cbs_geo_scope) ((pdu[0] >> 6) & 0x03);
@@ -3868,6 +3869,10 @@ gboolean cbs_decode(const unsigned char *pdu, int len, struct cbs *out)
out->max_pages = pdu[5] & 0xf; out->max_pages = pdu[5] & 0xf;
out->page = (pdu[5] >> 4) & 0xf; out->page = (pdu[5] >> 4) & 0xf;
/* Allow the last fragment to be truncated */
if (len != 88 && out->max_pages != out->page)
return FALSE;
/* /*
* If a mobile receives the code 0000 in either the first field or * If a mobile receives the code 0000 in either the first field or
* the second field then it shall treat the CBS message exactly the * the second field then it shall treat the CBS message exactly the
@@ -3879,7 +3884,10 @@ gboolean cbs_decode(const unsigned char *pdu, int len, struct cbs *out)
out->page = 1; out->page = 1;
} }
memcpy(out->ud, pdu + 6, 82); out->udlen = (guint8)(len - 6);
memcpy(out->ud, pdu + 6, out->udlen);
if (out->udlen < 82)
memset(out->ud + out->udlen, 0, 82 - out->udlen);
return TRUE; return TRUE;
} }
@@ -4072,7 +4080,7 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
if (iso639) if (iso639)
bufsize -= 3; bufsize -= 3;
} else { } else {
bufsize += 82; bufsize += cbs->udlen;
if (iso639) if (iso639)
bufsize -= 2; bufsize -= 2;
@@ -4089,7 +4097,7 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
if (sms_udh_iter_init_from_cbs(cbs, &iter)) if (sms_udh_iter_init_from_cbs(cbs, &iter))
taken = sms_udh_iter_get_udh_length(&iter) + 1; taken = sms_udh_iter_get_udh_length(&iter) + 1;
unpack_7bit_own_buf(cbs->ud + taken, 82 - taken, unpack_7bit_own_buf(cbs->ud + taken, cbs->udlen - taken,
taken, FALSE, 2, taken, FALSE, 2,
NULL, 0, NULL, 0,
(unsigned char *)iso639_lang); (unsigned char *)iso639_lang);
@@ -4122,7 +4130,7 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
max_chars = max_chars =
sms_text_capacity_gsm(CBS_MAX_GSM_CHARS, taken); sms_text_capacity_gsm(CBS_MAX_GSM_CHARS, taken);
unpack_7bit_own_buf(ud + taken, 82 - taken, unpack_7bit_own_buf(ud + taken, cbs->udlen - taken,
taken, FALSE, max_chars, taken, FALSE, max_chars,
&written, 0, unpacked); &written, 0, unpacked);
@@ -4156,7 +4164,7 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
* the check here since the specification isn't clear * the check here since the specification isn't clear
*/ */
} else { } else {
int num_ucs2_chars = (82 - taken) >> 1; int num_ucs2_chars = (cbs->udlen - taken) >> 1;
int i = taken; int i = taken;
int max_offset = taken + num_ucs2_chars * 2; int max_offset = taken + num_ucs2_chars * 2;

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2020 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -398,6 +399,7 @@ struct cbs {
guint8 dcs; /* 8 bits */ guint8 dcs; /* 8 bits */
guint8 max_pages; /* 4 bits */ guint8 max_pages; /* 4 bits */
guint8 page; /* 4 bits */ guint8 page; /* 4 bits */
guint8 udlen;
guint8 ud[82]; guint8 ud[82];
}; };

View File

@@ -3,6 +3,8 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -725,6 +727,12 @@ static DBusMessage *stk_register_agent(DBusConnection *conn,
if (!dbus_validate_path(agent_path, NULL)) if (!dbus_validate_path(agent_path, NULL))
return __ofono_error_invalid_format(msg); return __ofono_error_invalid_format(msg);
if (!__ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
OFONO_DBUS_ACCESS_INTF_STK,
OFONO_DBUS_ACCESS_STK_REGISTER_AGENT,
agent_path))
return __ofono_error_access_denied(msg);
stk->default_agent = stk_agent_new(agent_path, stk->default_agent = stk_agent_new(agent_path,
dbus_message_get_sender(msg), dbus_message_get_sender(msg),
FALSE); FALSE);

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved. * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2019 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -36,10 +37,19 @@
#include <glib.h> #include <glib.h>
#include "storage.h" #include "storage.h"
#include "ofono.h"
static char* config_dir = NULL;
void __ofono_set_config_dir(const char *dir)
{
g_free(config_dir);
config_dir = g_strdup(dir);
}
const char *ofono_config_dir(void) const char *ofono_config_dir(void)
{ {
return CONFIGDIR; return config_dir ? config_dir : CONFIGDIR;
} }
const char *ofono_storage_dir(void) const char *ofono_storage_dir(void)

View File

@@ -349,12 +349,12 @@ static int tone_queue(struct ofono_voicecall *vc, const char *tone_str,
/* /*
* Tones can be 0-9, *, #, A-D according to 27.007 C.2.11, * Tones can be 0-9, *, #, A-D according to 27.007 C.2.11,
* and p for Pause. * and p for Pause (also , for Pause as per ITU-T V.250 6.3.1.2).
*/ */
for (i = 0; tone_str[i]; i++) for (i = 0; tone_str[i]; i++)
if (!g_ascii_isdigit(tone_str[i]) && tone_str[i] != 'p' && if (!g_ascii_isdigit(tone_str[i]) && tone_str[i] != 'p' &&
tone_str[i] != 'P' && tone_str[i] != '*' && tone_str[i] != 'P' && tone_str[i] != '*' &&
tone_str[i] != '.' && tone_str[i] != ',' && tone_str[i] != ',' &&
tone_str[i] != '#' && (tone_str[i] < 'A' || tone_str[i] != '#' && (tone_str[i] < 'A' ||
tone_str[i] > 'D')) tone_str[i] > 'D'))
return -EINVAL; return -EINVAL;
@@ -1798,7 +1798,7 @@ static DBusMessage *manager_dial(DBusConnection *conn,
return __ofono_error_failed(msg); return __ofono_error_failed(msg);
} }
static void manager_dial_last_callback(const struct ofono_error *error, static void manager_dial_hfp_callback(const struct ofono_error *error,
void *data) void *data)
{ {
struct ofono_voicecall *vc = data; struct ofono_voicecall *vc = data;
@@ -1827,7 +1827,7 @@ error:
__ofono_error_failed(vc->pending)); __ofono_error_failed(vc->pending));
} }
static int voicecall_dial_last(struct ofono_voicecall *vc, static int voicecall_dial_hfp(struct ofono_voicecall *vc, unsigned int position,
ofono_voicecall_cb_t cb, void *data) ofono_voicecall_cb_t cb, void *data)
{ {
struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom); struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom);
@@ -1838,9 +1838,6 @@ static int voicecall_dial_last(struct ofono_voicecall *vc,
if (ofono_modem_get_online(modem) == FALSE) if (ofono_modem_get_online(modem) == FALSE)
return -ENETDOWN; return -ENETDOWN;
if (vc->driver->dial_last == NULL)
return -ENOTSUP;
if (voicecalls_have_incoming(vc)) if (voicecalls_have_incoming(vc))
return -EBUSY; return -EBUSY;
@@ -1851,7 +1848,18 @@ static int voicecall_dial_last(struct ofono_voicecall *vc,
if (voicecalls_have_active(vc) && voicecalls_have_held(vc)) if (voicecalls_have_active(vc) && voicecalls_have_held(vc))
return -EBUSY; return -EBUSY;
/* when position is not given we dial the last called number */
if (position == 0) {
if (vc->driver->dial_last == NULL)
return -ENOTSUP;
vc->driver->dial_last(vc, cb, vc); vc->driver->dial_last(vc, cb, vc);
} else {
if (vc->driver->dial_memory == NULL )
return -ENOTSUP;
vc->driver->dial_memory(vc, position, cb, vc);
}
return 0; return 0;
} }
@@ -1867,7 +1875,7 @@ static DBusMessage *manager_dial_last(DBusConnection *conn,
vc->pending = dbus_message_ref(msg); vc->pending = dbus_message_ref(msg);
err = voicecall_dial_last(vc, manager_dial_last_callback, vc); err = voicecall_dial_hfp(vc, 0, manager_dial_hfp_callback, vc);
if (err >= 0) if (err >= 0)
return NULL; return NULL;
@@ -1889,6 +1897,44 @@ static DBusMessage *manager_dial_last(DBusConnection *conn,
return __ofono_error_failed(msg); return __ofono_error_failed(msg);
} }
static DBusMessage *manager_dial_memory(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ofono_voicecall *vc = data;
int memory_location;
int err;
if (vc->pending || vc->dial_req || vc->pending_em)
return __ofono_error_busy(msg);
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &memory_location,
DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
vc->pending = dbus_message_ref(msg);
err = voicecall_dial_hfp(vc, memory_location,
manager_dial_hfp_callback, vc);
if (err >= 0)
return NULL;
vc->pending = NULL;
dbus_message_unref(msg);
switch (err) {
case -EINVAL:
return __ofono_error_invalid_format(msg);
case -ENETDOWN:
return __ofono_error_not_available(msg);
case -ENOTSUP:
return __ofono_error_not_implemented(msg);
}
return __ofono_error_failed(msg);
}
static DBusMessage *manager_transfer(DBusConnection *conn, static DBusMessage *manager_transfer(DBusConnection *conn,
DBusMessage *msg, void *data) DBusMessage *msg, void *data)
{ {
@@ -2552,6 +2598,9 @@ static const GDBusMethodTable manager_methods[] = {
GDBUS_ARGS({ "path", "o" }), GDBUS_ARGS({ "path", "o" }),
manager_dial) }, manager_dial) },
{ GDBUS_ASYNC_METHOD("DialLast", NULL, NULL, manager_dial_last)}, { GDBUS_ASYNC_METHOD("DialLast", NULL, NULL, manager_dial_last)},
{ GDBUS_ASYNC_METHOD("DialMemory",
GDBUS_ARGS({"memory_location", "u" }), NULL,
manager_dial_memory) },
{ GDBUS_ASYNC_METHOD("Transfer", NULL, NULL, manager_transfer) }, { GDBUS_ASYNC_METHOD("Transfer", NULL, NULL, manager_transfer) },
{ GDBUS_ASYNC_METHOD("SwapCalls", NULL, NULL, manager_swap_calls) }, { GDBUS_ASYNC_METHOD("SwapCalls", NULL, NULL, manager_swap_calls) },
{ GDBUS_ASYNC_METHOD("ReleaseAndAnswer", NULL, NULL, { GDBUS_ASYNC_METHOD("ReleaseAndAnswer", NULL, NULL,
@@ -4340,7 +4389,7 @@ static void tone_request_cb(const struct ofono_error *error, void *data)
goto done; goto done;
} }
len = strspn(entry->left, "pP.,"); len = strspn(entry->left, "pP,");
entry->left += len; entry->left += len;
done: done:
@@ -4374,7 +4423,7 @@ static gboolean tone_request_run(gpointer user_data)
if (entry == NULL) if (entry == NULL)
return FALSE; return FALSE;
len = strcspn(entry->left, "pP.,"); len = strcspn(entry->left, "pP,");
if (len) { if (len) {
if (len > 8) /* Arbitrary length limit per request */ if (len > 8) /* Arbitrary length limit per request */

View File

@@ -20,9 +20,11 @@ TESTS="\
test-dbus-access \ test-dbus-access \
test-gprs-filter \ test-gprs-filter \
test-provision \ test-provision \
test-config \
test-watch \ test-watch \
test-ril_util \ test-ril_util \
test-ril_config \ test-ril_config \
test-ril_ecclist \
test-ril-transport \ test-ril-transport \
test-ril_vendor \ test-ril_vendor \
test-sms-filter \ test-sms-filter \

448
ofono/unit/test-config.c Normal file
View File

@@ -0,0 +1,448 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <ofono/log.h>
#include "ofono.h"
#include <gutil_strv.h>
#include <gutil_ints.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#define TMP_DIR_TEMPLATE "test-config-XXXXXX"
static gboolean test_keyfile_empty(GKeyFile *k)
{
gsize n = 0;
char **groups = g_key_file_get_groups(k, &n);
g_strfreev(groups);
return !n;
}
static void test_merge_ignore(const char *filename, const char *contents,
const char *dirname, const char *filename1, const char *contents1)
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/", filename, NULL);
char *subdir = g_strconcat(dir, "/", dirname, NULL);
char *file1 = g_strconcat(subdir, "/", filename1, NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
DBG("reading %s", file);
config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(file1);
remove(subdir);
remove(dir);
g_free(file);
g_free(file1);
g_free(dir);
g_free(subdir);
}
static void test_merge1(const char *conf, const char *conf1, const char *out)
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *file1 = g_strconcat(subdir, "/bar.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, conf, -1, NULL));
g_assert(g_file_set_contents(file1, conf1, -1, NULL));
DBG("reading %s", file);
g_key_file_set_list_separator(k, ',');
config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, out));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(file1);
remove(subdir);
remove(dir);
g_free(file);
g_free(file1);
g_free(dir);
g_free(subdir);
}
/* ==== merge_basic ==== */
static void test_merge_basic(void)
{
GKeyFile *k = g_key_file_new();
char *nonexistent = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
config_merge_files(NULL, NULL);
remove(nonexistent);
config_merge_files(k, nonexistent);
g_assert(test_keyfile_empty(k));
config_merge_files(k, NULL);
g_assert(test_keyfile_empty(k));
config_merge_files(k, "");
g_assert(test_keyfile_empty(k));
g_key_file_unref(k);
g_free(nonexistent);
}
/* ==== merge_simple ==== */
static void test_merge_simple(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
char *data;
GKeyFile *k = g_key_file_new();
g_assert(g_file_set_contents(file, contents, -1, NULL));
DBG("reading %s", file);
config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(dir);
g_free(file);
g_free(dir);
}
/* ==== merge_empty_dir ==== */
static void test_merge_empty_dir(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
DBG("reading %s", file);
config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(subdir);
remove(dir);
g_free(file);
g_free(dir);
g_free(subdir);
}
/* ==== merge_ignore ==== */
static void test_merge_ignore0(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *subdir2 = g_strconcat(subdir, "/dir.conf", NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
/* Two empty subdirectories, one with matching name, one not */
g_assert(!mkdir(subdir, 0700));
g_assert(!mkdir(subdir2, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
DBG("reading %s", file);
config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(subdir2);
remove(subdir);
remove(dir);
g_free(file);
g_free(dir);
g_free(subdir);
g_free(subdir2);
}
static void test_merge_ignore1(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\nb=3\n";
/* File has no suffix */
test_merge_ignore("foo.conf", contents, "foo.d", "file", contents1);
}
static void test_merge_ignore2(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[[[[[[[";
/* File is not a valid keyfile */
test_merge_ignore("foo.conf", contents, "foo.d", "a.conf", contents1);
}
/* ==== merge_sort ==== */
static void test_merge_sort(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\nb=3\n";
static const char contents2 [] = "[foo]\nb=4\n";
static const char result [] = "[foo]\na=1\nb=4\n";
/* Test file sort order */
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/foo.", NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *file1 = g_strconcat(subdir, "/1.conf", NULL);
char *file2 = g_strconcat(subdir, "/2.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
g_assert(g_file_set_contents(file2, contents2, -1, NULL));
DBG("reading %s", file);
config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, result));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(file1);
remove(file2);
remove(subdir);
remove(dir);
g_free(file);
g_free(file1);
g_free(file2);
g_free(dir);
g_free(subdir);
}
/* ==== merge_remove_group ==== */
static void test_merge_remove_group(void)
{
static const char contents [] = "[foo]\na=1\n\n[bar]\nb=1\n";
static const char contents1 [] = "[!bar]\n";
static const char result [] = "[foo]\na=1\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_remove_key ==== */
static void test_merge_remove_key(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\n!b=\n\n!=\n";
static const char result [] = "[foo]\na=1\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_default_value ==== */
static void test_merge_default_value(void)
{
/* b is assigned the default value, a stays as is */
static const char contents [] = "[foo]\na=1\n";
static const char contents1 [] = "[foo]\na:=2\nb:=3\n";
static const char result [] = "[foo]\na=1\nb=3\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_list_add ==== */
static void test_merge_list_add0(void)
{
/* Adding empty list */
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\na+=\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_add1(void)
{
/* a=1 turns into a=1,2, */
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\na+=2,\n";
static const char result [] = "[foo]\na=1,2,\nb=2\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_add2(void)
{
/* 2 is already there */
static const char contents [] = "[foo]\na=1,2,\nb=2\n";
static const char contents1 [] = "[foo]\na?=2\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_add3(void)
{
/* 2 is already there, 3 is not */
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na?=2,3,\n";
static const char result [] = "[foo]\na=1,2,3,\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_add4(void)
{
/* b=2,3, is created */
static const char contents [] = "[foo]\na=1\n";
static const char contents1 [] = "[foo]\nb?=2,3,\n";
static const char result [] = "[foo]\na=1\nb=2,3,\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_add5(void)
{
/* Add a new group */
static const char contents [] = "[foo]\na=1\n";
static const char contents1 [] = "[bar]\nb=2\n";
static const char result [] = "[foo]\na=1\n\n[bar]\nb=2\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_list_remove ==== */
static void test_merge_list_remove0(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na-=\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_remove1(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na-=2,\n";
static const char result [] = "[foo]\na=1,\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_remove2(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na-=3\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_remove3(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\nb-=1\n";
test_merge1(contents, contents1, contents);
}
#define TEST_(name) "/config/" name
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
__ofono_log_init("test-config",
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
g_test_add_func(TEST_("merge_basic"), test_merge_basic);
g_test_add_func(TEST_("merge_simple"), test_merge_simple);
g_test_add_func(TEST_("merge_empty_dir"), test_merge_empty_dir);
g_test_add_func(TEST_("merge_ignore0"), test_merge_ignore0);
g_test_add_func(TEST_("merge_ignore1"), test_merge_ignore1);
g_test_add_func(TEST_("merge_ignore2"), test_merge_ignore2);
g_test_add_func(TEST_("merge_sort"), test_merge_sort);
g_test_add_func(TEST_("merge_remove_group"), test_merge_remove_group);
g_test_add_func(TEST_("merge_remove_key"), test_merge_remove_key);
g_test_add_func(TEST_("merge_default_value"), test_merge_default_value);
g_test_add_func(TEST_("merge_list_add0"), test_merge_list_add0);
g_test_add_func(TEST_("merge_list_add1"), test_merge_list_add1);
g_test_add_func(TEST_("merge_list_add2"), test_merge_list_add2);
g_test_add_func(TEST_("merge_list_add3"), test_merge_list_add3);
g_test_add_func(TEST_("merge_list_add4"), test_merge_list_add4);
g_test_add_func(TEST_("merge_list_add5"), test_merge_list_add5);
g_test_add_func(TEST_("merge_list_remove0"), test_merge_list_remove0);
g_test_add_func(TEST_("merge_list_remove1"), test_merge_list_remove1);
g_test_add_func(TEST_("merge_list_remove2"), test_merge_list_remove2);
g_test_add_func(TEST_("merge_list_remove3"), test_merge_list_remove3);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2019 Jolla Ltd. * Copyright (C) 2019-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -33,6 +34,12 @@ static enum ofono_dbus_access deny_method_access(const char *sender,
return OFONO_DBUS_ACCESS_DENY; return OFONO_DBUS_ACCESS_DENY;
} }
static enum ofono_dbus_access broken_method_access(const char *sender,
enum ofono_dbus_access_intf intf, int method, const char *arg)
{
return (enum ofono_dbus_access)(-1);
}
struct ofono_dbus_access_plugin access_inval; struct ofono_dbus_access_plugin access_inval;
struct ofono_dbus_access_plugin access_dontcare = { struct ofono_dbus_access_plugin access_dontcare = {
.name = "DontCare", .name = "DontCare",
@@ -50,6 +57,12 @@ struct ofono_dbus_access_plugin access_deny = {
.method_access = deny_method_access .method_access = deny_method_access
}; };
struct ofono_dbus_access_plugin access_broken = {
.name = "Broken",
.priority = OFONO_DBUS_ACCESS_PRIORITY_LOW,
.method_access = broken_method_access
};
/*==========================================================================* /*==========================================================================*
* Tests * Tests
*==========================================================================*/ *==========================================================================*/
@@ -103,6 +116,12 @@ static const struct test_method_name_data method_name_tests[] = {
},{ },{
OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS, OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS,
OFONO_DBUS_ACCESS_RADIOSETTINGS_METHOD_COUNT OFONO_DBUS_ACCESS_RADIOSETTINGS_METHOD_COUNT
},{
OFONO_DBUS_ACCESS_INTF_STK,
OFONO_DBUS_ACCESS_STK_METHOD_COUNT
},{
OFONO_DBUS_ACCESS_INTF_OEMRAW,
OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT
} }
}; };
@@ -152,6 +171,13 @@ static void test_register()
ofono_dbus_access_plugin_unregister(&access_deny); ofono_dbus_access_plugin_unregister(&access_deny);
ofono_dbus_access_plugin_unregister(&access_dontcare); ofono_dbus_access_plugin_unregister(&access_dontcare);
/* And here too */
g_assert(!ofono_dbus_access_plugin_register(&access_broken));
g_assert(!ofono_dbus_access_plugin_register(&access_deny));
g_assert(!__ofono_dbus_access_method_allowed(":1.0", 0, 1, NULL));
ofono_dbus_access_plugin_unregister(&access_deny);
ofono_dbus_access_plugin_unregister(&access_dontcare);
/* DontCare will allow everything */ /* DontCare will allow everything */
g_assert(!ofono_dbus_access_plugin_register(&access_dontcare)); g_assert(!ofono_dbus_access_plugin_register(&access_dontcare));
g_assert(__ofono_dbus_access_method_allowed(":1.0", 0, 1, NULL)); g_assert(__ofono_dbus_access_method_allowed(":1.0", 0, 1, NULL));

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2014-2017 Jolla. All rights reserved. * Copyright (C) 2014-2020 Jolla. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -105,21 +105,21 @@ static void test_provision(gconstpointer test_data)
g_assert(actual->type == expected->type); g_assert(actual->type == expected->type);
g_assert(actual->proto == expected->proto); g_assert(actual->proto == expected->proto);
g_assert(!g_strcmp0(actual->provider_name, g_assert_cmpstr(actual->provider_name, ==,
expected->provider_name)); expected->provider_name);
g_assert(!g_strcmp0(actual->name, expected->name)); g_assert_cmpstr(actual->name, ==, expected->name);
g_assert(actual->provider_primary == g_assert(actual->provider_primary ==
expected->provider_primary); expected->provider_primary);
g_assert(!g_strcmp0(actual->apn, expected->apn)); g_assert_cmpstr(actual->apn, ==, expected->apn);
g_assert(!g_strcmp0(actual->username, g_assert_cmpstr(actual->username, ==,
expected->username)); expected->username);
g_assert(!g_strcmp0(actual->password, g_assert_cmpstr(actual->password, ==,
expected->password)); expected->password);
g_assert(actual->auth_method == expected->auth_method); g_assert(actual->auth_method == expected->auth_method);
g_assert(!g_strcmp0(actual->message_proxy, g_assert_cmpstr(actual->message_proxy, ==,
expected->message_proxy)); expected->message_proxy);
g_assert(!g_strcmp0(actual->message_center, g_assert_cmpstr(actual->message_center, ==,
expected->message_center)); expected->message_center);
} }
} else { } else {
g_assert(!__ofono_gprs_provision_get_settings(test->mcc, g_assert(!__ofono_gprs_provision_get_settings(test->mcc,
@@ -212,6 +212,14 @@ static char telia_fi_message_center [] = "http://mms/";
.apn = "mms", \ .apn = "mms", \
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
/* Default IMS settings */
#define DEFAULT_IMS_SETTINGS \
.type = OFONO_GPRS_CONTEXT_TYPE_IMS, \
.proto = OFONO_GPRS_PROTO_IPV4V6, \
.name = "IMS", \
.apn = "ims", \
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE
static const struct ofono_gprs_provision_data telia_fi_internet_mms_p[] = { static const struct ofono_gprs_provision_data telia_fi_internet_mms_p[] = {
{ {
.type = OFONO_GPRS_CONTEXT_TYPE_INTERNET, .type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
@@ -231,7 +239,8 @@ static const struct ofono_gprs_provision_data telia_fi_internet_mms_p[] = {
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE, .auth_method = OFONO_GPRS_AUTH_METHOD_NONE,
.message_proxy = telia_fi_message_proxy, .message_proxy = telia_fi_message_proxy,
.message_center = telia_fi_message_center .message_center = telia_fi_message_center
} },
{ DEFAULT_IMS_SETTINGS }
}; };
static const struct ofono_gprs_provision_data telia_fi_internet_mms[] = { static const struct ofono_gprs_provision_data telia_fi_internet_mms[] = {
@@ -251,7 +260,8 @@ static const struct ofono_gprs_provision_data telia_fi_internet_mms[] = {
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE, .auth_method = OFONO_GPRS_AUTH_METHOD_NONE,
.message_proxy = telia_fi_message_proxy, .message_proxy = telia_fi_message_proxy,
.message_center = telia_fi_message_center .message_center = telia_fi_message_center
} },
{ DEFAULT_IMS_SETTINGS }
}; };
static const struct ofono_gprs_provision_data telia_fi_internet[] = { static const struct ofono_gprs_provision_data telia_fi_internet[] = {
@@ -263,7 +273,8 @@ static const struct ofono_gprs_provision_data telia_fi_internet[] = {
.apn = telia_fi_apn_internet, .apn = telia_fi_apn_internet,
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
}, },
{ DEFAULT_MMS_SETTINGS } { DEFAULT_MMS_SETTINGS },
{ DEFAULT_IMS_SETTINGS }
}; };
static const struct ofono_gprs_provision_data telia_fi_mms[] = { static const struct ofono_gprs_provision_data telia_fi_mms[] = {
@@ -277,12 +288,14 @@ static const struct ofono_gprs_provision_data telia_fi_mms[] = {
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE, .auth_method = OFONO_GPRS_AUTH_METHOD_NONE,
.message_proxy = telia_fi_message_proxy, .message_proxy = telia_fi_message_proxy,
.message_center = telia_fi_message_center .message_center = telia_fi_message_center
} },
{ DEFAULT_IMS_SETTINGS }
}; };
static const struct ofono_gprs_provision_data default_settings[] = { static const struct ofono_gprs_provision_data default_settings[] = {
{ DEFAILT_INTERNET_SETTINGS }, { DEFAILT_INTERNET_SETTINGS },
{ DEFAULT_MMS_SETTINGS } { DEFAULT_MMS_SETTINGS },
{ DEFAULT_IMS_SETTINGS }
}; };
static const struct ofono_gprs_provision_data no_auth_settings[] = { static const struct ofono_gprs_provision_data no_auth_settings[] = {
@@ -300,7 +313,8 @@ static const struct ofono_gprs_provision_data no_auth_settings[] = {
.name = "MMS", .name = "MMS",
.apn = "mms", .apn = "mms",
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
} },
{ DEFAULT_IMS_SETTINGS }
}; };
static const struct ofono_gprs_provision_data auth_settings[] = { static const struct ofono_gprs_provision_data auth_settings[] = {
@@ -318,7 +332,8 @@ static const struct ofono_gprs_provision_data auth_settings[] = {
.apn = "mms", .apn = "mms",
.password = "password", .password = "password",
.auth_method = OFONO_GPRS_AUTH_METHOD_ANY .auth_method = OFONO_GPRS_AUTH_METHOD_ANY
} },
{ DEFAULT_IMS_SETTINGS }
}; };
static const struct ofono_gprs_provision_data settings_ip[] = { static const struct ofono_gprs_provision_data settings_ip[] = {
@@ -329,7 +344,8 @@ static const struct ofono_gprs_provision_data settings_ip[] = {
.apn = "internet", .apn = "internet",
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
}, },
{ DEFAULT_MMS_SETTINGS } { DEFAULT_MMS_SETTINGS },
{ DEFAULT_IMS_SETTINGS }
}; };
static const struct ofono_gprs_provision_data settings_ipv6[] = { static const struct ofono_gprs_provision_data settings_ipv6[] = {
@@ -345,7 +361,8 @@ static const struct ofono_gprs_provision_data settings_ipv6[] = {
.name = "MMS", .name = "MMS",
.apn = "mms", .apn = "mms",
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
} },
{ DEFAULT_IMS_SETTINGS }
}; };
static const struct ofono_gprs_provision_data settings_ipv4v6[] = { static const struct ofono_gprs_provision_data settings_ipv4v6[] = {
@@ -356,6 +373,39 @@ static const struct ofono_gprs_provision_data settings_ipv4v6[] = {
.name = "MMS", .name = "MMS",
.apn = "mms", .apn = "mms",
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
},
{ DEFAULT_IMS_SETTINGS }
};
static char beeline_provider_name [] = "Beeline";
static const struct ofono_gprs_provision_data beeline_ims[] = {
{
.type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
.proto = OFONO_GPRS_PROTO_IPV4V6,
.provider_name = beeline_provider_name,
.name = "Beeline Internet",
.apn = "internet.beeline.ru",
.username = "beeline",
.password = "beeline",
.auth_method = OFONO_GPRS_AUTH_METHOD_ANY
}, {
.type = OFONO_GPRS_CONTEXT_TYPE_MMS,
.proto = OFONO_GPRS_PROTO_IP,
.provider_name = beeline_provider_name,
.name = "Beeline MMS",
.apn = "mms.beeline.ru",
.username = "beeline",
.password = "beeline",
.auth_method = OFONO_GPRS_AUTH_METHOD_PAP,
.message_proxy = "192.168.94.23:8080",
.message_center = "http://mms/"
}, {
.type = OFONO_GPRS_CONTEXT_TYPE_IMS,
.proto = OFONO_GPRS_PROTO_IPV4V6,
.provider_name = beeline_provider_name,
.name = "Beeline IMS",
.apn = "ims.beeline.ru",
.auth_method = OFONO_GPRS_AUTH_METHOD_NONE
} }
}; };
@@ -382,7 +432,8 @@ static const struct ofono_gprs_provision_data test_username_password[] = {
.auth_method = OFONO_GPRS_AUTH_METHOD_CHAP, .auth_method = OFONO_GPRS_AUTH_METHOD_CHAP,
.message_proxy = test_message_proxy, .message_proxy = test_message_proxy,
.message_center = test_message_center .message_center = test_message_center
} },
{ DEFAULT_IMS_SETTINGS }
}; };
static const char telia_fi_internet_xml[] = static const char telia_fi_internet_xml[] =
@@ -806,6 +857,42 @@ static const struct provision_test_case test_cases[] = {
.mnc = "91", .mnc = "91",
.settings = telia_fi_mms, .settings = telia_fi_mms,
.count = G_N_ELEMENTS(telia_fi_mms) .count = G_N_ELEMENTS(telia_fi_mms)
},{
.name = TEST_SUITE "ims",
.xml =
"<serviceproviders format=\"2.0\">\n\
<country code=\"ru\">\n\
<provider>\n\
<name>Beeline</name>\n\
<gsm>\n\
<network-id mcc=\"250\" mnc=\"99\"/>\n\
<apn value=\"internet.beeline.ru\">\n\
<usage type=\"internet\"/>\n\
<name>Beeline Internet</name>\n\
<username>beeline</username>\n\
<password>beeline</password>\n\
</apn>\n\
<apn value=\"mms.beeline.ru\">\n\
<usage type=\"mms\"/>\n\
<name>Beeline MMS</name>\n\
<authentication method=\"pap\"/>\n\
<username>beeline</username>\n\
<password>beeline</password>\n\
<mmsc>http://mms/</mmsc>\n\
<mmsproxy>192.168.94.23:8080</mmsproxy>\n\
</apn>\n\
<apn value=\"ims.beeline.ru\">\n\
<usage type=\"ims\"/>\n\
<name>Beeline IMS</name>\n\
</apn>\n\
</gsm>\n\
</provider>\n\
</country>\n\
</serviceproviders>\n",
.mcc = "250",
.mnc = "99",
.settings = beeline_ims,
.count = G_N_ELEMENTS(beeline_ims)
},{ },{
.name = TEST_SUITE "not_found_mcc", .name = TEST_SUITE "not_found_mcc",
.xml = telia_fi_internet_xml, .xml = telia_fi_internet_xml,
@@ -1297,3 +1384,11 @@ int main(int argc, char **argv)
} }
return g_test_run(); return g_test_run();
} }
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2018 Jolla Ltd. * Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -47,80 +48,6 @@ static void test_get_value(const char *conf, void (*test)(GKeyFile *k))
g_free(dir); g_free(dir);
} }
static gboolean test_keyfile_empty(GKeyFile *k)
{
gsize n = 0;
char **groups = g_key_file_get_groups(k, &n);
g_strfreev(groups);
return !n;
}
static void test_merge_ignore(const char *filename, const char *contents,
const char *dirname, const char *filename1, const char *contents1)
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/", filename, NULL);
char *subdir = g_strconcat(dir, "/", dirname, NULL);
char *file1 = g_strconcat(subdir, "/", filename1, NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(file1);
remove(subdir);
remove(dir);
g_free(file);
g_free(file1);
g_free(dir);
g_free(subdir);
}
static void test_merge1(const char *conf, const char *conf1, const char *out)
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *file1 = g_strconcat(subdir, "/bar.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, conf, -1, NULL));
g_assert(g_file_set_contents(file1, conf1, -1, NULL));
DBG("reading %s", file);
g_key_file_set_list_separator(k, ',');
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, out));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(file1);
remove(subdir);
remove(dir);
g_free(file);
g_free(file1);
g_free(dir);
g_free(subdir);
}
/* ==== get_string ==== */ /* ==== get_string ==== */
static void test_get_string0_cb(GKeyFile *k) static void test_get_string0_cb(GKeyFile *k)
@@ -450,6 +377,39 @@ static void test_get_enum(void)
test_get_value(conf, test_get_enum_cb); test_get_value(conf, test_get_enum_cb);
} }
/* ==== get_mask ==== */
static void test_get_mask_cb(GKeyFile *k)
{
int v = 0;
g_assert(!ril_config_get_mask(k, "g1", "k", NULL, "x",1, "y",2, NULL));
g_assert(!ril_config_get_mask(k, "g1", "k", &v, "x",1, "y",2, NULL));
g_assert_cmpint(v, ==, 0);
g_assert(ril_config_get_mask(k, "g", "k", NULL, "x",1, "y",2, NULL));
g_assert(ril_config_get_mask(k, "g", "k", &v, "x",1, "y",2, NULL));
g_assert_cmpint(v, ==, 1);
g_assert(ril_config_get_mask(k, "g", "k1", NULL, "x",1, "y",2, NULL));
g_assert(ril_config_get_mask(k, "g", "k1", &v, "x",1, "y",2, NULL));
g_assert_cmpint(v, ==, 3);
g_assert(!ril_config_get_mask(k, "g", "k2", NULL, "x",1, "y",2, NULL));
g_assert(!ril_config_get_mask(k, "g", "k2", &v, "x",1, "y",2, NULL));
g_assert_cmpint(v, ==, 0);
}
static void test_get_mask(void)
{
static const char conf [] = "[g]\n"
"k = x# comment\n"
"k1 = x+y\n"
"k2 = x+z+y\n";
test_get_value(conf, test_get_mask_cb);
}
/* ==== get_ints ==== */ /* ==== get_ints ==== */
static void test_get_ints_cb(GKeyFile *k) static void test_get_ints_cb(GKeyFile *k)
@@ -500,311 +460,6 @@ static void test_ints_to_string(void)
g_assert(!ril_config_ints_to_string(NULL, 0)); g_assert(!ril_config_ints_to_string(NULL, 0));
} }
/* ==== merge_basic ==== */
static void test_merge_basic(void)
{
GKeyFile *k = g_key_file_new();
char *nonexistent = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
ril_config_merge_files(NULL, NULL);
remove(nonexistent);
ril_config_merge_files(k, nonexistent);
g_assert(test_keyfile_empty(k));
ril_config_merge_files(k, NULL);
g_assert(test_keyfile_empty(k));
ril_config_merge_files(k, "");
g_assert(test_keyfile_empty(k));
g_key_file_unref(k);
g_free(nonexistent);
}
/* ==== merge_simple ==== */
static void test_merge_simple(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
char *data;
GKeyFile *k = g_key_file_new();
g_assert(g_file_set_contents(file, contents, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(dir);
g_free(file);
g_free(dir);
}
/* ==== merge_empty_dir ==== */
static void test_merge_empty_dir(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(subdir);
remove(dir);
g_free(file);
g_free(dir);
g_free(subdir);
}
/* ==== merge_ignore ==== */
static void test_merge_ignore0(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *subdir2 = g_strconcat(subdir, "/dir.conf", NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
/* Two empty subdirectories, one with matching name, one not */
g_assert(!mkdir(subdir, 0700));
g_assert(!mkdir(subdir2, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(subdir2);
remove(subdir);
remove(dir);
g_free(file);
g_free(dir);
g_free(subdir);
g_free(subdir2);
}
static void test_merge_ignore1(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\nb=3\n";
/* File has no suffix */
test_merge_ignore("foo.conf", contents, "foo.d", "file", contents1);
}
static void test_merge_ignore2(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[[[[[[[";
/* File is not a valid keyfile */
test_merge_ignore("foo.conf", contents, "foo.d", "a.conf", contents1);
}
/* ==== merge_sort ==== */
static void test_merge_sort(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\nb=3\n";
static const char contents2 [] = "[foo]\nb=4\n";
static const char result [] = "[foo]\na=1\nb=4\n";
/* Test file sort order */
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/foo.", NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *file1 = g_strconcat(subdir, "/1.conf", NULL);
char *file2 = g_strconcat(subdir, "/2.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
g_assert(g_file_set_contents(file2, contents2, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, result));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(file1);
remove(file2);
remove(subdir);
remove(dir);
g_free(file);
g_free(file1);
g_free(file2);
g_free(dir);
g_free(subdir);
}
/* ==== merge_remove_group ==== */
static void test_merge_remove_group(void)
{
static const char contents [] = "[foo]\na=1\n\n[bar]\nb=1\n";
static const char contents1 [] = "[!bar]\n";
static const char result [] = "[foo]\na=1\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_remove_key ==== */
static void test_merge_remove_key(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\n!b=\n\n!=\n";
static const char result [] = "[foo]\na=1\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_default_value ==== */
static void test_merge_default_value(void)
{
/* b is assigned the default value, a stays as is */
static const char contents [] = "[foo]\na=1\n";
static const char contents1 [] = "[foo]\na:=2\nb:=3\n";
static const char result [] = "[foo]\na=1\nb=3\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_list_add ==== */
static void test_merge_list_add0(void)
{
/* Adding empty list */
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\na+=\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_add1(void)
{
/* a=1 turns into a=1,2, */
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\na+=2,\n";
static const char result [] = "[foo]\na=1,2,\nb=2\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_add2(void)
{
/* 2 is already there */
static const char contents [] = "[foo]\na=1,2,\nb=2\n";
static const char contents1 [] = "[foo]\na?=2\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_add3(void)
{
/* 2 is already there, 3 is not */
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na?=2,3,\n";
static const char result [] = "[foo]\na=1,2,3,\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_add4(void)
{
/* b=2,3, is created */
static const char contents [] = "[foo]\na=1\n";
static const char contents1 [] = "[foo]\nb?=2,3,\n";
static const char result [] = "[foo]\na=1\nb=2,3,\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_add5(void)
{
/* Add a new group */
static const char contents [] = "[foo]\na=1\n";
static const char contents1 [] = "[bar]\nb=2\n";
static const char result [] = "[foo]\na=1\n\n[bar]\nb=2\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_list_remove ==== */
static void test_merge_list_remove0(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na-=\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_remove1(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na-=2,\n";
static const char result [] = "[foo]\na=1,\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_remove2(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na-=3\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_remove3(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\nb-=1\n";
test_merge1(contents, contents1, contents);
}
#define TEST_(name) "/ril_config/" name #define TEST_(name) "/ril_config/" name
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@@ -829,28 +484,9 @@ int main(int argc, char *argv[])
g_test_add_func(TEST_("get_boolean3"), test_get_boolean3); g_test_add_func(TEST_("get_boolean3"), test_get_boolean3);
g_test_add_func(TEST_("get_flag"), test_get_flag); g_test_add_func(TEST_("get_flag"), test_get_flag);
g_test_add_func(TEST_("get_enum"), test_get_enum); g_test_add_func(TEST_("get_enum"), test_get_enum);
g_test_add_func(TEST_("get_mask"), test_get_mask);
g_test_add_func(TEST_("get_ints"), test_get_ints); g_test_add_func(TEST_("get_ints"), test_get_ints);
g_test_add_func(TEST_("ints_to_string"), test_ints_to_string); g_test_add_func(TEST_("ints_to_string"), test_ints_to_string);
g_test_add_func(TEST_("merge_basic"), test_merge_basic);
g_test_add_func(TEST_("merge_simple"), test_merge_simple);
g_test_add_func(TEST_("merge_empty_dir"), test_merge_empty_dir);
g_test_add_func(TEST_("merge_ignore0"), test_merge_ignore0);
g_test_add_func(TEST_("merge_ignore1"), test_merge_ignore1);
g_test_add_func(TEST_("merge_ignore2"), test_merge_ignore2);
g_test_add_func(TEST_("merge_sort"), test_merge_sort);
g_test_add_func(TEST_("merge_remove_group"), test_merge_remove_group);
g_test_add_func(TEST_("merge_remove_key"), test_merge_remove_key);
g_test_add_func(TEST_("merge_default_value"), test_merge_default_value);
g_test_add_func(TEST_("merge_list_add0"), test_merge_list_add0);
g_test_add_func(TEST_("merge_list_add1"), test_merge_list_add1);
g_test_add_func(TEST_("merge_list_add2"), test_merge_list_add2);
g_test_add_func(TEST_("merge_list_add3"), test_merge_list_add3);
g_test_add_func(TEST_("merge_list_add4"), test_merge_list_add4);
g_test_add_func(TEST_("merge_list_add5"), test_merge_list_add5);
g_test_add_func(TEST_("merge_list_remove0"), test_merge_list_remove0);
g_test_add_func(TEST_("merge_list_remove1"), test_merge_list_remove1);
g_test_add_func(TEST_("merge_list_remove2"), test_merge_list_remove2);
g_test_add_func(TEST_("merge_list_remove3"), test_merge_list_remove3);
return g_test_run(); return g_test_run();
} }

View File

@@ -0,0 +1,326 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "drivers/ril/ril_ecclist.h"
#include "drivers/ril/ril_log.h"
#include "ofono.h"
#include <gutil_strv.h>
#include <sys/stat.h>
#define TMP_DIR_TEMPLATE "test-ril_ecclist-XXXXXX"
#define TEST_TIMEOUT_SEC (20)
GLOG_MODULE_DEFINE("rilmodem");
static gboolean test_debug = FALSE;
struct ril_ecclist_parse_test {
const char* name;
const char* in;
const char* const* out;
};
static gboolean test_timeout_cb(gpointer user_data)
{
g_assert_not_reached();
return G_SOURCE_REMOVE;
}
static gboolean test_idle_quit_cb(gpointer loop)
{
g_main_loop_quit(loop);
return G_SOURCE_REMOVE;
}
static void test_quit_cb(struct ril_ecclist *ecc, gpointer loop)
{
g_idle_add(test_idle_quit_cb, loop);
}
static void test_inc_cb(struct ril_ecclist *ecc, gpointer ptr)
{
(*(int*)ptr)++;
}
/* ==== parse ==== */
static void test_parse(gconstpointer data)
{
const struct ril_ecclist_parse_test *test = data;
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_build_filename(dir, "ecclist", NULL);
struct ril_ecclist *ecc;
GDEBUG("Created file %s", file);
g_assert(g_file_set_contents(file, test->in, -1, NULL));
ecc = ril_ecclist_new(file);
g_assert(gutil_strv_equal(ecc->list, (char**)test->out));
ril_ecclist_unref(ecc);
remove(file);
remove(dir);
g_free(file);
g_free(dir);
}
static const char* null_str = NULL;
static const char single_str_in[] = "911";
static const char* single_str_out[] = { "911", NULL };
static const char double_str_in[] = "911,112";
static const char double2_str_in[] = "911, 112,";
static const char double3_str_in[] = "911, 911, 112 ";
static const char* double_str_out[] = { "112", "911", NULL };
static const char mtk_str_in[] = "112,31;911,31;112,-1;911,-1";
static const char mtk2_str_in[] = "112,31; 911,31; 112; 911 ";
static const struct ril_ecclist_parse_test tests[] = {
{ "empty", "", &null_str },
{ "single", single_str_in, single_str_out },
{ "double", double_str_in, double_str_out },
{ "double2", double2_str_in, double_str_out },
{ "double3", double3_str_in, double_str_out },
{ "mtk", mtk_str_in, double_str_out },
{ "mtk2", mtk2_str_in, double_str_out }
};
/* ==== file_perm ==== */
static void test_file_perm()
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_build_filename(dir, "ecclist", NULL);
int count = 0;
struct ril_ecclist *ecc;
gulong id[2];
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
guint test_timeout_id = test_debug ? 0 :
g_timeout_add_seconds(TEST_TIMEOUT_SEC, test_timeout_cb, NULL);
GDEBUG("Created file %s", file);
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
ecc = ril_ecclist_new(file);
id[0] = ril_ecclist_add_list_changed_handler(ecc, test_inc_cb, &count);
id[1] = ril_ecclist_add_list_changed_handler(ecc, test_quit_cb, loop);
g_assert(id[0]);
g_assert(id[1]);
g_assert(gutil_strv_equal(ecc->list, (char**)single_str_out));
/* Modify the file */
g_assert(g_file_set_contents(file, double_str_in, -1, NULL));
/* ril_ecclist needs event loop to process filesystem change events */
g_main_loop_run(loop);
g_assert(count == 1);
g_assert(gutil_strv_equal(ecc->list, (char**)double_str_out));
/* Making file unreadable resets the ecc list */
GDEBUG("Making file %s unreadable", file);
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
g_assert(chmod(file, 0) == 0);
count = 0;
g_main_loop_run(loop);
g_assert(count == 1);
g_assert(!ecc->list);
if (test_timeout_id) {
g_source_remove(test_timeout_id);
}
g_main_loop_unref(loop);
ril_ecclist_remove_handler(ecc, id[0]);
ril_ecclist_remove_handler(ecc, id[1]);
ril_ecclist_unref(ecc);
remove(dir);
g_free(file);
g_free(dir);
}
/* ==== file_change ==== */
static void test_file_change()
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_build_filename(dir, "ecclist", NULL);
int count = 0;
struct ril_ecclist *ecc;
gulong id[2];
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
guint test_timeout_id = test_debug ? 0 :
g_timeout_add_seconds(TEST_TIMEOUT_SEC, test_timeout_cb, NULL);
GDEBUG("Created file %s", file);
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
ecc = ril_ecclist_new(file);
id[0] = ril_ecclist_add_list_changed_handler(ecc, test_inc_cb, &count);
id[1] = ril_ecclist_add_list_changed_handler(ecc, test_quit_cb, loop);
g_assert(id[0]);
g_assert(id[1]);
g_assert(gutil_strv_equal(ecc->list, (char**)single_str_out));
/* Modify the file */
g_assert(g_file_set_contents(file, double_str_in, -1, NULL));
/* ril_ecclist needs event loop to process filesystem change events */
g_main_loop_run(loop);
g_assert(count == 1);
g_assert(gutil_strv_equal(ecc->list, (char**)double_str_out));
/* Removing the file resets the ecc list */
GDEBUG("Removing file %s", file);
g_assert(remove(file) == 0);
count = 0;
g_main_loop_run(loop);
g_assert(count == 1);
g_assert(!ecc->list);
if (test_timeout_id) {
g_source_remove(test_timeout_id);
}
g_main_loop_unref(loop);
ril_ecclist_remove_handler(ecc, id[0]);
ril_ecclist_remove_handler(ecc, id[1]);
ril_ecclist_unref(ecc);
remove(dir);
g_free(file);
g_free(dir);
}
/* ==== dir_change ==== */
static void test_dir_change()
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_build_filename(dir, "ecclist", NULL);
int count = 0;
struct ril_ecclist *ecc;
gulong id[3];
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
guint test_timeout_id = test_debug ? 0 :
g_timeout_add_seconds(TEST_TIMEOUT_SEC, test_timeout_cb, NULL);
GDEBUG("Created directory %s", dir);
ecc = ril_ecclist_new(file);
id[0] = ril_ecclist_add_list_changed_handler(ecc, test_inc_cb, &count);
id[1] = ril_ecclist_add_list_changed_handler(ecc, test_quit_cb, loop);
g_assert(id[0]);
g_assert(id[1]);
g_assert(!ecc->list);
GDEBUG("Created file %s", file);
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
/* ril_ecclist needs event loop to process filesystem change events */
g_main_loop_run(loop);
g_assert(count == 1);
g_assert(gutil_strv_equal(ecc->list, (char**)single_str_out));
/* Removing the directory resets the ecc list */
GDEBUG("Removing directory %s", dir);
g_assert(remove(file) == 0);
g_assert(remove(dir) == 0);
count = 0;
g_main_loop_run(loop);
g_assert(count == 1);
g_assert(!ecc->list);
if (test_timeout_id) {
g_source_remove(test_timeout_id);
}
g_main_loop_unref(loop);
ril_ecclist_remove_handler(ecc, id[0]);
ril_ecclist_remove_handler(ecc, id[1]);
ril_ecclist_unref(ecc);
g_free(file);
g_free(dir);
}
/* ==== null ==== */
static void test_null(void)
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_build_filename(dir, "ecclist", NULL);
struct ril_ecclist *ecc;
/* Make sure neither directory nor file exist */
remove(dir);
ecc = ril_ecclist_new(file);
g_assert(ecc);
g_assert(!ecc->list);
g_assert(!ril_ecclist_new(NULL));
g_assert(!ril_ecclist_ref(NULL));
g_assert(!ril_ecclist_add_list_changed_handler(NULL, NULL, NULL));
g_assert(!ril_ecclist_add_list_changed_handler(ecc, NULL, NULL));
ril_ecclist_unref(NULL);
ril_ecclist_remove_handler(NULL, 0);
ril_ecclist_remove_handler(ecc, 0);
ril_ecclist_unref(ril_ecclist_ref(ecc));
ril_ecclist_unref(ecc);
g_free(file);
g_free(dir);
}
#define TEST_(name) "/ril_ecclist/" name
int main(int argc, char *argv[])
{
int i;
g_test_init(&argc, &argv, NULL);
gutil_log_timestamp = FALSE;
gutil_log_default.name = "test-ril_ecclist";
gutil_log_default.level = g_test_verbose() ?
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
__ofono_log_init(gutil_log_default.name,
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
if (argc > 1 && !strcmp(argv[1] , "-d")) {
test_debug = TRUE;
GDEBUG("Debugging on (no timeout)");
}
for (i = 0; i < G_N_ELEMENTS(tests); i++) {
const struct ril_ecclist_parse_test* test = tests + i;
char* path = g_strconcat(TEST_("parse/"), test->name, NULL);
g_test_add_data_func(path, test, test_parse);
g_free(path);
}
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("file_perm"), test_file_perm);
g_test_add_func(TEST_("file_change"), test_file_change);
g_test_add_func(TEST_("dir_change"), test_dir_change);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,8 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2017-2019 Jolla Ltd. * Copyright (C) 2017-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@@ -46,6 +47,7 @@
#define TEST_SPN "Test" #define TEST_SPN "Test"
#define TEST_ERROR_KEY "Error" #define TEST_ERROR_KEY "Error"
#define TEST_SLOT_ERROR_KEY "SlotError" #define TEST_SLOT_ERROR_KEY "SlotError"
#define TEST_CONFIG_DIR_TEMPLATE "test-saifish_manager-config-XXXXXX"
extern struct ofono_plugin_desc __ofono_builtin_sailfish_manager; extern struct ofono_plugin_desc __ofono_builtin_sailfish_manager;
static GMainLoop *test_loop = NULL; static GMainLoop *test_loop = NULL;
@@ -970,6 +972,128 @@ static void test_voice_sim(void)
test_common_deinit(); test_common_deinit();
} }
/* ==== auto_data_sim ==== */
static gboolean test_auto_data_sim_done(gpointer user_data)
{
test_slot_manager *sm = user_data;
test_slot *s = sm->slot;
struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
struct ofono_watch *w = ofono_watch_new(TEST_PATH);
struct ofono_watch *w2 = ofono_watch_new(TEST_PATH_1);
struct ofono_modem modem;
struct ofono_sim sim;
struct ofono_sim sim2;
memset(&modem, 0, sizeof(modem));
memset(&sim, 0, sizeof(sim));
sim.mcc = TEST_MCC;
sim.mnc = TEST_MNC;
sim.state = OFONO_SIM_STATE_READY;
sim2 = sim;
/* Assign IMSI to the SIMs */
w->modem = &modem;
fake_watch_signal_queue(w, FAKE_WATCH_SIGNAL_MODEM_CHANGED);
fake_watch_set_ofono_sim(w, &sim);
fake_watch_set_ofono_iccid(w, TEST_ICCID);
fake_watch_set_ofono_imsi(w, TEST_IMSI);
fake_watch_emit_queued_signals(w);
w2->modem = &modem;
fake_watch_signal_queue(w2, FAKE_WATCH_SIGNAL_MODEM_CHANGED);
fake_watch_set_ofono_sim(w2, &sim2);
fake_watch_set_ofono_iccid(w2, TEST_ICCID_1);
fake_watch_set_ofono_imsi(w2, TEST_IMSI_1);
fake_watch_emit_queued_signals(w2);
/* No data SIM yet, only voice SIM is assigned */
g_assert(s->data_role == SAILFISH_DATA_ROLE_NONE);
g_assert(!m->default_voice_imsi);
g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
g_assert(!m->default_data_imsi);
g_assert(!m->default_data_path);
/* Set the first modem online */
w->online = TRUE;
fake_watch_signal_queue(w, FAKE_WATCH_SIGNAL_ONLINE_CHANGED);
fake_watch_emit_queued_signals(w);
/* Now data modem must point to the first slot */
g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
ofono_watch_unref(w);
ofono_watch_unref(w2);
g_main_loop_quit(test_loop);
return G_SOURCE_REMOVE;
}
static guint test_auto_data_sim_start(test_slot_manager *sm)
{
struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
test_slot *s = g_new0(test_slot, 1);
test_slot *s2 = g_new0(test_slot, 1);
DBG("");
/* Create the slots */
DBG("");
s->handle = sailfish_manager_slot_add(sm->handle, s, TEST_PATH,
OFONO_RADIO_ACCESS_MODE_GSM, NULL, TEST_IMEISV,
SAILFISH_SIM_STATE_PRESENT);
s2->handle = sailfish_manager_slot_add(sm->handle, s2, TEST_PATH_1,
OFONO_RADIO_ACCESS_MODE_GSM, NULL, TEST_IMEISV,
SAILFISH_SIM_STATE_PRESENT);
sm->slot = s;
sm->slot2 = s2;
sailfish_slot_manager_started(sm->handle);
g_assert(!m->ready);
sailfish_manager_imei_obtained(s->handle, TEST_IMEI);
g_assert(!m->ready);
sailfish_manager_imei_obtained(s2->handle, TEST_IMEI_1);
g_assert(m->ready);
g_idle_add(test_auto_data_sim_done, sm);
return 0;
}
static void test_auto_data_sim(gconstpointer option)
{
static const struct sailfish_slot_driver test_auto_data_sim_driver = {
.name = "auto_data_sim",
.manager_create = test_slot_manager_create,
.manager_start = test_auto_data_sim_start,
.manager_free = test_slot_manager_free,
.slot_enabled_changed = test_slot_enabled_changed,
.slot_free = test_slot_free
};
char *cfg_dir = g_dir_make_tmp(TEST_CONFIG_DIR_TEMPLATE, NULL);
char *cfg_file = g_build_filename(cfg_dir, "main.conf", NULL);
GKeyFile* cfg = g_key_file_new();
struct sailfish_slot_driver_reg *reg;
g_key_file_set_string(cfg, "ModemManager", "AutoSelectDataSim", option);
g_assert(g_key_file_save_to_file(cfg, cfg_file, NULL));
g_key_file_unref(cfg);
__ofono_set_config_dir(cfg_dir);
test_common_init();
reg = sailfish_slot_driver_register(&test_auto_data_sim_driver);
g_assert(reg);
g_main_loop_run(test_loop);
sailfish_slot_driver_unregister(reg);
test_common_deinit();
__ofono_set_config_dir(NULL);
remove(cfg_file);
remove(cfg_dir);
g_free(cfg_file);
g_free(cfg_dir);
}
/* ==== data_sim ==== */ /* ==== data_sim ==== */
static gboolean test_data_sim_done(gpointer user_data) static gboolean test_data_sim_done(gpointer user_data)
@@ -1066,8 +1190,17 @@ static void test_data_sim(void)
.slot_enabled_changed = test_slot_enabled_changed, .slot_enabled_changed = test_slot_enabled_changed,
.slot_free = test_slot_free .slot_free = test_slot_free
}; };
char *cfg_dir = g_dir_make_tmp(TEST_CONFIG_DIR_TEMPLATE, NULL);
char *cfg_file = g_build_filename(cfg_dir, "main.conf", NULL);
GKeyFile* cfg = g_key_file_new();
struct sailfish_slot_driver_reg *reg; struct sailfish_slot_driver_reg *reg;
/* Invalid AutoSelectDataSim option is treated as "off" */
g_key_file_set_string(cfg, "ModemManager", "AutoSelectDataSim", "x");
g_assert(g_key_file_save_to_file(cfg, cfg_file, NULL));
g_key_file_unref(cfg);
__ofono_set_config_dir(cfg_dir);
test_common_init(); test_common_init();
reg = sailfish_slot_driver_register(&test_data_sim_driver); reg = sailfish_slot_driver_register(&test_data_sim_driver);
g_assert(reg); g_assert(reg);
@@ -1076,6 +1209,12 @@ static void test_data_sim(void)
sailfish_slot_driver_unregister(reg); sailfish_slot_driver_unregister(reg);
test_common_deinit(); test_common_deinit();
__ofono_set_config_dir(NULL);
remove(cfg_file);
remove(cfg_dir);
g_free(cfg_file);
g_free(cfg_dir);
} }
/* ==== mms_sim ==== */ /* ==== mms_sim ==== */
@@ -1511,6 +1650,12 @@ int main(int argc, char *argv[])
g_test_add_func(TEST_("cancel_start"), test_cancel_start); g_test_add_func(TEST_("cancel_start"), test_cancel_start);
g_test_add_func(TEST_("voice_sim"), test_voice_sim); g_test_add_func(TEST_("voice_sim"), test_voice_sim);
g_test_add_func(TEST_("data_sim"), test_data_sim); g_test_add_func(TEST_("data_sim"), test_data_sim);
g_test_add_data_func(TEST_("auto_data_sim_on"), "on",
test_auto_data_sim);
g_test_add_data_func(TEST_("auto_data_sim_always"), "always",
test_auto_data_sim);
g_test_add_data_func(TEST_("auto_data_sim_once"), "once",
test_auto_data_sim);
g_test_add_func(TEST_("mms_sim"), test_mms_sim); g_test_add_func(TEST_("mms_sim"), test_mms_sim);
g_test_add_func(TEST_("multisim"), test_multisim); g_test_add_func(TEST_("multisim"), test_multisim);
g_test_add_func(TEST_("storage"), test_storage); g_test_add_func(TEST_("storage"), test_storage);

View File

@@ -500,8 +500,8 @@ static void test_application_entry_decode(void)
g_assert(app[1]->label != NULL); g_assert(app[1]->label != NULL);
g_assert(!strcmp(app[1]->label, "MIDPfiles")); g_assert(!strcmp(app[1]->label, "MIDPfiles"));
g_free(ef_dir);
g_slist_free_full(entries, (GDestroyNotify) sim_app_record_free); g_slist_free_full(entries, (GDestroyNotify) sim_app_record_free);
g_free(ef_dir);
} }
static void test_get_3g_path(void) static void test_get_3g_path(void)

View File

@@ -1,13 +1,12 @@
Name: ofono Name: ofono
Summary: Open Source Telephony Summary: Open Source Telephony
Version: 1.22 Version: 1.23
Release: 1 Release: 1
Group: Communications/Connectivity Adaptation
License: GPLv2 License: GPLv2
URL: https://git.sailfishos.org/mer-core/ofono URL: https://git.sailfishos.org/mer-core/ofono
Source: %{name}-%{version}.tar.bz2 Source: %{name}-%{version}.tar.bz2
%define libgrilio_version 1.0.35 %define libgrilio_version 1.0.38
%define libglibutil_version 1.0.30 %define libglibutil_version 1.0.30
%define libmce_version 1.0.6 %define libmce_version 1.0.6
@@ -38,13 +37,13 @@ BuildRequires: pkgconfig(mobile-broadband-provider-info)
BuildRequires: libtool BuildRequires: libtool
BuildRequires: automake BuildRequires: automake
BuildRequires: autoconf BuildRequires: autoconf
BuildRequires: systemd
%description %description
Telephony stack Telephony stack
%package devel %package devel
Summary: Headers for oFono Summary: Headers for oFono
Group: Development/Libraries
Requires: %{name} = %{version}-%{release} Requires: %{name} = %{version}-%{release}
%description devel %description devel
@@ -52,7 +51,6 @@ Development headers and libraries for oFono
%package tests %package tests
Summary: Test Scripts for oFono Summary: Test Scripts for oFono
Group: Development/Libraries
Requires: %{name} = %{version}-%{release} Requires: %{name} = %{version}-%{release}
Requires: dbus-python3 Requires: dbus-python3
Requires: python3-gobject Requires: python3-gobject
@@ -64,7 +62,6 @@ Scripts for testing oFono and its functionality
%package configs-mer %package configs-mer
Summary: Package to provide default configs for ofono Summary: Package to provide default configs for ofono
Group: Development/Tools
Provides: ofono-configs Provides: ofono-configs
%description configs-mer %description configs-mer
@@ -72,7 +69,6 @@ This package provides default configs for ofono
%package doc %package doc
Summary: Documentation for %{name} Summary: Documentation for %{name}
Group: Documentation
Requires: %{name} = %{version}-%{release} Requires: %{name} = %{version}-%{release}
%description doc %description doc
@@ -98,9 +94,9 @@ autoreconf --force --install
--disable-add-remove-context \ --disable-add-remove-context \
--disable-isimodem \ --disable-isimodem \
--disable-qmimodem \ --disable-qmimodem \
--with-systemdunitdir="/%{_lib}/systemd/system" --with-systemdunitdir=%{_unitdir}
make %{_smp_mflags} %make_build
%check %check
# run unit tests # run unit tests
@@ -111,9 +107,9 @@ rm -rf %{buildroot}
%make_install %make_install
mkdir -p %{buildroot}/%{_sysconfdir}/ofono/push_forwarder.d mkdir -p %{buildroot}/%{_sysconfdir}/ofono/push_forwarder.d
mkdir -p %{buildroot}/%{_lib}/systemd/system/network.target.wants mkdir -p %{buildroot}%{_unitdir}/network.target.wants
mkdir -p %{buildroot}/var/lib/ofono mkdir -p %{buildroot}/var/lib/ofono
ln -s ../ofono.service %{buildroot}/%{_lib}/systemd/system/network.target.wants/ofono.service ln -s ../ofono.service %{buildroot}%{_unitdir}/network.target.wants/ofono.service
mkdir -p %{buildroot}%{_docdir}/%{name}-%{version} mkdir -p %{buildroot}%{_docdir}/%{name}-%{version}
install -m0644 -t %{buildroot}%{_docdir}/%{name}-%{version} \ install -m0644 -t %{buildroot}%{_docdir}/%{name}-%{version} \
@@ -139,8 +135,8 @@ systemctl daemon-reload ||:
%license COPYING %license COPYING
%config %{_sysconfdir}/dbus-1/system.d/*.conf %config %{_sysconfdir}/dbus-1/system.d/*.conf
%{_sbindir}/* %{_sbindir}/*
/%{_lib}/systemd/system/network.target.wants/ofono.service %{_unitdir}/network.target.wants/ofono.service
/%{_lib}/systemd/system/ofono.service %{_unitdir}/ofono.service
%dir %{_sysconfdir}/ofono/ %dir %{_sysconfdir}/ofono/
%dir %{_sysconfdir}/ofono/push_forwarder.d %dir %{_sysconfdir}/ofono/push_forwarder.d
# This file is part of phonesim and not needed with ofono. # This file is part of phonesim and not needed with ofono.