Compare commits

...

118 Commits

Author SHA1 Message Date
Slava Monich
d13e48b638 Merge branch 'radio_caps' into 'master'
Start using RIL_REQUEST_SET_RADIO_CAPABILITY

See merge request !122
2017-06-15 11:53:27 +00:00
Slava Monich
e0edfca358 [ril] Added SetRadioCapability config option. JB#38689
The RIL_REQUEST_SET_RADIO_CAPABILITY request is still not supported
by some relatively recent RILs, it should be possible to forcibly
turn it off.
2017-06-14 17:54:34 +03:00
Slava Monich
7cd2075ada [ril] Start using SET_RADIO_CAPABILITY. Fixes JB#38689
With some RILs it seems to be the only way to let all slots to use 4G,
SET_PREFERRED_NETWORK_TYPE is not always enough.
2017-06-14 17:50:51 +03:00
Slava Monich
3ccacfd5f7 [ril] Notify rild when we don't need mobile data. JB#38689
We were only telling rild when we need mobile data, but we should also
tell it when we don't need it.
2017-06-11 21:27:28 +03:00
Slava Monich
5ee13f8e2c [rpm] Drop the .changes file
It's not being maintained.
2017-06-11 16:09:09 +03:00
Slava Monich
6ab9dcb553 Merge branch 'sailfish_plugins' into 'master'
Consistent naming of Sailfish OS specific plugins

See merge request !125
2017-06-11 13:08:19 +00:00
Slava Monich
102061107a [ofono] push-forwarder -> sailfish-pushforwarder. Fixes JB#38927
The configure option --enable-sailfish-pushforwarder is now required in order
to enable this plugin (it was enabled by default)
2017-06-11 15:56:03 +03:00
Slava Monich
2bb7d629f5 [ofono] debuglog plugin -> sailfish_debuglog. JB#38927 2017-06-11 15:47:43 +03:00
Slava Monich
5ce01787e8 [ofono] Renamed jolla-rilmodem configure option into sailfish-rilmodem. JB#38927 2017-06-11 15:42:30 +03:00
Slava Monich
1d57cb0e73 [ofono] Renamed sailfishos configure option to sailfish-bt. JB#38927
Also, renamed sfos_bt.c into sailfish_bt.c so that the file name
looks similar to the configure option that enables it.
2017-06-11 15:41:56 +03:00
Slava Monich
3d84c0a120 [ofono] Renamed Sailfish OS specific provision plugin to sailfish_provision. JB#38927
plugins/provision.c is the original upstream provisioning plugin and
plugins/sailfish_provision.c is the Sailfish OS specific thing. They
are mutually exclusuve.

Sailfish OS specific plugin is enabled with --enable-sailfish-provision
configure switch. By default, the upstream plugin is used.
2017-06-11 15:40:57 +03:00
Slava Monich
091cf21c0b Merge branch 'hangup' into 'master'
Keep hangup D-Bus request pending until RIL hangup completes

See merge request !123
2017-06-08 09:58:44 +00:00
Slava Monich
351ac1e9db [ril] Keep hangup D-Bus request pending until RIL hangup completes. JB#38105 2017-06-07 16:49:57 +03:00
Slava Monich
b7481a918f radio-settings: Fix memory leaks in radio_load_settings
Errors returned by g_key_file_get_integer have to be deallocated
by the caller to avoid leaks like these:

==13330== 104 (24 direct, 80 indirect) bytes in 2 blocks are definitely lost
==13330==    at 0x483F3EC: malloc (vg_replace_malloc.c)
==13330==    by 0x4B020DF: g_malloc (gmem.c)
==13330==    by 0x4B17F51: g_slice_alloc (gslice.c)
==13330==    by 0x4AE80B9: g_error_new_valist (gerror.c)
==13330==    by 0x4AE830B: g_set_error (gerror.c)
==13330==    by 0x4AF5681: g_key_file_get_value (gkeyfile.c)
==13330==    by 0x4AF6817: g_key_file_get_integer (gkeyfile.c)
==13330==    by 0x10CFE3: radio_load_settings (radio-settings.c)
==13330==    by 0x10D2E3: ofono_radio_settings_register (radio-settings.c)
2017-06-02 21:23:23 +03:00
Slava Monich
e1e4381105 Merge branch 'default_data_sim' into 'master'
Don't auto-select the data sim on a multisim phone

See merge request !121
2017-05-31 07:59:32 +00:00
Slava Monich
cc3ca52e61 [ril] Don't auto-select the data sim on a multisim phone. JB#38719
This kind of behavior is reserved for single sim phone (for now).
2017-05-30 16:44:15 +03:00
Slava Monich
a71779ea2a [ril] Added assert in ril_sim_card_status_parse
.. that we have parsed the entire parcel to the end
2017-05-26 12:10:04 +03:00
Slava Monich
a9d2849bbb Merge branch 'jb38795' into 'master'
Fix passing -j to make

See merge request !120
2017-05-25 13:38:34 +00:00
Martin Kampas
ca29c8e538 [packaging] Fix passing -j to make. Contribute to JB#38795 2017-05-25 14:28:18 +02:00
Slava Monich
85fe1b7174 Merge branch 'imei' into 'master'
Use RIL_REQUEST_DEVICE_IDENTITY  instead of RIL_REQUEST_GET_IMEI

See merge request !117
2017-05-12 21:17:02 +00:00
Slava Monich
56e0d9dffa Merge branch 'file_watches' into 'master'
Prevent a crash in sim_fs_notify_file_watches

See merge request !118
2017-05-12 20:33:58 +00:00
Slava Monich
6867ba65cb [simfs] Prevent a crash in sim_fs_notify_file_watches. Fixes JB#38656
If no file watchers have ever been added, context->file_watches
is NULL and sim_fs_notify_file_watches() should take that into
account.
2017-05-12 18:51:53 +03:00
Slava Monich
6199eaa4d8 [ril] Allow (some) DEVICE_IDENTITY requests to time out. Fixes JB#38632
If GET_SIM_STATUS succeeds but DEVICE_IDENTITY keeps on failing,
allow the latter to time out. Some RILs behave that way until the
modem has been properly initialized.
2017-05-12 17:21:40 +03:00
Slava Monich
fabdd6799c [ril] Use DEVICE_IDENTITY request instead of GET_IMEI. Contributes to JB#38632
RIL_REQUEST_GET_IMEI has been deprecated since 2009
2017-05-12 17:15:01 +03:00
Slava Monich
1219ab6a3f Merge branch 'permlock' into 'master'
Detection of permanently locked SIM cards

See merge request !116
2017-04-28 16:13:23 +00:00
Slava Monich
85a956d9eb [ril] Improved detection of permanently locked SIM cards. JB#38257
If PUK is required, app state is PUK and pin1_state is ENABLED_BLOCKED.
If the card is permanently locked, app state is still PUK but pin1_state
becomes ENABLED_PERM_BLOCKED. That way we can tell whether the SIM card
is locked even if the number of remaining attempts is not available.
2017-04-28 16:06:22 +03:00
Slava Monich
c83d992a3b Merge branch 'retries' into 'master'
Query PUK retry count

See merge request !115
2017-04-28 11:54:09 +00:00
Slava Monich
b22027017c [ril] Query PUK retry count. JB#38257
PUK retry counts can be queried in a way similar to PIN retry counts
on those RILs that support it.
2017-04-27 21:36:46 +03:00
Slava Monich
1fa137b36d [sim] Allow plugins to use puk2pin() function 2017-04-27 21:27:27 +03:00
Slava Monich
cfd837b1db Merge branch 'puk' into 'master'
Always refresh SIM status from query_passwd_state

See merge request !114
2017-04-27 08:08:20 +00:00
Slava Monich
735ad21e89 [ril] Always refresh SIM status from query_passwd_state. Fixes JB#38257
After we have entered an invalid pin too many times, RIL signals
the SIM status change, we request the new status but ofono core
asks us for the new passwd state before our SIM status query has
completed. We need to wait for the query to complete before we can
report the new status to the core.

It also won't hurt if we request a fresh SIM status every time
when query_passwd_state callback is called, just in case if RIL
fails to notify us about the SIM status change.
2017-04-26 15:03:26 +03:00
Slava Monich
c9078404de [ril] Housekeeping 2017-04-14 19:51:42 +03:00
Slava Monich
e375195c92 Merge branch 'tech' into 'master'
Add "technologies" configuration option

See merge request !111
2017-04-10 21:10:22 +00:00
Slava Monich
ef5610f741 [ril] Added "technologies" configuration option. Fixes JB#38295
It supersedes enable4G option.
2017-04-05 21:18:00 +03:00
jpoutiai
aef9bbd3e0 Merge branch 'jb38053' into 'master'
[plugins] support bt call audio control. Fixes JB#38053

See merge request !110
2017-04-05 10:23:27 +00:00
Jarko Poutiainen
c6eb410f21 [plugins] support bt call audio control. Fixes JB#38053 2017-04-05 08:35:55 +03:00
Slava Monich
08b3ea3d0f Merge branch 'last_fail' into 'master'
Handle fancy variant of LAST_CALL_FAIL_CAUSE response

Some RILs get creative and invent their own formats.
They must be very proud of it.

See merge request !106
2017-03-15 21:46:11 +00:00
Slava Monich
2978862417 [ril] Handle fancy variant of LAST_CALL_FAIL_CAUSE response. Fixes JB#38079
Some RILs get creative and invent their own formats.
2017-03-15 17:19:37 +02:00
Slava Monich
19228c9e67 Merge branch 'lastcause' into 'master'
Allow to configure custom hangup reasons

One can define localHangupReasons and remoteHangupReasons in
ril_subscription.conf which will be treated as normal local or
remote hangup reasons.

See merge request !104
2017-02-24 13:11:46 +00:00
Slava Monich
9be791d531 [ofono] Allow to conifigure custom hangup reasons. Fixes JB#37879
One can define localHangupReasons and remoteHangupReasons in
ril_subscription.conf which will be treated as normal local or
remote hangup reasons. The value is a comma-separated list of
numbers, e.g.

localHangupReasons=20,39
2017-02-24 12:07:57 +02:00
Slava Monich
6b9eb7bf8f Merge branch 'voicecall' into 'master'
Don't use internal voicecall data structures

Added ofono_voicecall_find_call API instead

See merge request !105
2017-02-24 10:06:39 +00:00
Slava Monich
01f8989aee [ril] Don't use internal voicecall data structures
Use newly added ofono_voicecall_find_call API instead
2017-02-24 00:28:50 +02:00
Slava Monich
2f5efaf591 [ofono] Added ofono_voicecall_find_call API
For use by plugins
2017-02-24 00:28:18 +02:00
Slava Monich
ca1d06c37a Merge branch 'disable' into 'master'
Disable some unnecessary and harmful functionality

See merge request !103
2017-01-12 15:17:23 +00:00
Slava Monich
5f45928a84 [ofono] Disable PhoNet/ISI and QMI modem support. MER#1734
This makes ARM executable smaller by 170 KB
2017-01-12 00:47:04 +02:00
Slava Monich
19f74e6c85 [ofono] Don't allow to add or remove connection context over D-Bus. Fixes MER#1733
Quite a few things in SailfishOS assume that each modem has exactly
one internet and one mms context. However, ofono's D-Bus API allows
any application to arbitrarily add and remove connection contexts
which can screw things up quite badly. Since this functionality is
not used by SailfishOS, it should be disabled.
2017-01-12 00:27:17 +02:00
Slava Monich
41d5cfcab2 Merge branch 'modem-error' into 'master'
Count rild crashes

See merge request !102
2017-01-11 11:58:42 +00:00
Slava Monich
357c5db580 [ril] Count rild crashes. Contributes to JB#35780
org.nemomobile.ofono.ModemManager.ModemError signal is emitted
when rild crash is detected. Also, the new GetModemErrors method
allows to query how many times which instance of rild has crashed
since ofono was (re)started.
2017-01-11 13:24:23 +02:00
Slava Monich
8cea5b9f96 [ril] Allow to retry GET_BROADCAST_SMS_CONFIG. MER#1729
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG sometimes fails at startup.
We may have to retry a few times (typically, once or twice on Jolla 1)
2017-01-05 18:40:50 +03:00
Slava Monich
5fb35d5fb4 Merge branch 'v1.19' into 'master'
Update ofono baseline to 1.19

It's the latest stable release.

See merge request !101
2017-01-05 12:39:13 +00:00
Slava Monich
e8d57bb928 [ofono] Update baseline to 1.19
Removed merge artifacts
2017-01-05 15:37:58 +03:00
Slava Monich
2bfde2418e [ril] Removed old workaround breaking hot-swap. Fixes MER#1730
The workaround is no longer needed. All SIM I/O requests have to
be completed even if the SIM card is removed while the request is
pending. Otherwise simfs request queue gets stuck.
2017-01-05 15:35:29 +03:00
Marcel Holtmann
c710ce76c1 Release 1.19 2017-01-05 11:20:08 +03:00
Alfonso Sánchez-Beato
78acd90464 gitignore: unit/test-rilmodem-gprs binary 2017-01-05 11:20:08 +03:00
Alfonso Sánchez-Beato
e51b3ca0c8 build: add rilmodem gprs unit tests
Conflicts:
	ofono/Makefile.am
2017-01-05 11:20:08 +03:00
Alfonso Sánchez-Beato
b3c8813bd4 unit: add rilmodem gprs tests
Add rilmodem gprs tests, which use the rilmodem test engine.
2017-01-05 11:20:08 +03:00
Alfonso Sánchez-Beato
e2a3acd9d0 unit: add rilmodem test engine
Add rilmodem test engine. This engine is an improvement on the rilmodem
test server that allows us to test generic interactions with the
rilmodem driver. Instead of just be able to check content of received/
sent bytes on the rild socket, we can now specify a set of steps for a
test that include interactions with the atom. The step types are

- TST_ACTION_SEND: The harness sends a parcel
- TST_ACTION_CALL: The harness calls a driver function
- TST_EVENT_RECEIVE: The driver sends a parcel
- TST_EVENT_CALL: The driver calls a harness (atom) function
2017-01-05 11:20:08 +03:00
Slava Monich
2054ca9570 include: Remove unused field from primary_context 2017-01-05 11:20:08 +03:00
Denis Kenzior
48dbb7912a AUTHORS: Mention Antoine's contributions 2017-01-05 11:20:08 +03:00
Denis Kenzior
d7e7ad671d gatchat: Fix style 2017-01-05 11:20:08 +03:00
Antoine Aubert
5b5a86dc80 gatmux: fix read channel remove on error
In case of invalid IO, read_watch is not reset. This fix crash on
destroy gatmux.
2017-01-05 11:20:08 +03:00
Slava Monich
c232524e99 main: Make -d option repeatable
Concatenating the patterns makes more sense than using the last
supplied value and leaking the previous allocated patterns.
2017-01-05 11:20:08 +03:00
Frédéric Dalleau
bfd09a5c14 udevng: Detect huawei E3372 modem and pcui
When the modes are modified with AT^SETPORT="FF;12,1,16", this modem
and pcui will appear using different ids. Update the interfaces
identifier accordingly.
2017-01-05 11:20:08 +03:00
Frédéric Dalleau
f8adcd2550 udevng: Detect huawei E3372 pcui
The huawei E3372 exposes two USB tty at /dev/ttyUSB0 and /dev/ttyUSB1
/dev/ttyUSB1 is properly detected as modem.
/dev/ttyUSB0 is the pcui.

lsusb shows 12d1:1506 Huawei Technologies Co., Ltd. Modem/Networkcard
2017-01-05 11:20:08 +03:00
Denis Kenzior
2a97567147 handsfree-audio: Fix crash
For HFP 1.5 devices the driver is always set to NULL.  So if the AG
establishes the SCO connection first, we might crash.
2017-01-05 11:20:07 +03:00
Santtu Lakkala
04d84b615e huaweimodem: Fix DHCP parsing on 32-bit platforms
strtol clamps returned value between INT_MIN and INT_MAX, causing
invalid value (255.255.255.127) being reported for any address
if last octet > 127 when sizeof(long) == 4.
2017-01-05 11:20:07 +03:00
Samrat Guha Niyogi
6e34792323 sim: remove locked_pin reset from sim_free_main_state 2017-01-05 11:20:07 +03:00
Samrat Guha Niyogi
d6a59f5dc4 rilmodem: fix cbd init in ril_query_facility_lock 2017-01-05 11:20:07 +03:00
Samrat Guha Niyogi
23e299055f rilmodem: fix num_params in query_facility_lock_cb 2017-01-05 11:20:07 +03:00
Denis Kenzior
a56ef3ba0f rilmodem: Co-locate the callback with invocation 2017-01-05 11:20:07 +03:00
Denis Kenzior
7294433906 rilmodem: Co-locate the callback with invocation 2017-01-05 11:20:07 +03:00
Samrat Guha Niyogi
d7263cd344 rilmodem: split ril_pin_change_state_cb
split ril_pin_change_state_cb based on functionality w.r.t.
facility lock, puk and pin. Rename ril_pin_change_state to
more appropriate name ril_set_facility_lock and rename
ril_pin_change_state_cb to ril_enter_sim_pin_cb.
2017-01-05 11:20:07 +03:00
Samrat Guha Niyogi
2f3b469fbb rilmodem: Remove unneeded pin sending logic 2017-01-05 11:20:07 +03:00
Denis Kenzior
4187e7ee8f sim: Fix style 2017-01-05 11:20:07 +03:00
Samrat Guha Niyogi
4d3f89bae0 sim: query facility during initialization in chain manner
query facility during initialization is modified from back
to back invocation to chain manner to keep it inline with
RIL design. All vendor RIL does not support back to back
handling since RIL telephony framework sends the request
synchronously.
2017-01-05 11:20:07 +03:00
Denis Kenzior
cbd1c5d524 sim: return false for SIM_PASSWORD_NONE 2017-01-05 11:20:07 +03:00
Ankit Navik
7976e44746 ril_sofia3gr: use vendor modem power down command 2017-01-05 11:20:07 +03:00
Denis Kenzior
3d6e220686 test: Add cancel-sms script 2017-01-05 11:20:07 +03:00
Denis Kenzior
919526d392 test: Fix permissions 2017-01-05 11:20:07 +03:00
Anirudh Gargi
b7082146e8 gril: Fix print macros to use latest print_buf 2017-01-05 11:20:07 +03:00
Denis Kenzior
094a296a14 AUTHORS: Mention Rajagopal's contributions 2017-01-05 11:20:07 +03:00
Rajagopal Aravindan
5c259e751b test: Added test to disable sofia 3gr tx throttling 2017-01-05 11:20:07 +03:00
Rajagopal Aravindan
69e5d5b356 test: Added test to enable sofia 3gr tx throttling 2017-01-05 11:20:07 +03:00
Rajagopal Aravindan
56e7d0e8ea ril_sofia3gr: Add transmit power throttling
Added 'sofia3gr.ThermalManagement' interface to sofia3gr plugin and
floated 'TransmitPowerThrottling' as an ofono property under that,
to support modem throttling.

'sofia3gr.ThermalManagement'
    1.Will be available ONLY if modem throttling is supported in RIL.
      This is determined by sending a RIL request during ofono start,
      to get current throttling state. If it succeeds, interface is
      published otherwise not.

'TransmitPowerThrottling'
    1.GetProperties will be allowed both when modem is ON & OFF.
    2.GetProperties will be serviced by looking it up from state
      information maintained inside ofono. No RIL call will be made.
    3.SetProperty will be allowed ONLY when modem is ON.
    4.SetProperty request will be forwarded to RIL ONLY if
      new state != current state. If RIL request succeeds, state
      information will be updated and also, a property change signal
      will be emitted.
2017-01-05 11:20:07 +03:00
Nishanth V
bb2ae6d1a1 rilmodem: fix WCDMA only in query rat mode 2017-01-05 11:20:07 +03:00
Caiwen Zhang
cf7692db49 plugins/ril: enable cbs 2017-01-05 11:20:07 +03:00
Caiwen Zhang
63f3311cd6 rilmodem: add cell broadcast message support 2017-01-05 11:20:07 +03:00
Samrat Guha Niyogi
c5aae77d41 ril_sofia3gr: Return -EINPROGRESS on disable() 2017-01-05 11:20:07 +03:00
Denis Kenzior
f8e21c8ad4 AUTHORS: Mention Suman's contributions 2017-01-05 11:20:07 +03:00
Suman Mallela
8e6dfe433b rilmodem: Fix PIN retries logic
The SIM PIN retries were not getting reset when the correct PIN/PUK
was entered.
2017-01-05 11:20:07 +03:00
Caiwen Zhang
ae23bb552b gril: avoid glib runtime warning
gril may be destroyed in the request callback (e.g in the callback of
set modem power off request). 'out_queue' and 'command_queue' is NULL.
there will be glib runtime warning if use them.
2017-01-05 11:20:06 +03:00
Caiwen Zhang
2becd051d4 plugins/ril: complete modem power off process 2017-01-05 11:20:06 +03:00
Slava Monich
8cfb1d5ca3 Merge branch 'cbs' into 'master'
Enable Cell Broadcast support

It was totally broken. 

See merge request !100
2017-01-05 08:15:45 +00:00
Slava Monich
50f35458f6 Merge branch 'rat' into 'master'
Preferred network mode, more corner cases

See merge request !99
2017-01-05 08:14:43 +00:00
Slava Monich
51843accf7 [ril] Enable Cell Broadcast support. Fixes MER#1729 2017-01-04 20:34:54 +03:00
Slava Monich
fb856dc7d6 [ril] Preferred network mode, more corner cases. Contributes to JB#36683
Prevents repeated rat mode setting failures when data SIM is not selected.
2017-01-04 16:05:11 +03:00
Slava Monich
1482748183 Merge branch 'silent-retry' into 'master'
Retry data call more than once

See merge request !98
2016-12-10 18:16:16 +00:00
Slava Monich
869ffda61e [ofono] Retry data call more than once. Contributes to JB#35406
Sometimes one retry is not enough, we need to allow more.
The first retry occurs immediately, then short delays are
applied. The delays and the number of retries are configurable.
The default is 4 retries and 200 ms delay before each retry
(except for the first one).

That should reduce the number of "Problem with connection" banners
thrown into the user's face.
2016-12-09 18:32:46 +02:00
Slava Monich
f875cbfda2 [ril] A few debug log changes 2016-12-08 18:20:43 +02:00
Slava Monich
2a60eaa6e3 Merge branch 'radiosetting' into 'master'
Fix the problem with radio settings saved to the wrong place

After the baseline was upgraded to 1.18, ofono core started saving
its radio settings to a file, and in order to save it to the right
place, the radio settings module needs to know the IMSI. So we have
to make sure that IMSI is available when we register the radio
settings atom.

See merge request !97
2016-11-25 13:41:02 +00:00
Slava Monich
29b6c41d48 [ril] Register ofono radio settings only when IMSI is available. Fixes MER#1708
Otherwise its radiosetting files gets written directly to /var/lib/ofono
instead of the SIM specific subdirectory.
2016-11-25 01:57:19 +02:00
Slava Monich
2f6491d005 [ril] Reset imsi in ril_sim_settings to NULL when SIM is removed. 2016-11-25 01:56:33 +02:00
Slava Monich
1a25047e9d Merge branch 'jb36957' into 'master'
Fix receiving UTF-16 encoded messages with split 4-byte char.

See merge request !96
2016-11-18 16:58:17 +00:00
Martin Jones
899e14bf17 [ofono] Fix receiving UTF-16 encoded messages with split 4-byte char. Fixes JB#36957
The spec supports UCS2, but in reality UTF-16 is used, which supports
4-byte characters, which could be split into different message
fragments. Accumulate the entire UTF-16 message before converting to
UTF8.
2016-11-18 14:06:57 +02:00
Slava Monich
2520664c63 Merge branch 'gprs-picks' into 'master'
Couple of upstream picks

One of those eliminates a possible root cause of mobile data
becoming disabled under certain (fairly rare) circumstances.

See merge request !95
2016-11-07 09:43:04 +00:00
Slava Monich
445bbbd66f gprs: Check GPRS_FLAG_ATTACHED_UPDATE
... in pri_deactivate_callback

This prevents attached state from getting stuck at 0 like this:

1. Context deactivation is initiated over D-Bus, ctx->pending is set
2. Attached becomes FALSE, context is still marked as active
3. Attached becomes TRUE, gprs_attached_update sets GPRS_FLAG_ATTACHED_UPDATE
4. Deactivation completes, attached is 0, driver_attached is 1

Futher network status updates don't call gprs_attached_update because
driver_attached is still 1, so attached is staying 0 until we lose the
data registration again which may not happen for quite a long time.
2016-11-04 12:14:48 +03:00
Caiwen Zhang
08fc4b0d03 gprs: fix crash removing a context being activated
If remove the context before context activation is completed, it may
cause a crash.
2016-11-04 12:14:18 +03:00
Slava Monich
c82e94ffb4 Merge branch 'cancel' into 'master'
Make sure that data request completion callback is always called on cancel

See merge request !94
2016-10-31 16:12:52 +00:00
Slava Monich
fd3712940b [ril] Make sure data request completion callback is called on cancel. Contributes to JB#33640
Completion callback wasn't invoked if the data request was cancelled
before it was actually submitted to RIL.
2016-10-28 15:46:06 +03:00
Slava Monich
8410c985c9 Merge branch 'nitz' into 'master'
Handle NITZ information coming before MCC/MNC

See merge request !93
2016-10-27 09:26:05 +00:00
Slava Monich
0878decdc0 Merge branch 'prefmode' into 'master'
Preferred network mode, corner cases

See merge request !92
2016-10-27 09:25:18 +00:00
Slava Monich
cb69984722 [ril] Preferred network mode, corner cases. Fixes JB#36683
Really make sure that we don't try to set preferred network mode to LTE
for more than one slot at a time.
2016-10-26 17:30:01 +03:00
Slava Monich
1fe8701f1a [nettime] Handle NITZ information coming before MCC/MNC. Fixes MER#1680
Due to the order in which events are delivered and network registration
information requiring one extra query, NITZ information may be delivered
to ofono before MCC/MNC are known.
2016-10-26 16:56:30 +03:00
Slava Monich
c5286fee70 Merge branch 'rat' into 'master'
Check network mode after ril_data is created

Not sure if it completely fixes the issue but it could cause
repeating SET_PREFERRED_NETWORK_TYPE failures.

See merge request !91
2016-10-23 21:04:29 +00:00
Slava Monich
3c5f6f84e1 Merge branch 'data_calls' into 'master'
Make data call format configurable

Different RILs use different data call structures which don't
necessarily match the format specified in the data list header.
The header may have version 9 but the list may contain 
RIL_Data_Call_Response_v6` structures, list version 10 may
contain RIL_Data_Call_Response_v11 and so on. By default ofono
assumes that the version from the list header matches the contents
but sometimes you have to explicitly tell ofono which one to use.

Possible values are 6, 9, 11 and auto.

See merge request !90
2016-10-23 21:03:52 +00:00
Slava Monich
8b87b55e8d [ril] Check network mode after ril_data is created. Contributes to JB#36683 2016-10-20 14:41:29 +03:00
Slava Monich
bce34cbff3 [ril] Housekeeping
Removed unnecessary forward declaration
2016-10-20 14:38:04 +03:00
Slava Monich
f8351cacf1 [ril] Made data call format configurable. Contributes to MER#1679
This commit adds dataCallFormat configuration option to
ril_subscriptuion.conf which allows to select which data
call format to use. There are quite a few rils where version
provided in the data call list header doesn't match the contents.
2016-10-19 12:30:13 +03:00
69 changed files with 6006 additions and 1570 deletions

1
ofono/.gitignore vendored
View File

@@ -44,6 +44,7 @@ unit/test-stkutil
unit/test-cdmasms
unit/test-rilmodem-cb
unit/test-rilmodem-cs
unit/test-rilmodem-gprs
unit/test-rilmodem-sms
unit/test-*.log
unit/test-*.trs

View File

@@ -113,3 +113,6 @@ Anirudh Gargi <anirudh.gargi@intel.com>
Nishanth V <nishanth.v@intel.com>
Antara Borwankar <antara.borwankar@gmail.com>
Martin Chaplet <m.chaplet@kerlink.fr>
Suman Mallela <suman.m@intel.com>
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
Antoine Aubert <a.aubert@overkiz.com>

View File

@@ -1,3 +1,13 @@
ver 1.19:
Fix issue with DHCP parsing and Huawei modems.
Fix issue with detecting Huawei E3372 modem.
Fix issue with handling serving cell info.
Fix issue with handling SIM SC facility lock.
Fix issue with Android RIL PIN retry logic.
Fix issue with Android RIL and RAT handling.
Add support for Android RIL cell broadcast.
Add support for SoFIA 3GR thermal management.
ver 1.18:
Fix issue with cell broadcast and use-after-fee.
Fix issue with repeated held call indicator.

View File

@@ -117,7 +117,7 @@ builtin_sources += plugins/udevng.c
endif
if RILMODEM
if JOLLA_RILMODEM
if SAILFISH_RILMODEM
builtin_modules += ril
builtin_sources += drivers/ril/ril_call_barring.c \
@@ -143,6 +143,7 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_plugin.c \
drivers/ril/ril_plugin_dbus.c \
drivers/ril/ril_radio.c \
drivers/ril/ril_radio_caps.c \
drivers/ril/ril_radio_settings.c \
drivers/ril/ril_sim.c \
drivers/ril/ril_sim_card.c \
@@ -197,6 +198,7 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
drivers/rilmodem/call-barring.c \
drivers/rilmodem/netmon.c \
drivers/rilmodem/stk.c \
drivers/rilmodem/cbs.c \
drivers/infineonmodem/infineon_constants.h
endif
endif
@@ -574,6 +576,11 @@ builtin_sources += plugins/bluez5.c plugins/bluez5.h
builtin_modules += hfp_ag_bluez5
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
if SAILFISH_BT
builtin_modules += sfos_bt
builtin_sources += plugins/sailfish_bt.c
endif
endif
if UPOWER
@@ -587,11 +594,25 @@ builtin_modules += nettime
builtin_sources += plugins/nettime.c
endif
if SAILFISH_DEBUGLOG
builtin_modules += debuglog
builtin_sources += plugins/sailfish_debuglog.c
endif
if SAILFISH_PROVISION
builtin_sources += plugins/sailfish_provision.c
PROVISION = 1
else
if PROVISION
builtin_sources += plugins/provision.c
endif
endif
if PROVISION
builtin_sources += plugins/mbpi.h plugins/mbpi.c
builtin_modules += provision
builtin_sources += plugins/provision.h plugins/provision.c
builtin_sources += plugins/provision.h
builtin_modules += cdma_provision
builtin_sources += plugins/cdma-provision.c
@@ -629,18 +650,13 @@ builtin_sources += plugins/smart-messaging.c
builtin_modules += push_notification
builtin_sources += plugins/push-notification.c
if PUSHFORWARDER
builtin_modules += push_forwarder
builtin_sources += plugins/push-forwarder.c
if SAILFISH_PUSHFORWARDER
builtin_modules += pushforwarder
builtin_sources += plugins/sailfish_pushforwarder.c
builtin_cflags += @WSPCODEC_CFLAGS@
builtin_libadd += @WSPCODEC_LIBS@
endif
if DEBUGLOG
builtin_modules += debuglog
builtin_sources += plugins/debuglog.c
endif
builtin_modules += sms_history
builtin_sources += plugins/smshistory.c
@@ -758,6 +774,7 @@ test_scripts = test/backtrace \
test/receive-sms \
test/remove-contexts \
test/send-sms \
test/cancel-sms \
test/set-mic-volume \
test/set-speaker-volume \
test/test-stk-menu \
@@ -828,7 +845,9 @@ test_scripts = test/backtrace \
test/set-sms-smsc \
test/set-sms-bearer \
test/get-serving-cell-info \
test/list-allowed-access-points
test/list-allowed-access-points \
test/enable-throttling \
test/disable-throttling
if TEST
testdir = $(pkglibdir)/test
@@ -849,12 +868,13 @@ unit_tests = unit/test-common unit/test-util unit/test-idmap \
unit/test-provision
if RILMODEM
if JOLLA_RILMODEM
if SAILFISH_RILMODEM
unit_tests += unit/test-rilmodem-cs \
unit/test-rilmodem-cs \
unit/test-rilmodem-sms \
unit/test-rilmodem-cb
unit/test-rilmodem-cb \
unit/test-rilmodem-gprs
endif
endif
@@ -910,20 +930,20 @@ unit_test_caif_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_caif_OBJECTS)
unit_test_provision_SOURCES = unit/test-provision.c \
plugins/provision.h plugins/provision.c \
plugins/mbpi.c src/gprs-provision.c \
src/log.c
plugins/provision.h plugins/mbpi.c \
plugins/sailfish_provision.c \
src/gprs-provision.c src/log.c
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_provision_OBJECTS)
if RILMODEM
if JOLLA_RILMODEM
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
gatchat/ringbuffer.h gatchat/ringbuffer.c \
unit/rilmodem-test-server.h \
unit/rilmodem-test-server.c \
src/simutil.c
unit/rilmodem-test-engine.h \
unit/rilmodem-test-engine.c \
src/simutil.c \
drivers/rilmodem/rilutil.c
unit_test_rilmodem_cs_SOURCES = $(test_rilmodem_sources) \
unit/test-rilmodem-cs.c \
@@ -946,8 +966,12 @@ unit_test_rilmodem_cb_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
unit_objects += $(unit_test_rilmodem_cb_OBJECTS)
endif
endif
unit_test_rilmodem_gprs_SOURCES = $(test_rilmodem_sources) \
unit/test-rilmodem-gprs.c \
drivers/rilmodem/gprs.c
unit_test_rilmodem_gprs_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
unit_objects += $(unit_test_rilmodem_gprs_OBJECTS)
TESTS = $(unit_tests)

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(ofono, 1.18)
AC_INIT(ofono, 1.19)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)
@@ -167,22 +167,30 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
[enable_rilmodem=${enableval}])
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
AC_ARG_ENABLE(jolla-rilmodem,
AC_HELP_STRING([--enable-jolla-rilmodem], [enable Jolla RIL modem]),
[enable_jolla_rilmodem=${enableval}], [enable_jolla_rilmodem="no"])
AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_rilmodem}" != "no")
AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
[enable Sailfish RIL modem]),
[enable_sailfish_rilmodem=${enableval}],
[enable_sailfish_rilmodem="no"])
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
if (test "${enable_jolla_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.6, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.6 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.5, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.5 is required))
if (test "${enable_sailfish_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.14, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.14 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
PKG_CHECK_MODULES(LIBMCE, libmce-glib, dummy=yes,
AC_MSG_ERROR(libmce-glib is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS $LIBMCE_CFLAGS"
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS $LIBMCE_LIBS"
fi
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
[don't allow to add or remove connection context over D-Bus]), [
if (test "${enableval}" = "no"); then
CFLAGS="$CFLAGS -DDISABLE_ADD_REMOVE_CONTEXT"
fi
])
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
[disable Qualcomm QMI modem support]),
[enable_qmimodem=${enableval}])
@@ -206,6 +214,16 @@ fi
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
AC_ARG_ENABLE(sailfish-bt, AC_HELP_STRING([--enable-sailfish-bt],
[enable Sailfish OS Bluetooth plugin]),
[enable_sailfish_bt=${enableval}])
AM_CONDITIONAL(SAILFISH_BT, test "${enable_sailfish_bt}" = "yes")
AC_ARG_ENABLE(sailfish-provision, AC_HELP_STRING([--enable-sailfish-provision],
[enable Sailfish OS provisioning plugin]),
[enable_sailfish_provision=${enableval}])
AM_CONDITIONAL(SAILFISH_PROVISION, test "${enable_sailfish_provision=$}" = "yes")
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
[disable Nettime plugin]),
[enable_nettime=${enableval}])
@@ -248,22 +266,24 @@ AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
[enable_datafiles=${enableval}])
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
AC_ARG_ENABLE(pushforwarder, AC_HELP_STRING([--disable-pushforwarder],
[disable Push Forwarder plugin]),
[enable_pushforwarder=${enableval}])
AM_CONDITIONAL(PUSHFORWARDER, test "${enable_pushforwarder}" != "no")
if (test "${enable_pushforwarder}" != "no"); then
AC_ARG_ENABLE(sailfish-pushforwarder, AC_HELP_STRING([--enable-sailfish-pushforwarder],
[enable Sailfish OS push forwarder plugin]),
[enable_sailfish_pushforwarder=${enableval}],
[enable_sailfish_pushforwarder="no"])
AM_CONDITIONAL(SAILFISH_PUSHFORWARDER, test "${enable_sailfish_pushforwarder}" != "no")
if (test "${enable_sailfish_pushforwarder}" != "no"); then
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
AC_MSG_ERROR(WSP decoder is required))
AC_SUBST(WSPCODEC_CFLAGS)
AC_SUBST(WSPCODEC_LIBS)
fi
AC_ARG_ENABLE(debuglog,
AC_HELP_STRING([--enable-debuglog], [enable log control plugin]),
[enable_debuglog=${enableval}], [enable_debuglog="no"])
AM_CONDITIONAL(DEBUGLOG, test "${enable_debuglog}" != "no")
if (test "${enable_debuglog}" = "yes"); then
AC_ARG_ENABLE(sailfish-debuglog, AC_HELP_STRING([--enable-sailfish-debuglog],
[enable Sailfish OS debug log plugin]),
[enable_sailfish_debuglog=${enableval}],
[enable_sailfish_debuglog="no"])
AM_CONDITIONAL(SAILFISH_DEBUGLOG, test "${enable_sailfish_debuglog}" != "no")
if (test "${enable_sailfish_debuglog}" = "yes"); then
PKG_CHECK_MODULES(DBUSLOG, libdbuslogserver-dbus, dummy=yes,
AC_MSG_ERROR(libdbuslogserver-dbus is required))
CFLAGS="$CFLAGS $DBUSLOG_CFLAGS"

View File

@@ -80,7 +80,7 @@ static gboolean get_next_addr(GAtResultIter *iter, char **addr)
if (g_at_result_iter_next_unquoted_string(iter, &str) == FALSE)
return FALSE;
val = strtol(str, NULL, 16);
val = strtoul(str, NULL, 16);
if (addr)
*addr = g_strdup_printf("%u.%u.%u.%u",

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,60 +16,155 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include <gutil_strv.h>
struct ril_cbs {
struct ofono_cbs *cbs;
GRilIoChannel *io;
guint timer_id;
GRilIoQueue *q;
char *log_prefix;
gulong event_id;
};
static void ril_set_topics(struct ofono_cbs *cbs, const char *topics,
ofono_cbs_set_cb_t cb, void *data)
struct ril_cbs_cbd {
struct ril_cbs *cd;
ofono_cbs_set_cb_t cb;
gpointer data;
};
#define RIL_CBS_CHECK_RETRY_MS 1000
#define RIL_CBS_CHECK_RETRY_COUNT 30
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
#define ril_cbs_cbd_free g_free
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
ofono_cbs_set_cb_t cb, void *data)
{
struct ofono_error error;
cb(ril_error_ok(&error), data);
struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
cbd->cd = cd;
cbd->cb = cb;
cbd->data = data;
return cbd;
}
static void ril_clear_topics(struct ofono_cbs *cbs,
static void ril_cbs_request_activation(struct ril_cbs *cd,
gboolean activate, GRilIoChannelResponseFunc response,
GDestroyNotify destroy, void* user_data)
{
GRilIoRequest* req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, activate ? 0 :1);
DBG_(cd, "%sactivating CB", activate ? "" : "de");
grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
response, destroy, user_data);
grilio_request_unref(req);
}
static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
GRilIoChannelResponseFunc response,
GDestroyNotify destroy, void* user_data)
{
char **list = topics ? g_strsplit(topics, ",", 0) : NULL;
int i, n = gutil_strv_length(list);
GRilIoRequest* req = grilio_request_new();
grilio_request_append_int32(req, n);
for (i = 0; i < n; i++) {
const char *entry = list[i];
const char *delim = strchr(entry, '-');
int from, to;
if (delim) {
char **range = g_strsplit(topics, "-", 0);
from = atoi(range[0]);
to = atoi(range[1]);
g_strfreev(range);
} else {
from = to = atoi(entry);
}
grilio_request_append_int32(req, from);
grilio_request_append_int32(req, to);
grilio_request_append_int32(req, 0);
grilio_request_append_int32(req, 0xff);
grilio_request_append_int32(req, 1);
}
DBG_(cd, "configuring CB");
grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
response, destroy, user_data);
grilio_request_unref(req);
g_strfreev(list);
}
static void ril_cbs_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_cbs_cbd *cbd = user_data;
if (cbd->cb) {
struct ofono_error error;
if (ril_status == RIL_E_SUCCESS) {
cbd->cb(ril_error_ok(&error), cbd->data);
} else {
cbd->cb(ril_error_failure(&error), cbd->data);
}
}
}
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
ofono_cbs_set_cb_t cb, void *data)
{
struct ofono_error error;
cb(ril_error_ok(&error), data);
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
DBG_(cd, "%s", topics);
ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
ril_cbs_cbd_new(cd, cb, data));
}
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
ofono_cbs_set_cb_t cb, void *data)
{
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
DBG_(cd, "");
ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
ril_cbs_cbd_new(cd, cb, data));
}
static void ril_cbs_notify(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_cbs *cd = user_data;
GRilIoParser rilp;
char* pdu;
GASSERT(code == RIL_UNSOL_ON_USSD);
grilio_parser_init(&rilp, data, len);
pdu = grilio_parser_get_utf8(&rilp);
DBG("%s", pdu);
if (pdu) {
ofono_cbs_notify(cd->cbs, (const guchar *)pdu, strlen(pdu));
g_free(pdu);
}
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
DBG_(cd, "%u bytes", len);
ofono_cbs_notify(cd->cbs, data, len);
}
static gboolean ril_cbs_register(gpointer user_data)
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_cbs *cd = user_data;
DBG("");
GASSERT(cd->timer_id);
cd->timer_id = 0;
ofono_cbs_register(cd->cbs);
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
/* Single-shot */
return FALSE;
if (status == RIL_E_SUCCESS) {
DBG_(cd, "registering for CB");
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
cd);
ofono_cbs_register(cd->cbs);
} else {
DBG_(cd, "failed to query CB config");
ofono_cbs_remove(cd->cbs);
}
}
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
@@ -77,12 +172,27 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
{
struct ril_modem *modem = data;
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
GRilIoRequest* req = grilio_request_new();
DBG("");
cd->cbs = cbs;
cd->io = grilio_channel_ref(ril_modem_io(modem));
cd->timer_id = g_idle_add(ril_cbs_register, cd);
ofono_cbs_set_data(cbs, cd);
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
cd->cbs = cbs;
DBG_(cd, "");
cd->io = grilio_channel_ref(ril_modem_io(modem));
cd->q = grilio_queue_new(cd->io);
/*
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup.
* We may have to retry a few times.
*/
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
RIL_CBS_CHECK_RETRY_COUNT);
grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
ril_cbs_probe_done_cb, NULL, cd);
grilio_request_unref(req);
return 0;
}
@@ -90,15 +200,13 @@ static void ril_cbs_remove(struct ofono_cbs *cbs)
{
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
DBG("");
DBG_(cd, "");
ofono_cbs_set_data(cbs, NULL);
if (cd->timer_id > 0) {
g_source_remove(cd->timer_id);
}
grilio_channel_remove_handler(cd->io, cd->event_id);
grilio_channel_unref(cd->io);
grilio_queue_cancel_all(cd->q, FALSE);
grilio_queue_unref(cd->q);
g_free(cd->log_prefix);
g_free(cd);
}
@@ -106,8 +214,8 @@ const struct ofono_cbs_driver ril_cbs_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_cbs_probe,
.remove = ril_cbs_remove,
.set_topics = ril_set_topics,
.clear_topics = ril_clear_topics
.set_topics = ril_cbs_set_topics,
.clear_topics = ril_cbs_clear_topics
};
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,10 +14,14 @@
*/
#include "ril_config.h"
#include "ril_log.h"
#include <gutil_intarray.h>
#include <gutil_ints.h>
/* Utilities for parsing ril_subscription.conf */
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
{
char *val = g_key_file_get_string(file, group, key, NULL);
@@ -29,6 +33,31 @@ char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
return val;
}
char **ril_config_get_strings(GKeyFile *file, const char *group,
const char *key, char delimiter)
{
char *str = ril_config_get_string(file, group, key);
if (str) {
char **strv, **p;
char delimiter_str[2];
delimiter_str[0] = delimiter;
delimiter_str[1] = 0;
strv = g_strsplit(str, delimiter_str, -1);
/* Strip whitespaces */
for (p = strv; *p; p++) {
*p = g_strstrip(*p);
}
g_free(str);
return strv;
}
return NULL;
}
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
const char *key, int *out_value)
{
@@ -106,6 +135,95 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
}
}
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...)
{
char *str = ril_config_get_string(file, group, key);
if (str) {
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(str, '#');
if (comment) *comment = 0;
g_strstrip(str);
if (strcasecmp(str, name)) {
va_list args;
va_start(args, value);
while ((name = va_arg(args, char*)) != NULL) {
value = va_arg(args, int);
if (!strcasecmp(str, name)) {
break;
}
}
va_end(args);
}
if (!name) {
ofono_error("Invalid %s config value (%s)", key, str);
}
g_free(str);
if (name) {
if (result) {
*result = value;
}
return TRUE;
}
}
return FALSE;
}
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key)
{
char *value = ril_config_get_string(file, group, key);
if (value) {
char **values = g_strsplit(value, ",", -1);
char **ptr = values;
GUtilIntArray *array = gutil_int_array_new();
while (*ptr) {
const char *str = *ptr++;
char *end = NULL;
long ival = strtol(str, &end, 0);
if (str[0] && !end[0]) {
gutil_int_array_append(array, ival);
}
}
g_free(value);
g_strfreev(values);
return gutil_int_array_free_to_ints(array);
}
return NULL;
}
char *ril_config_ints_to_string(GUtilInts *ints, char separator)
{
if (ints) {
guint i, n;
const int *data = gutil_ints_get_data(ints, &n);
GString *buf = g_string_new(NULL);
for (i=0; i<n; i++) {
if (buf->len > 0) {
g_string_append_c(buf, separator);
}
g_string_append_printf(buf, "%d", data[i]);
}
return g_string_free(buf, FALSE);
}
return NULL;
}
/*
* Local Variables:
* mode: C

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,13 +22,22 @@
#define RILCONF_SETTINGS_GROUP "Settings"
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key);
char *ril_config_get_string(GKeyFile *file, const char *group,
const char *key);
char **ril_config_get_strings(GKeyFile *file, const char *group,
const char *key, char delimiter);
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
const char *key, int *value);
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
const char *key, gboolean *value);
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
const char *key, int flag, int *flags);
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...);
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key);
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
#endif /* RIL_CONFIG_H */

View File

@@ -1,11 +1,10 @@
/*
*
* RIL constants adopted from AOSP's header:
*
* /hardware/ril/reference_ril/ril.h
*
* Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2013-2016 Jolla Ltd.
* Copyright (C) 2013-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,37 +19,70 @@
#ifndef __RIL_CONSTANTS_H
#define __RIL_CONSTANTS_H 1
#define RIL_MAX_UUID_LENGTH 64
/* Error Codes */
#define RIL_E_SUCCESS 0
#define RIL_E_RADIO_NOT_AVAILABLE 1
#define RIL_E_GENERIC_FAILURE 2
#define RIL_E_PASSWORD_INCORRECT 3
#define RIL_E_SIM_PIN2 4
#define RIL_E_SIM_PUK2 5
#define RIL_E_REQUEST_NOT_SUPPORTED 6
#define RIL_E_CANCELLED 7
#define RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL 8
#define RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW 9
#define RIL_E_SMS_SEND_FAIL_RETRY 10
#define RIL_E_SIM_ABSENT 11
#define RIL_E_SUBSCRIPTION_NOT_AVAILABLE 12
#define RIL_E_MODE_NOT_SUPPORTED 13
#define RIL_E_FDN_CHECK_FAILURE 14
#define RIL_E_ILLEGAL_SIM_OR_ME 15
#define RIL_E_UNUSED 16
#define RIL_E_DIAL_MODIFIED_TO_USSD 17
#define RIL_E_DIAL_MODIFIED_TO_SS 18
#define RIL_E_DIAL_MODIFIED_TO_DIAL 19
#define RIL_E_USSD_MODIFIED_TO_DIAL 20
#define RIL_E_USSD_MODIFIED_TO_SS 21
#define RIL_E_USSD_MODIFIED_TO_USSD 22
#define RIL_E_SS_MODIFIED_TO_DIAL 23
#define RIL_E_SS_MODIFIED_TO_USSD 24
#define RIL_E_SS_MODIFIED_TO_SS 25
#define RIL_E_SUBSCRIPTION_NOT_SUPPORTED 26
#define RIL_E_MISSING_RESOURCE 27
#define RIL_E_NO_SUCH_ELEMENT 28
#define RIL_E_INVALID_PARAMETER 29
enum ril_status {
RIL_E_SUCCESS = 0,
RIL_E_RADIO_NOT_AVAILABLE = 1,
RIL_E_GENERIC_FAILURE = 2,
RIL_E_PASSWORD_INCORRECT = 3,
RIL_E_SIM_PIN2 = 4,
RIL_E_SIM_PUK2 = 5,
RIL_E_REQUEST_NOT_SUPPORTED = 6,
RIL_E_CANCELLED = 7,
RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
RIL_E_SMS_SEND_FAIL_RETRY = 10,
RIL_E_SIM_ABSENT = 11,
RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
RIL_E_MODE_NOT_SUPPORTED = 13,
RIL_E_FDN_CHECK_FAILURE = 14,
RIL_E_ILLEGAL_SIM_OR_ME = 15,
RIL_E_MISSING_RESOURCE = 16,
RIL_E_NO_SUCH_ELEMENT = 17,
RIL_E_DIAL_MODIFIED_TO_USSD = 18,
RIL_E_DIAL_MODIFIED_TO_SS = 19,
RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
RIL_E_USSD_MODIFIED_TO_DIAL = 21,
RIL_E_USSD_MODIFIED_TO_SS = 22,
RIL_E_USSD_MODIFIED_TO_USSD = 23,
RIL_E_SS_MODIFIED_TO_DIAL = 24,
RIL_E_SS_MODIFIED_TO_USSD = 25,
RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
RIL_E_SS_MODIFIED_TO_SS = 27,
RIL_E_LCE_NOT_SUPPORTED = 36,
RIL_E_NO_MEMORY = 37,
RIL_E_INTERNAL_ERR = 38,
RIL_E_SYSTEM_ERR = 39,
RIL_E_MODEM_ERR = 40,
RIL_E_INVALID_STATE = 41,
RIL_E_NO_RESOURCES = 42,
RIL_E_SIM_ERR = 43,
RIL_E_INVALID_ARGUMENTS = 44,
RIL_E_INVALID_SIM_STATE = 45,
RIL_E_INVALID_MODEM_STATE = 46,
RIL_E_INVALID_CALL_ID = 47,
RIL_E_NO_SMS_TO_ACK = 48,
RIL_E_NETWORK_ERR = 49,
RIL_E_REQUEST_RATE_LIMITED = 50,
RIL_E_SIM_BUSY = 51,
RIL_E_SIM_FULL = 52,
RIL_E_NETWORK_REJECT = 53,
RIL_E_OPERATION_NOT_ALLOWED = 54,
RIL_E_EMPTY_RECORD = 55,
RIL_E_INVALID_SMS_FORMAT = 56,
RIL_E_ENCODING_ERR = 57,
RIL_E_INVALID_SMSC_ADDRESS = 58,
RIL_E_NO_SUCH_ENTRY = 59,
RIL_E_NETWORK_NOT_READY = 60,
RIL_E_NOT_PROVISIONED = 61,
RIL_E_NO_SUBSCRIPTION = 62,
RIL_E_NO_NETWORK_FOUND = 63,
RIL_E_DEVICE_IN_USE = 64,
RIL_E_ABORTED = 65,
RIL_E_INVALID_RESPONSE = 66
};
/* call states */
enum ril_call_state {
@@ -114,49 +146,120 @@ enum ril_radio_tech {
RADIO_TECH_HSPAP = 15,
RADIO_TECH_GSM = 16,
RADIO_TECH_TD_SCDMA = 17,
RADIO_TECH_IWLAN = 18
RADIO_TECH_IWLAN = 18,
RADIO_TECH_LTE_CA = 19
};
/* Radio capabilities */
enum ril_radio_access_family {
RAF_GPRS = (1 << RADIO_TECH_GPRS),
RAF_EDGE = (1 << RADIO_TECH_EDGE),
RAF_UMTS = (1 << RADIO_TECH_UMTS),
RAF_IS95A = (1 << RADIO_TECH_IS95A),
RAF_IS95B = (1 << RADIO_TECH_IS95B),
RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
RAF_HSPA = (1 << RADIO_TECH_HSPA),
RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
RAF_LTE = (1 << RADIO_TECH_LTE),
RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
RAF_GSM = (1 << RADIO_TECH_GSM),
RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
};
enum ril_radio_capability_phase {
RC_PHASE_CONFIGURED = 0,
RC_PHASE_START = 1,
RC_PHASE_APPLY = 2,
RC_PHASE_UNSOL_RSP = 3,
RC_PHASE_FINISH = 4
};
enum ril_radio_capability_status {
RC_STATUS_NONE = 0,
RC_STATUS_SUCCESS = 1,
RC_STATUS_FAIL = 2
};
#define RIL_RADIO_CAPABILITY_VERSION 1
struct ril_radio_capability {
int version;
int session;
enum ril_radio_capability_phase phase;
enum ril_radio_access_family rat;
char logicalModemUuid[RIL_MAX_UUID_LENGTH];
int status;
};
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
#define CALL_FAIL_UNOBTAINABLE_NUMBER 1
#define CALL_FAIL_NORMAL 16
#define CALL_FAIL_BUSY 17
#define CALL_FAIL_CONGESTION 34
#define CALL_FAIL_ACM_LIMIT_EXCEEDED 68
#define CALL_FAIL_CALL_BARRED 240
#define CALL_FAIL_FDN_BLOCKED 241
#define CALL_FAIL_IMSI_UNKNOWN_IN_VLR 242
#define CALL_FAIL_IMEI_NOT_ACCEPTED 243
#define CALL_FAIL_DIAL_MODIFIED_TO_USSD 244
#define CALL_FAIL_DIAL_MODIFIED_TO_SS 245
#define CALL_FAIL_DIAL_MODIFIED_TO_DIAL 246
#define CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE 1000
#define CALL_FAIL_CDMA_DROP 1001
#define CALL_FAIL_CDMA_INTERCEPT 1002
#define CALL_FAIL_CDMA_REORDER 1003
#define CALL_FAIL_CDMA_SO_REJECT 1004
#define CALL_FAIL_CDMA_RETRY_ORDER 1005
#define CALL_FAIL_CDMA_ACCESS_FAILURE 1006
#define CALL_FAIL_CDMA_PREEMPTED 1007
#define CALL_FAIL_CDMA_NOT_EMERGENCY 1008
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
enum ril_call_fail_cause {
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
CALL_FAIL_NORMAL = 16,
CALL_FAIL_BUSY = 17,
CALL_FAIL_NO_USER_RESPONDING = 18,
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
CALL_FAIL_CALL_REJECTED = 21,
CALL_FAIL_NUMBER_CHANGED = 22,
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
CALL_FAIL_FACILITY_REJECTED = 29,
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
CALL_FAIL_CONGESTION = 34,
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
CALL_FAIL_TEMPORARY_FAILURE = 41,
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
CALL_FAIL_QOS_UNAVAILABLE = 49,
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
CALL_FAIL_CALL_BARRED = 240,
CALL_FAIL_FDN_BLOCKED = 241,
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
/* Not defined in ril.h but valid 3GPP specific cause values
* for call control. See 3GPP TS 24.008 Annex H. */
#define CALL_FAIL_NO_ROUTE_TO_DESTINATION 3
#define CALL_FAIL_CHANNEL_UNACCEPTABLE 6
#define CALL_FAIL_OPERATOR_DETERMINED_BARRING 8
#define CALL_FAIL_NO_USER_RESPONDING 18
#define CALL_FAIL_USER_ALERTING_NO_ANSWER 19
#define CALL_FAIL_CALL_REJECTED 21
#define CALL_FAIL_NUMBER_CHANGED 22
#define CALL_FAIL_ANONYMOUS_CALL_REJECTION 24
#define CALL_FAIL_PRE_EMPTION 25
#define CALL_FAIL_DESTINATION_OUT_OF_ORDER 27
#define CALL_FAIL_INCOMPLETE_NUMBER 28
#define CALL_FAIL_FACILITY_REJECTED 29
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
CALL_FAIL_PRE_EMPTION = 25
};
enum ril_data_call_fail_cause {
PDP_FAIL_NONE = 0,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -36,6 +36,7 @@
#define PROTO_IPV4V6_STR "IPV4V6"
enum ril_data_priv_flags {
RIL_DATA_FLAG_NONE = 0x00,
RIL_DATA_FLAG_ALLOWED = 0x01,
RIL_DATA_FLAG_MAX_SPEED = 0x02,
RIL_DATA_FLAG_ON = 0x04
@@ -99,7 +100,8 @@ struct ril_data_priv {
struct ril_data_request *req_queue;
struct ril_data_request *pending_req;
enum ril_data_allow_data_opt allow_data;
struct ril_data_options options;
guint slot;
char *log_prefix;
guint query_id;
gulong io_event_id;
@@ -159,7 +161,8 @@ struct ril_data_request_setup {
char *password;
enum ofono_gprs_proto proto;
enum ofono_gprs_auth_method auth_method;
int retry_count;
guint retry_count;
guint retry_delay_id;
};
struct ril_data_request_deact {
@@ -167,12 +170,11 @@ struct ril_data_request_deact {
int cid;
};
struct ril_data_request_2g {
struct ril_data_request_allow_data {
struct ril_data_request req;
gulong handler_id;
gboolean allow;
};
static gboolean ril_data_manager_handover(struct ril_data_manager *dm);
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);
@@ -272,7 +274,8 @@ static int ril_data_protocol_to_ofono(gchar *str)
return -1;
}
static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp)
static struct ril_data_call *ril_data_call_parse(int version,
GRilIoParser *rilp)
{
int prot;
char *prot_str;
@@ -280,6 +283,7 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
guint32 active = RIL_DATA_CALL_INACTIVE;
struct ril_data_call *call = g_new0(struct ril_data_call, 1);
/* RIL_Data_Call_Response_v6 (see ril.h) */
grilio_parser_get_uint32(rilp, &status);
grilio_parser_get_int32(rilp, &call->retry_time);
grilio_parser_get_int32(rilp, &call->cid);
@@ -299,15 +303,13 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
call->status = status;
call->active = active;
/* RIL_Data_Call_Response_v9 */
if (version >= 9) {
/* PCSCF */
grilio_parser_skip_string(rilp);
/*
* All known rils that report version 10 are using
* RIL_Data_Call_Response_v11 (FairPhone 2, Nexus 4)
*/
if (version >= 10) {
/* RIL_Data_Call_Response_v11 */
if (version >= 11) {
/* MTU */
grilio_parser_get_int32(rilp, &call->mtu);
}
@@ -317,7 +319,8 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
return call;
}
struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
guint len, enum ril_data_call_format format)
{
unsigned int version, n, i;
GRilIoParser rilp;
@@ -328,8 +331,13 @@ struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
struct ril_data_call_list *list =
g_new0(struct ril_data_call_list, 1);
DBG("version=%u,num=%u", version, n);
list->version = version;
if (format == RIL_DATA_CALL_FORMAT_AUTO || format == version) {
DBG("version=%u,num=%u", version, n);
list->version = version;
} else {
DBG("version=%u(%d),num=%u", version, format, n);
list->version = format;
}
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
struct ril_data_call *call =
@@ -499,7 +507,8 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
priv->query_id = 0;
}
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->options.data_call_format));
}
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
@@ -511,7 +520,8 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
GASSERT(priv->query_id);
priv->query_id = 0;
if (ril_status == RIL_E_SUCCESS) {
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->options.data_call_format));
}
}
@@ -586,11 +596,11 @@ static gboolean ril_data_request_do_cancel(struct ril_data_request *req)
struct ril_data_priv *priv = req->data->priv;
DBG_(req->data, "canceling %s request %p", req->name, req);
if (req->cancel) {
req->cancel(req);
}
if (priv->pending_req == req) {
/* Request has been submitted already */
if (req->cancel) {
req->cancel(req);
}
priv->pending_req = NULL;
} else if (priv->req_queue == req) {
/* It's the first one in the queue */
@@ -673,15 +683,33 @@ static void ril_data_request_queue(struct ril_data_request *req)
static void ril_data_call_setup_cancel(struct ril_data_request *req)
{
if (req->pending_id) {
grilio_queue_cancel_request(req->data->priv->q,
req->pending_id, FALSE);
req->pending_id = 0;
if (req->cb.setup) {
req->cb.setup(req->data, GRILIO_STATUS_CANCELLED,
NULL, req->arg);
}
struct ril_data_request_setup *setup =
G_CAST(req, struct ril_data_request_setup, req);
ril_data_request_cancel_io(req);
if (setup->retry_delay_id) {
g_source_remove(setup->retry_delay_id);
setup->retry_delay_id = 0;
}
if (req->cb.setup) {
ril_data_call_setup_cb_t cb = req->cb.setup;
req->cb.setup = NULL;
cb(req->data, GRILIO_STATUS_CANCELLED, NULL, req->arg);
}
}
static gboolean ril_data_call_setup_retry(void *user_data)
{
struct ril_data_request_setup *setup = user_data;
struct ril_data_request *req = &setup->req;
GASSERT(setup->retry_delay_id);
setup->retry_delay_id = 0;
setup->retry_count++;
DBG("silent retry %u out of %u", setup->retry_count,
req->data->priv->options.data_call_retry_limit);
req->submit(req);
return G_SOURCE_REMOVE;
}
static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
@@ -690,11 +718,13 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
struct ril_data_request_setup *setup = user_data;
struct ril_data_request *req = &setup->req;
struct ril_data *self = req->data;
struct ril_data_priv *priv = self->priv;
struct ril_data_call_list *list = NULL;
struct ril_data_call *call = NULL;
if (ril_status == RIL_E_SUCCESS) {
list = ril_data_call_list_parse(data, len);
list = ril_data_call_list_parse(data, len,
priv->options.data_call_format);
}
if (list) {
@@ -707,15 +737,25 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
}
if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED &&
!setup->retry_count) {
setup->retry_count < priv->options.data_call_retry_limit) {
/*
* Retry silently according to comment in ril.h
* (no more than once though)
* According to the comment from ril.h we should silently
* retry. First time we retry immediately and if that doedsn't
* work, then after certain delay.
*/
DBG("retrying silently");
setup->retry_count++;
req->pending_id = 0;
req->submit(req);
GASSERT(!setup->retry_delay_id);
if (!setup->retry_count) {
setup->retry_count++;
DBG("silent retry %u out of %u", setup->retry_count,
priv->options.data_call_retry_limit);
req->submit(req);
} else {
guint ms = priv->options.data_call_retry_delay_ms;
DBG("silent retry scheduled in %u ms", ms);
setup->retry_delay_id = g_timeout_add(ms,
ril_data_call_setup_retry, setup);
}
ril_data_call_list_free(list);
return;
}
@@ -844,14 +884,11 @@ static struct ril_data_request *ril_data_call_setup_new(struct ril_data *data,
static void ril_data_call_deact_cancel(struct ril_data_request *req)
{
if (req->pending_id) {
grilio_queue_cancel_request(req->data->priv->q,
req->pending_id, FALSE);
req->pending_id = 0;
if (req->cb.setup) {
req->cb.deact(req->data, GRILIO_STATUS_CANCELLED,
req->arg);
}
ril_data_request_cancel_io(req);
if (req->cb.deact) {
ril_data_call_deactivate_cb_t cb = req->cb.deact;
req->cb.deact = NULL;
cb(req->data, GRILIO_STATUS_CANCELLED, req->arg);
}
}
@@ -938,15 +975,6 @@ static struct ril_data_request *ril_data_call_deact_new(struct ril_data *data,
* ril_data_allow_request
*==========================================================================*/
static GRilIoRequest *ril_data_allow_req(gboolean allow)
{
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, allow != FALSE);
return req;
}
static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
const void *req_data, guint len, void *user_data)
{
@@ -956,13 +984,22 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
ril_data_request_completed(req);
if (ril_status == RIL_E_SUCCESS &&
(priv->flags & RIL_DATA_FLAG_ALLOWED)) {
GASSERT(!ril_data_allowed(data));
priv->flags |= RIL_DATA_FLAG_ON;
GASSERT(ril_data_allowed(data));
DBG_(data, "data on");
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
if (ril_status == RIL_E_SUCCESS) {
const gboolean was_allowed = ril_data_allowed(data);
struct ril_data_request_allow_data *ad =
G_CAST(req, struct ril_data_request_allow_data, req);
if (ad->allow) {
priv->flags |= RIL_DATA_FLAG_ON;
DBG_(data, "data on");
} else {
priv->flags &= ~RIL_DATA_FLAG_ON;
DBG_(data, "data off");
}
if (ril_data_allowed(data) != was_allowed) {
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
}
}
ril_data_request_finish(req);
@@ -970,7 +1007,9 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
static gboolean ril_data_allow_submit(struct ril_data_request *req)
{
GRilIoRequest *ioreq = ril_data_allow_req(TRUE);
struct ril_data_request_allow_data *ad =
G_CAST(req, struct ril_data_request_allow_data, req);
GRilIoRequest *ioreq = grilio_request_array_int32_new(1, ad->allow);
struct ril_data_priv *priv = req->data->priv;
grilio_request_set_retry(ioreq, RIL_RETRY_SECS*1000, -1);
@@ -980,15 +1019,19 @@ static gboolean ril_data_allow_submit(struct ril_data_request *req)
return TRUE;
}
static struct ril_data_request *ril_data_allow_new(struct ril_data *data)
static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
gboolean allow)
{
struct ril_data_request *req = g_new0(struct ril_data_request, 1);
struct ril_data_request_allow_data *ad =
g_new0(struct ril_data_request_allow_data, 1);
struct ril_data_request *req = &ad->req;
req->name = "ALLOW_DATA";
req->data = data;
req->submit = ril_data_allow_submit;
req->cancel = ril_data_request_cancel_io;
req->flags = DATA_REQUEST_FLAG_CANCEL_WHEN_DISALLOWED;
ad->allow = allow;
return req;
}
@@ -1023,9 +1066,20 @@ static void ril_data_settings_changed(struct ril_sim_settings *settings,
ril_data_manager_check_network_mode(RIL_DATA(user_data)->priv->dm);
}
static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
{
const struct ril_data *d1 = a;
const struct ril_data *d2 = b;
const struct ril_data_priv *p1 = d1->priv;
const struct ril_data_priv *p2 = d2->priv;
return p1->slot < p2->slot ? (-1) : p1->slot > p2->slot ? 1 : 0;
}
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, enum ril_data_allow_data_opt opt)
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config)
{
GASSERT(dm);
if (G_LIKELY(dm)) {
@@ -1034,24 +1088,26 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_sim_settings *settings = network->settings;
GRilIoRequest *req = grilio_request_new();
switch (opt) {
case RIL_ALLOW_DATA_ON:
case RIL_ALLOW_DATA_OFF:
priv->allow_data = opt;
priv->options = *options;
switch (priv->options.allow_data) {
case RIL_ALLOW_DATA_ENABLED:
case RIL_ALLOW_DATA_DISABLED:
break;
default:
/*
* When RIL_REQUEST_ALLOW_DATA first appeared in ril.h
* RIL_VERSION was 10
*/
priv->allow_data = (io->ril_version > 10) ?
RIL_ALLOW_DATA_ON : RIL_ALLOW_DATA_OFF;
priv->options.allow_data = (io->ril_version > 10) ?
RIL_ALLOW_DATA_ENABLED :
RIL_ALLOW_DATA_DISABLED;
break;
}
priv->log_prefix = (name && name[0]) ?
g_strconcat(name, " ", NULL) : g_strdup("");
priv->slot = config->slot;
priv->q = grilio_queue_new(io);
priv->io = grilio_channel_ref(io);
priv->dm = ril_data_manager_ref(dm);
@@ -1076,7 +1132,10 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
NULL, self);
grilio_request_unref(req);
dm->data_list = g_slist_append(dm->data_list, self);
/* Order data contexts according to slot numbers */
dm->data_list = g_slist_insert_sorted(dm->data_list, self,
ril_data_compare_cb);
ril_data_manager_check_network_mode(dm);
return self;
}
return NULL;
@@ -1159,10 +1218,11 @@ static void ril_data_cancel_requests(struct ril_data *self,
static void ril_data_disallow(struct ril_data *self)
{
struct ril_data_priv *priv = self->priv;
const gboolean was_allowed = ril_data_allowed(self);
DBG_(self, "disallowed");
GASSERT(priv->flags & RIL_DATA_FLAG_ALLOWED);
priv->flags &= ~(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
priv->flags &= ~RIL_DATA_FLAG_ALLOWED;
/*
* Cancel all requests that can be canceled.
@@ -1175,7 +1235,20 @@ static void ril_data_disallow(struct ril_data *self)
* requests are already pending? That's quite unlikely though)
*/
ril_data_deactivate_all(self);
ril_data_power_update(self);
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
/* Tell rild that the data is now disabled */
ril_data_request_queue(ril_data_allow_new(self, FALSE));
} else {
priv->flags &= ~RIL_DATA_FLAG_ON;
GASSERT(!ril_data_allowed(self));
DBG_(self, "data off");
ril_data_power_update(self);
}
if (ril_data_allowed(self) != was_allowed) {
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
}
}
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
@@ -1192,12 +1265,7 @@ static void ril_data_disallow_cb(gpointer data_ptr, gpointer allowed)
struct ril_data *data = data_ptr;
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
const gboolean was_allowed = ril_data_allowed(data);
ril_data_disallow(data);
if (was_allowed) {
ril_data_signal_emit(data,
SIGNAL_ALLOW_CHANGED);
}
}
}
}
@@ -1251,13 +1319,7 @@ void ril_data_allow(struct ril_data *self, enum ril_data_role role)
}
} else {
if (priv->flags & RIL_DATA_FLAG_ALLOWED) {
gboolean was_allowed = ril_data_allowed(self);
ril_data_disallow(self);
if (was_allowed) {
ril_data_signal_emit(self,
SIGNAL_ALLOW_CHANGED);
}
ril_data_manager_check_data(dm);
}
}
@@ -1379,6 +1441,16 @@ void ril_data_manager_unref(struct ril_data_manager *self)
}
}
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
{
/*
* The 3G/LTE handover thing only makes sense if we are managing
* more than one SIM slot. Otherwise leave things where they are.
*/
return (self->data_list && self->data_list->next &&
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
}
static gboolean ril_data_manager_requests_pending(struct ril_data_manager *self)
{
GSList *l;
@@ -1398,53 +1470,54 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
GSList *l;
if (ril_data_manager_handover(self)) {
gboolean need_fast_access = FALSE;
struct ril_network *lte_network = NULL;
int non_gsm_count = 0;
/*
* Count number of SIMs for which GSM is selected
* Count number of SIMs for which non-GSM mode is selected
*/
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
struct ril_data_priv *priv = data->priv;
struct ril_sim_settings *sim = priv->network->settings;
struct ril_network *network = priv->network;
struct ril_sim_settings *sim = network->settings;
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM &&
sim->imsi) {
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) {
non_gsm_count++;
if (priv->flags & RIL_DATA_FLAG_MAX_SPEED) {
need_fast_access = TRUE;
if ((priv->flags & RIL_DATA_FLAG_MAX_SPEED) &&
!lte_network) {
lte_network = network;
}
}
}
/*
* If the SIM selected for internet access has non-GSM mode
* enabled and non-GSM mode is enabled for more than one SIM,
* then we need to limit other SIMs to GSM. Otherwise, turn
* all limits off.
* If there's no SIM selected for internet access
* then choose the first slot for LTE.
*/
if (need_fast_access && non_gsm_count > 1) {
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
struct ril_data_priv *priv = data->priv;
ril_network_set_max_pref_mode(priv->network,
(priv->flags & RIL_DATA_FLAG_MAX_SPEED) ?
OFONO_RADIO_ACCESS_MODE_ANY :
OFONO_RADIO_ACCESS_MODE_GSM,
FALSE);
}
return;
if (!lte_network) {
struct ril_data *data = self->data_list->data;
lte_network = data->priv->network;
}
}
/* Otherwise there's no reason to limit anything */
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
ril_network_set_max_pref_mode(data->priv->network,
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
struct ril_network *network = data->priv->network;
ril_network_set_max_pref_mode(network,
(network == lte_network) ?
OFONO_RADIO_ACCESS_MODE_ANY :
OFONO_RADIO_ACCESS_MODE_GSM,
FALSE);
}
} else {
/* Otherwise there's no reason to limit anything */
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
ril_network_set_max_pref_mode(data->priv->network,
OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
}
}
}
@@ -1462,16 +1535,6 @@ static struct ril_data *ril_data_manager_allowed(struct ril_data_manager *self)
return NULL;
}
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
{
/*
* The 3G/LTE handover thing only makes sense if we are managing
* more than one SIM slot. Otherwise leave things where they are.
*/
return (self->data_list && self->data_list->next &&
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
}
static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
struct ril_data *data)
{
@@ -1485,9 +1548,8 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
}
if (priv->allow_data == RIL_ALLOW_DATA_ON) {
ril_data_request_queue(ril_data_allow_new(data));
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
ril_data_request_queue(ril_data_allow_new(data, TRUE));
} else {
priv->flags |= RIL_DATA_FLAG_ON;
GASSERT(ril_data_allowed(data));
@@ -1510,6 +1572,16 @@ static void ril_data_manager_check_data(struct ril_data_manager *self)
}
}
void ril_data_manager_assert_data_on(struct ril_data_manager *self)
{
if (self) {
struct ril_data *data = ril_data_manager_allowed(self);
if (data) {
ril_data_request_queue(ril_data_allow_new(data, TRUE));
}
}
}
/*
* Local Variables:
* mode: C

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -56,8 +56,22 @@ enum ril_data_manager_flags {
enum ril_data_allow_data_opt {
RIL_ALLOW_DATA_AUTO,
RIL_ALLOW_DATA_ON,
RIL_ALLOW_DATA_OFF
RIL_ALLOW_DATA_ENABLED,
RIL_ALLOW_DATA_DISABLED
};
enum ril_data_call_format {
RIL_DATA_CALL_FORMAT_AUTO,
RIL_DATA_CALL_FORMAT_6 = 6,
RIL_DATA_CALL_FORMAT_9 = 9,
RIL_DATA_CALL_FORMAT_11 = 11
};
struct ril_data_options {
enum ril_data_allow_data_opt allow_data;
enum ril_data_call_format data_call_format;
unsigned int data_call_retry_limit;
unsigned int data_call_retry_delay_ms;
};
enum ril_data_role {
@@ -70,6 +84,7 @@ struct ril_data_manager;
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
void ril_data_manager_unref(struct ril_data_manager *dm);
void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
@@ -79,8 +94,9 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
int ril_status, void *arg);
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, enum ril_data_allow_data_opt opt);
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config);
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
gboolean ril_data_allowed(struct ril_data *data);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,16 +17,24 @@
#include "ril_util.h"
#include "ril_log.h"
#include <gutil_idlequeue.h>
/*
* TODO: No public RIL api to query manufacturer or model.
* Check where to get, could /system/build.prop be updated to have good values?
*/
enum ril_devinfo_cb_tag {
DEVINFO_QUERY_SERIAL = 1,
DEVINFO_QUERY_SVN
};
struct ril_devinfo {
struct ofono_devinfo *info;
GRilIoQueue *q;
guint register_id;
guint imei_id;
GUtilIdleQueue *iq;
char *log_prefix;
char *imeisv;
char *imei;
};
@@ -36,6 +44,7 @@ struct ril_devinfo_cbd {
gpointer data;
};
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
#define ril_devinfo_cbd_free g_free
static inline struct ril_devinfo *ril_devinfo_get_data(
@@ -62,7 +71,7 @@ static void ril_devinfo_query_unsupported(struct ofono_devinfo *info,
cb(ril_error_failure(&error), "", data);
}
static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
static void ril_devinfo_query_revision_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
@@ -73,7 +82,7 @@ static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
res = grilio_parser_get_utf8(&rilp);
DBG("%s", res);
DBG_(cbd->di, "%s", res);
cbd->cb(ril_error_ok(&error), res ? res : "", cbd->data);
g_free(res);
} else {
@@ -86,23 +95,46 @@ static void ril_devinfo_query_revision(struct ofono_devinfo *info,
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG("");
grilio_queue_send_request_full(di->q, NULL, RIL_REQUEST_BASEBAND_VERSION,
ril_devinfo_query_cb, ril_devinfo_cbd_free,
DBG_(di, "");
grilio_queue_send_request_full(di->q, NULL,
RIL_REQUEST_BASEBAND_VERSION,
ril_devinfo_query_revision_cb,
ril_devinfo_cbd_free,
ril_devinfo_cbd_new(di, cb, data));
}
static gboolean ril_devinfo_query_serial_cb(void *user_data)
static void ril_devinfo_query_serial_cb(gpointer user_data)
{
struct ril_devinfo_cbd *cbd = user_data;
struct ril_devinfo *di = cbd->di;
struct ofono_error error;
GASSERT(di->imei_id);
di->imei_id = 0;
DBG_(di, "%s", di->imei);
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
return FALSE;
}
static void ril_devinfo_query_svn_cb(gpointer user_data)
{
struct ril_devinfo_cbd *cbd = user_data;
struct ril_devinfo *di = cbd->di;
struct ofono_error error;
DBG_(di, "%s", di->imeisv);
if (di->imeisv && di->imeisv[0]) {
cbd->cb(ril_error_ok(&error), di->imeisv, cbd->data);
} else {
cbd->cb(ril_error_failure(&error), "", cbd->data);
}
}
static void ril_devinfo_query(struct ril_devinfo *di,
enum ril_devinfo_cb_tag tag, GUtilIdleFunc fn,
ofono_devinfo_query_cb_t cb, void *data)
{
GVERIFY_FALSE(gutil_idle_queue_cancel_tag(di->iq, tag));
gutil_idle_queue_add_tag_full(di->iq, tag, fn,
ril_devinfo_cbd_new(di, cb, data),
ril_devinfo_cbd_free);
}
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
@@ -111,29 +143,28 @@ static void ril_devinfo_query_serial(struct ofono_devinfo *info,
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
GASSERT(!di->imei_id);
if (di->imei_id) {
g_source_remove(di->imei_id);
di->imei_id = 0;
}
DBG("%s", di->imei);
di->imei_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_devinfo_query_serial_cb,
ril_devinfo_cbd_new(di, cb, data),
ril_devinfo_cbd_free);
DBG_(di, "");
ril_devinfo_query(di, DEVINFO_QUERY_SERIAL,
ril_devinfo_query_serial_cb, cb, data);
}
static gboolean ril_devinfo_register(gpointer user_data)
static void ril_devinfo_query_svn(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb,
void *data)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG_(di, "");
ril_devinfo_query(di, DEVINFO_QUERY_SVN,
ril_devinfo_query_svn_cb, cb, data);
}
static void ril_devinfo_register(gpointer user_data)
{
struct ril_devinfo *di = user_data;
DBG("");
di->register_id = 0;
DBG_(di, "");
ofono_devinfo_register(di->info);
/* This makes the timeout a single-shot */
return FALSE;
}
static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
@@ -142,13 +173,18 @@ static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
struct ril_modem *modem = data;
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
DBG("%s %s %p", ril_modem_get_path(modem), modem->imei, di);
di->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
DBG_(di, "%s", modem->imei);
GASSERT(modem->imei);
di->q = grilio_queue_new(ril_modem_io(modem));
di->info = info;
di->imeisv = g_strdup(modem->imeisv);
di->imei = g_strdup(modem->imei);
di->register_id = g_idle_add(ril_devinfo_register, di);
di->iq = gutil_idle_queue_new();
gutil_idle_queue_add(di->iq, ril_devinfo_register, di);
ofono_devinfo_set_data(info, di);
return 0;
}
@@ -157,19 +193,14 @@ static void ril_devinfo_remove(struct ofono_devinfo *info)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG("%p", di);
DBG_(di, "");
ofono_devinfo_set_data(info, NULL);
if (di->register_id > 0) {
g_source_remove(di->register_id);
}
if (di->imei_id > 0) {
g_source_remove(di->imei_id);
}
gutil_idle_queue_cancel_all(di->iq);
gutil_idle_queue_unref(di->iq);
grilio_queue_cancel_all(di->q, FALSE);
grilio_queue_unref(di->q);
g_free(di->log_prefix);
g_free(di->imeisv);
g_free(di->imei);
g_free(di);
}
@@ -178,10 +209,11 @@ const struct ofono_devinfo_driver ril_devinfo_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_devinfo_probe,
.remove = ril_devinfo_remove,
.query_manufacturer = ril_devinfo_query_unsupported,
/* query_revision won't be called if query_model is missing */
.query_model = ril_devinfo_query_unsupported,
.query_revision = ril_devinfo_query_revision,
.query_serial = ril_devinfo_query_serial
.query_serial = ril_devinfo_query_serial,
.query_svn = ril_devinfo_query_svn
};
/*

View File

@@ -448,14 +448,14 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
ril_netreg_check_if_really_roaming(netreg, rs) ==
NETWORK_REGISTRATION_STATUS_ROAMING) {
struct ofono_error error;
ofono_info("Can't activate context %d (roaming)",
ofono_info("Can't activate context %u (roaming)",
ctx->cid);
cb(ril_error_failure(&error), data);
return;
}
}
ofono_info("Activating context: %d", ctx->cid);
ofono_info("Activating context: %u", ctx->cid);
GASSERT(!gcd->activate.req);
GASSERT(ctx->cid != CTX_ID_NONE);
@@ -509,7 +509,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
ofono_info("Deactivate primary");
ofono_info("Deactivating context: %u", id);
if (gcd->active_call && gcd->active_ctx_cid == id) {
gcd->deactivate.cb = cb;
@@ -526,7 +526,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
unsigned int id)
{
DBG("%d", id);
DBG("%u", id);
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -51,11 +51,13 @@ struct ril_modem_online_request {
struct ril_modem_data {
struct ril_modem modem;
GRilIoQueue *q;
struct ofono_radio_settings *radio_settings;
char *log_prefix;
char *imeisv;
char *imei;
char *ecclist_file;
gboolean pre_sim_done;
gboolean allow_data;
gulong sim_imsi_event_id;
guint online_check_id;
enum ril_modem_power_state power_state;
@@ -73,6 +75,8 @@ struct ril_modem_data {
#define RADIO_POWER_TAG(md) (md)
#define DBG_(md,fmt,args...) DBG("%s" fmt, (md)->log_prefix, ##args)
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
{
struct ril_modem_data *md = ofono_modem_get_data(o);
@@ -115,6 +119,12 @@ struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
}
static inline struct ofono_radio_settings *ril_modem_radio_settings(
struct ril_modem *modem)
{
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
}
void ril_modem_delete(struct ril_modem *md)
{
if (md && md->ofono) {
@@ -223,17 +233,23 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
{
if (md->modem.radio->state == RADIO_STATE_ON) {
if (!md->radio_settings) {
DBG("Initializing radio settings interface");
md->radio_settings =
ofono_radio_settings_create(md->modem.ofono, 0,
RILMODEM_DRIVER, md);
struct ril_modem *m = &md->modem;
if (m->radio->state == RADIO_STATE_ON && m->sim_settings->imsi) {
/* radio-settings.c assumes that IMSI is available */
if (!ril_modem_radio_settings(m)) {
DBG_(md, "initializing radio settings interface");
ofono_radio_settings_create(m->ofono, 0,
RILMODEM_DRIVER, md);
}
} else {
/* ofono core may remove radio settings atom internally */
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
if (rs) {
DBG_(md, "removing radio settings interface");
ofono_radio_settings_remove(rs);
} else {
DBG_(md, "radio settings interface is already gone");
}
} else if (md->radio_settings) {
DBG("Removing radio settings interface");
ofono_radio_settings_remove(md->radio_settings);
md->radio_settings = NULL;
}
}
@@ -246,6 +262,14 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
ril_modem_update_online_state(md);
}
static void ril_modem_imsi_cb(struct ril_sim_settings *settings, void *data)
{
struct ril_modem_data *md = data;
GASSERT(md->modem.sim_settings == settings);
ril_modem_update_radio_settings(md);
}
static void ril_modem_pre_sim(struct ofono_modem *modem)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
@@ -255,7 +279,6 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
ril_modem_update_radio_settings(md);
if (!md->radio_state_event_id) {
md->radio_state_event_id =
ril_radio_add_state_changed_handler(md->modem.radio,
@@ -289,6 +312,7 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
ofono_message_waiting_register(ofono_message_waiting_create(modem));
}
@@ -385,6 +409,10 @@ static void ril_modem_remove(struct ofono_modem *ofono)
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
ril_radio_unref(modem->radio);
ril_sim_settings_remove_handler(modem->sim_settings,
md->sim_imsi_event_id);
ril_sim_settings_unref(modem->sim_settings);
if (md->online_check_id) {
g_source_remove(md->online_check_id);
}
@@ -399,13 +427,14 @@ static void ril_modem_remove(struct ofono_modem *ofono)
ril_network_unref(modem->network);
ril_sim_card_unref(modem->sim_card);
ril_sim_settings_unref(modem->sim_settings);
ril_cell_info_unref(modem->cell_info);
ril_data_unref(modem->data);
grilio_channel_unref(modem->io);
grilio_queue_cancel_all(md->q, FALSE);
grilio_queue_unref(md->q);
g_free(md->ecclist_file);
g_free(md->log_prefix);
g_free(md->imeisv);
g_free(md->imei);
g_free(md);
}
@@ -433,9 +462,12 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
/* Copy config */
modem->config = *slot->config;
modem->imei = md->imei = g_strdup(slot->imei);
modem->imeisv = md->imeisv = g_strdup(slot->imeisv);
modem->log_prefix = log_prefix;
modem->ecclist_file =
md->ecclist_file = g_strdup(slot->ecclist_file);
md->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
modem->ofono = ofono;
modem->radio = ril_radio_ref(radio);
@@ -446,6 +478,16 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
modem->data = ril_data_ref(data);
modem->io = grilio_channel_ref(io);
md->q = grilio_queue_new(io);
/*
* modem->sim_settings->imsi follows IMSI known to the ofono
* core, unlike ril_sim_info->imsi which may point to the
* cached IMSI even before the PIN code is entered.
*/
md->sim_imsi_event_id =
ril_sim_settings_add_imsi_changed_handler(settings,
ril_modem_imsi_cb, md);
md->set_online.md = md;
md->set_offline.md = md;
ofono_modem_set_data(ofono, md);
@@ -470,6 +512,8 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
*/
grilio_queue_send_request(md->q, NULL,
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
ril_modem_update_radio_settings(md);
return modem;
} else {
ofono_error("Error %d registering %s",

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -47,12 +47,17 @@ enum ril_network_radio_event {
RADIO_EVENT_COUNT
};
enum ril_network_unsol_event {
UNSOL_EVENT_NETWORK_STATE,
UNSOL_EVENT_RADIO_CAPABILITY,
UNSOL_EVENT_COUNT
};
struct ril_network_priv {
GRilIoChannel *io;
GRilIoQueue *q;
struct ril_radio *radio;
struct ril_sim_card *sim_card;
enum ofono_radio_access_mode max_pref_mode;
int rat;
char *log_prefix;
guint operator_poll_id;
@@ -61,11 +66,12 @@ struct ril_network_priv {
guint timer[TIMER_COUNT];
gulong query_rat_id;
gulong set_rat_id;
gulong ril_event_id;
gulong unsol_event_id[UNSOL_EVENT_COUNT];
gulong settings_event_id;
gulong sim_status_event_id;
gulong radio_event_id[RADIO_EVENT_COUNT];
struct ofono_network_operator operator;
gboolean assert_rat;
};
enum ril_network_signal {
@@ -73,13 +79,15 @@ enum ril_network_signal {
SIGNAL_VOICE_STATE_CHANGED,
SIGNAL_DATA_STATE_CHANGED,
SIGNAL_PREF_MODE_CHANGED,
SIGNAL_MAX_PREF_MODE_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-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_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-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_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 };
@@ -420,13 +428,16 @@ static int ril_network_mode_to_rat(struct ril_network *self,
switch (mode) {
case OFONO_RADIO_ACCESS_MODE_ANY:
case OFONO_RADIO_ACCESS_MODE_LTE:
if (self->settings->enable_4g) {
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
return PREF_NET_TYPE_LTE_GSM_WCDMA;
}
/* no break */
default:
case OFONO_RADIO_ACCESS_MODE_UMTS:
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_UMTS) {
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
}
/* no break */
case OFONO_RADIO_ACCESS_MODE_GSM:
return PREF_NET_TYPE_GSM_ONLY;
}
@@ -436,9 +447,30 @@ static int ril_network_pref_mode_expected(struct ril_network *self)
{
struct ril_sim_settings *settings = self->settings;
struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode pref_mode = priv->max_pref_mode ?
MIN(settings->pref_mode, priv->max_pref_mode) :
settings->pref_mode;
/*
* On dual-SIM phones such as Jolla C only one slot at a time
* is allowed to use LTE. Even if the slot which has been using
* LTE gets powered off, we still need to explicitely set its
* preferred mode to GSM, to make LTE machinery available to
* the other slot. This sort of behaviour might not be necessary
* on some hardware and can (should) be made configurable when
* it becomes necessary.
*/
const enum ofono_radio_access_mode max_pref_mode =
(priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
OFONO_RADIO_ACCESS_MODE_GSM;
/*
* OFONO_RADIO_ACCESS_MODE_ANY is zero. If both pref_mode
* and max_pref_mode are not ANY, we pick the smallest value.
* Otherwise we take any non-zero value if there is one.
*/
const enum ofono_radio_access_mode pref_mode =
(settings->pref_mode && max_pref_mode) ?
MIN(settings->pref_mode, max_pref_mode) :
settings->pref_mode ? settings->pref_mode :
max_pref_mode;
return ril_network_mode_to_rat(self, pref_mode);
}
@@ -465,7 +497,7 @@ static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
* and SIM card state change callbacks will schedule a new check
* when it's appropriate.
*/
if (priv->rat != rat) {
if (priv->rat != rat || priv->assert_rat) {
if (ril_network_can_set_pref_mode(self)) {
ril_network_set_pref_mode(self, rat);
} else {
@@ -506,6 +538,9 @@ static void ril_network_set_pref_mode(struct ril_network *self, int rat)
ril_network_set_pref_mode_cb, NULL, self);
grilio_request_unref(req);
/* We have submitted the request, clear the assertion flag */
priv->assert_rat = FALSE;
/* Don't do it too often */
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
priv->timer[TIMER_SET_RAT_HOLDOFF] =
@@ -533,8 +568,7 @@ static void ril_network_check_pref_mode(struct ril_network *self,
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
}
if (priv->rat != rat) {
/* Something isn't right, we need to fix it */
if (priv->rat != rat || priv->assert_rat) {
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
ril_network_set_pref_mode(self, rat);
} else {
@@ -555,6 +589,31 @@ static int ril_network_parse_pref_resp(const void *data, guint len)
return pref;
}
static void ril_network_startup_query_pref_mode_cb(GRilIoChannel *io,
int status, const void *data, guint len, void *user_data)
{
if (status == RIL_E_SUCCESS) {
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
priv->rat = ril_network_parse_pref_resp(data, len);
self->pref_mode = ril_network_rat_to_mode(priv->rat);
DBG_(self, "rat mode %d (%s)", priv->rat,
ofono_radio_access_mode_to_string(self->pref_mode));
if (self->pref_mode != pref_mode) {
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
}
/*
* Unlike ril_network_query_pref_mode_cb, this one always
* checks the preferred mode.
*/
ril_network_check_pref_mode(self, FALSE);
}
}
static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
@@ -598,17 +657,25 @@ void ril_network_set_max_pref_mode(struct ril_network *self,
enum ofono_radio_access_mode max_mode,
gboolean force_check)
{
if (G_LIKELY(self)) {
struct ril_network_priv *priv = self->priv;
if (priv->max_pref_mode != max_mode || force_check) {
if (self && (self->max_pref_mode != max_mode || force_check)) {
if (self->max_pref_mode != max_mode) {
DBG_(self, "rat mode %d (%s)", max_mode,
ofono_radio_access_mode_to_string(max_mode));
priv->max_pref_mode = max_mode;
ril_network_check_pref_mode(self, TRUE);
self->max_pref_mode = max_mode;
ril_network_emit(self, SIGNAL_MAX_PREF_MODE_CHANGED);
}
ril_network_check_pref_mode(self, TRUE);
}
}
void ril_network_assert_pref_mode(struct ril_network *self, gboolean immediate)
{
struct ril_network_priv *priv = self->priv;
priv->assert_rat = TRUE;
ril_network_check_pref_mode(self, immediate);
}
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
@@ -637,6 +704,13 @@ gulong ril_network_add_pref_mode_changed_handler(struct ril_network *self,
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_MAX_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_network_remove_handler(struct ril_network *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
@@ -649,7 +723,7 @@ void ril_network_remove_handlers(struct ril_network *self, gulong *ids, int n)
gutil_disconnect_handlers(self, ids, n);
}
static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
static void ril_network_state_changed_cb(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
@@ -659,10 +733,23 @@ static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
ril_network_poll_state(self);
}
static void ril_network_radio_capability_changed_cb(GRilIoChannel *io,
guint code, const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
DBG_(self, "");
GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
ril_network_assert_pref_mode(self, FALSE);
}
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
{
struct ril_network *self = RIL_NETWORK(data);
ril_network_check_pref_mode(self, FALSE);
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(RIL_NETWORK(data));
ril_network_poll_state(self);
}
}
@@ -733,9 +820,14 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
priv->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
DBG_(self, "");
priv->ril_event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_network_voice_state_changed_cb,
priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
grilio_channel_add_unsol_event_handler(priv->io,
ril_network_state_changed_cb,
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
priv->unsol_event_id[UNSOL_EVENT_RADIO_CAPABILITY] =
grilio_channel_add_unsol_event_handler(priv->io,
ril_network_radio_capability_changed_cb,
RIL_UNSOL_RADIO_CAPABILITY, self);
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
ril_radio_add_state_changed_handler(priv->radio,
ril_network_radio_state_cb, self);
@@ -753,7 +845,9 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
* Query the initial state. Querying network state before the radio
* has been turned on makes RIL unhappy.
*/
ril_network_query_pref_mode(self);
grilio_queue_send_request_full(priv->q, NULL,
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
ril_network_startup_query_pref_mode_cb, NULL, self);
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(self);
}
@@ -795,7 +889,8 @@ static void ril_network_dispose(GObject *object)
struct ril_network_priv *priv = self->priv;
enum ril_network_timer tid;
grilio_channel_remove_handlers(priv->io, &priv->ril_event_id, 1);
grilio_channel_remove_handlers(priv->io, priv->unsol_event_id,
G_N_ELEMENTS(priv->unsol_event_id));
ril_radio_remove_handlers(priv->radio, priv->radio_event_id,
G_N_ELEMENTS(priv->radio_event_id));
ril_sim_settings_remove_handlers(self->settings,
@@ -840,6 +935,7 @@ static void ril_network_class_init(RilNetworkClass *klass)
RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
RIL_NETWORK_SIGNAL(klass, DATA_STATE);
RIL_NETWORK_SIGNAL(klass, PREF_MODE);
RIL_NETWORK_SIGNAL(klass, MAX_PREF_MODE);
}
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -38,6 +38,7 @@ struct ril_network {
struct ril_registration_state data;
const struct ofono_network_operator *operator;
enum ofono_radio_access_mode pref_mode;
enum ofono_radio_access_mode max_pref_mode;
struct ril_sim_settings *settings;
};
@@ -53,6 +54,7 @@ void ril_network_unref(struct ril_network *net);
void ril_network_set_max_pref_mode(struct ril_network *net,
enum ofono_radio_access_mode max_pref_mode,
gboolean force_check);
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
@@ -61,6 +63,8 @@ gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
void ril_network_remove_handler(struct ril_network *net, gulong id);
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,11 +21,13 @@
#include "ril_cell_info.h"
#include "ril_network.h"
#include "ril_radio.h"
#include "ril_radio_caps.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
#include <gdbus.h>
#include <gutil_ints.h>
#include <gutil_strv.h>
#include <gutil_misc.h>
#include <mce_display.h>
@@ -40,6 +42,12 @@
#include "ofono.h"
#include "storage.h"
#define OFONO_RADIO_ACCESS_MODE_ALL (OFONO_RADIO_ACCESS_MODE_GSM |\
OFONO_RADIO_ACCESS_MODE_UMTS |\
OFONO_RADIO_ACCESS_MODE_LTE)
#define RIL_DEVICE_IDENTITY_RETRIES_LAST 2
#define RADIO_GID 1001
#define RADIO_UID 1001
#define RIL_SUB_SIZE 4
@@ -48,16 +56,20 @@
#define RILMODEM_DEFAULT_SOCK "/dev/socket/rild"
#define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2"
#define RILMODEM_DEFAULT_SUB "SUB1"
#define RILMODEM_DEFAULT_4G TRUE /* 4G is on by default */
#define RILMODEM_DEFAULT_TECHS OFONO_RADIO_ACCESS_MODE_ALL
#define RILMODEM_DEFAULT_SLOT 0xffffffff
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
#define RILMODEM_DEFAULT_DATA_OPT RIL_ALLOW_DATA_AUTO
#define RILMODEM_DEFAULT_DM_FLAGS RIL_DATA_MANAGER_3GLTE_HANDOVER
#define RILMODEM_DEFAULT_DATA_CALL_FORMAT RIL_DATA_CALL_FORMAT_AUTO
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT 4
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY 200 /* ms */
#define RILMODEM_DEFAULT_EMPTY_PIN_QUERY TRUE /* optimistic */
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
#define RILCONF_DEV_PREFIX "ril_"
#define RILCONF_PATH_PREFIX "/" RILCONF_DEV_PREFIX
@@ -66,11 +78,17 @@
#define RILCONF_SLOT "slot"
#define RILCONF_SUB "sub"
#define RILCONF_TIMEOUT "timeout"
#define RILCONF_4G "enable4G"
#define RILCONF_4G "enable4G" /* Deprecated */
#define RILCONF_TECHS "technologies"
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
#define RILCONF_ECCLIST_FILE "ecclistFile"
#define RILCONF_ALLOW_DATA_REQ "allowDataReq"
#define RILCONF_EMPTY_PIN_QUERY "emptyPinQuery"
#define RILCONF_DATA_CALL_FORMAT "dataCallFormat"
#define RILCONF_DATA_CALL_RETRY_LIMIT "dataCallRetryLimit"
#define RILCONF_DATA_CALL_RETRY_DELAY "dataCallRetryDelay"
#define RILCONF_LOCAL_HANGUP_REASONS "localHangupReasons"
#define RILCONF_REMOTE_HANGUP_REASONS "remoteHangupReasons"
#define RIL_STORE "ril"
#define RIL_STORE_GROUP "Settings"
@@ -79,6 +97,12 @@
#define RIL_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
#define RIL_STORE_SLOTS_SEP ","
/* The file where error statistics is stored */
#define RIL_ERROR_STORAGE "rilerror"
/* Modem error ids, must be static strings (only one is defined for now) */
static const char RIL_ERROR_ID_RILD_RESTART[] = "rild-restart";
enum ril_plugin_io_events {
IO_EVENT_CONNECTED,
IO_EVENT_ERROR,
@@ -93,10 +117,23 @@ enum ril_plugin_display_events {
DISPLAY_EVENT_COUNT
};
enum ril_set_radio_cap_opt {
RIL_SET_RADIO_CAP_AUTO,
RIL_SET_RADIO_CAP_ENABLED,
RIL_SET_RADIO_CAP_DISABLED
};
struct ril_plugin_settings {
int dm_flags;
enum ril_set_radio_cap_opt set_radio_cap;
};
struct ril_plugin_priv {
struct ril_plugin pub;
struct ril_plugin_dbus *dbus;
struct ril_data_manager *data_manager;
struct ril_radio_caps_manager *caps_manager;
struct ril_plugin_settings settings;
MceDisplay *display;
gboolean display_on;
gulong display_event_id[DISPLAY_EVENT_COUNT];
@@ -115,6 +152,7 @@ struct ril_slot {
struct ril_slot_info pub;
char *path;
char *imei;
char *imeisv;
char *name;
char *sockpath;
char *sub;
@@ -122,12 +160,13 @@ struct ril_slot {
int timeout; /* RIL timeout, in milliseconds */
int index;
int sim_flags;
enum ril_data_allow_data_opt allow_data_opt;
struct ril_data_options data_opt;
struct ril_slot_config config;
struct ril_plugin_priv *plugin;
struct ril_modem *modem;
struct ofono_sim *sim;
struct ril_radio *radio;
struct ril_radio_caps *caps;
struct ril_network *network;
struct ril_sim_card *sim_card;
struct ril_sim_info *sim_info;
@@ -140,8 +179,10 @@ struct ril_slot {
MceDisplay *display;
GRilIoChannel *io;
gulong io_event_id[IO_EVENT_COUNT];
gulong imei_req_id;
gulong sim_card_state_event_id;
gboolean received_sim_status;
guint caps_check_id;
guint imei_req_id;
guint trace_id;
guint dump_id;
guint retry_id;
@@ -150,16 +191,13 @@ struct ril_slot {
enum ofono_sim_state sim_state;
};
struct ril_plugin_settings {
int dm_flags;
};
static void ril_debug_trace_notify(struct ofono_debug_desc *desc);
static void ril_debug_dump_notify(struct ofono_debug_desc *desc);
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc);
static void ril_debug_mce_notify(struct ofono_debug_desc *desc);
static void ril_plugin_debug_notify(struct ofono_debug_desc *desc);
static void ril_plugin_retry_init_io(struct ril_slot *slot);
static void ril_plugin_check_modem(struct ril_slot *slot);
GLOG_MODULE_DEFINE("rilmodem");
@@ -202,6 +240,12 @@ static struct ofono_debug_desc ril_plugin_debug OFONO_DEBUG_ATTR = {
.notify = ril_plugin_debug_notify
};
static inline const char *ril_slot_debug_prefix(const struct ril_slot *slot)
{
/* slot->path always starts with a slash, skip it */
return slot->path + 1;
}
static struct ril_plugin_priv *ril_plugin_cast(struct ril_plugin *pub)
{
return G_CAST(pub, struct ril_plugin_priv, pub);
@@ -226,7 +270,7 @@ static void ril_plugin_foreach_slot(struct ril_plugin_priv *plugin,
static void ril_plugin_send_screen_state(struct ril_slot *slot)
{
if (slot->io) {
if (slot->io && slot->io->connected) {
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1); /* Number of params */
grilio_request_append_int32(req, slot->plugin->display_on);
@@ -309,6 +353,11 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
slot->cell_info = NULL;
}
if (slot->caps) {
ril_radio_caps_unref(slot->caps);
slot->caps = NULL;
}
if (slot->data) {
ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
ril_data_unref(slot->data);
@@ -332,6 +381,7 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
ril_sim_card_unref(slot->sim_card);
slot->sim_card_state_event_id = 0;
slot->sim_card = NULL;
slot->received_sim_status = FALSE;
}
if (slot->io) {
@@ -342,9 +392,17 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
slot->trace_id = 0;
slot->dump_id = 0;
grilio_channel_cancel_request(slot->io,
if (slot->caps_check_id) {
grilio_channel_cancel_request(slot->io,
slot->caps_check_id, FALSE);
slot->caps_check_id = 0;
}
if (slot->imei_req_id) {
grilio_channel_cancel_request(slot->io,
slot->imei_req_id, FALSE);
slot->imei_req_id = 0;
slot->imei_req_id = 0;
}
for (i=0; i<IO_EVENT_COUNT; i++) {
ril_plugin_remove_slot_handler(slot, i);
@@ -463,14 +521,23 @@ static int ril_plugin_update_modem_paths(struct ril_plugin_priv *plugin)
if (plugin->default_data_imsi) {
slot = ril_plugin_find_slot_imsi(plugin->slots,
plugin->default_data_imsi);
} else if (plugin->data_slot) {
/* Make sure that the slot is enabled and SIM is in */
slot = ril_plugin_find_slot_imsi(plugin->slots,
} else if (!ril_plugin_multisim(plugin)) {
if (plugin->data_slot) {
/* Make sure that the slot is enabled and SIM is in */
slot = ril_plugin_find_slot_imsi(plugin->slots,
plugin->data_slot->modem ?
ofono_sim_get_imsi(plugin->data_slot->sim) :
NULL);
} else {
/* Check if anything is available */
slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
}
} else {
slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
/*
* Should we automatically select the default data sim
* on a multisim phone that has only one sim inserted?
*/
slot = NULL;
}
if (slot && !slot->radio->online) {
@@ -562,14 +629,79 @@ static void ril_plugin_update_ready(struct ril_plugin_priv *plugin)
}
}
static void ril_plugin_device_identity_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_slot *slot = user_data;
char *imei = NULL;
char *imeisv = NULL;
GASSERT(slot->imei_req_id);
slot->imei_req_id = 0;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
guint32 n;
/*
* RIL_REQUEST_DEVICE_IDENTITY
*
* "response" is const char **
* ((const char **)response)[0] is IMEI (for GSM)
* ((const char **)response)[1] is IMEISV (for GSM)
* ((const char **)response)[2] is ESN (for CDMA)
* ((const char **)response)[3] is MEID (for CDMA)
*/
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &n) && n >= 2) {
imei = grilio_parser_get_utf8(&rilp);
imeisv = grilio_parser_get_utf8(&rilp);
DBG("%s %s", imei, imeisv);
} else {
DBG("parsing failure!");
}
/*
* slot->imei should be either NULL (when we get connected
* to rild the very first time) or match the already known
* IMEI (if rild crashed and we have reconnected)
*/
if (slot->imei && imei && strcmp(slot->imei, imei)) {
ofono_warn("IMEI has changed \"%s\" -> \"%s\"",
slot->imei, imei);
}
} else {
ofono_error("Slot %u IMEI query error: %s", slot->config.slot,
ril_error_to_string(status));
}
if (slot->imei) {
/* We assume that IMEI never changes */
g_free(imei);
} else {
slot->pub.imei =
slot->imei = imei ? imei : g_strdup_printf("%d", slot->index);
}
if (slot->imeisv) {
g_free(imeisv);
} else {
slot->pub.imeisv =
slot->imeisv = (imeisv ? imeisv : g_strdup(""));
}
ril_plugin_check_modem(slot);
ril_plugin_update_ready(slot->plugin);
}
static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
{
struct ril_slot *slot = data;
struct ril_plugin_priv *plugin = slot->plugin;
const struct ril_sim_card_status *status = card->status;
gboolean present;
if (card && card->status &&
card->status->card_state == RIL_CARDSTATE_PRESENT) {
if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
DBG("SIM found in slot %u", slot->config.slot);
present = TRUE;
} else {
@@ -577,6 +709,36 @@ static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
present = FALSE;
}
if (status) {
if (!slot->received_sim_status && slot->imei_req_id) {
/*
* We have received the SIM status but haven't yet
* got IMEI from the modem. Some RILs behave this
* way if the modem doesn't have IMEI initialized
* yet. Cancel the current request (with unlimited
* number of retries) and give a few more tries
* (this time, limited number).
*
* Some RILs fail RIL_REQUEST_DEVICE_IDENTITY until
* the modem hasn't been properly initialized.
*/
GRilIoRequest* req = grilio_request_new();
DBG("Giving slot %u last chance", slot->config.slot);
grilio_request_set_retry(req, RIL_RETRY_MS,
RIL_DEVICE_IDENTITY_RETRIES_LAST);
grilio_channel_cancel_request(slot->io,
slot->imei_req_id, FALSE);
slot->imei_req_id =
grilio_channel_send_request_full(slot->io,
req, RIL_REQUEST_DEVICE_IDENTITY,
ril_plugin_device_identity_cb,
NULL, slot);
grilio_request_unref(req);
}
slot->received_sim_status = TRUE;
}
if (slot->pub.sim_present != present) {
slot->pub.sim_present = present;
ril_plugin_dbus_signal_sim(plugin->dbus, slot->index, present);
@@ -605,7 +767,7 @@ static void ril_plugin_sim_state_watch(enum ofono_sim_state new_state,
struct ril_slot *slot = data;
struct ril_plugin_priv *plugin = slot->plugin;
DBG("%s sim state %d", slot->path + 1, new_state);
DBG("%s sim state %d", ril_slot_debug_prefix(slot), new_state);
slot->sim_state = new_state;
if (new_state == OFONO_SIM_STATE_READY) {
struct ril_slot *voice_slot = plugin->voice_slot;
@@ -661,10 +823,10 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
struct ril_slot *slot = data;
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
DBG("%s sim registered", slot->path + 1);
DBG("%s sim registered", ril_slot_debug_prefix(slot));
ril_plugin_register_sim(slot, __ofono_atom_get_data(atom));
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
DBG("%s sim unregistered", slot->path + 1);
DBG("%s sim unregistered", ril_slot_debug_prefix(slot));
slot->sim = NULL;
}
@@ -672,8 +834,35 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
ril_plugin_update_modem_paths_full(slot->plugin);
}
static void ril_plugin_handle_error(struct ril_slot *slot)
static void ril_plugin_count_error(struct ril_slot *slot, const char *key,
const char *message)
{
GHashTable *errors = slot->pub.errors;
GKeyFile *storage = storage_open(NULL, RIL_ERROR_STORAGE);
/* Update life-time statistics */
if (storage) {
/* slot->path always starts with a slash, skip it */
const char *group = slot->path + 1;
g_key_file_set_integer(storage, group, key,
g_key_file_get_integer(storage, group, key, NULL) + 1);
storage_close(NULL, RIL_ERROR_STORAGE, storage, TRUE);
}
/* Update run-time error counts. The key is the error id which
* is always a static string */
g_hash_table_insert(errors, (void*)key, GINT_TO_POINTER(
GPOINTER_TO_INT(g_hash_table_lookup(errors, key)) + 1));
/* Issue the D-Bus signal */
ril_plugin_dbus_signal_modem_error(slot->plugin->dbus,
slot->index, key, message);
}
static void ril_plugin_handle_error(struct ril_slot *slot, const char *msg)
{
ofono_error("%s %s", ril_slot_debug_prefix(slot), msg);
ril_plugin_count_error(slot, RIL_ERROR_ID_RILD_RESTART, msg);
ril_plugin_shutdown_slot(slot, TRUE);
ril_plugin_update_modem_paths_full(slot->plugin);
ril_plugin_retry_init_io(slot);
@@ -682,12 +871,12 @@ static void ril_plugin_handle_error(struct ril_slot *slot)
static void ril_plugin_slot_error(GRilIoChannel *io, const GError *error,
void *data)
{
ril_plugin_handle_error((struct ril_slot *)data);
ril_plugin_handle_error((struct ril_slot *)data, GERRMSG(error));
}
static void ril_plugin_slot_disconnected(GRilIoChannel *io, void *data)
{
ril_plugin_handle_error((struct ril_slot *)data);
ril_plugin_handle_error((struct ril_slot *)data, "disconnected");
}
static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
@@ -695,7 +884,7 @@ static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
{
struct ril_slot *slot = data;
DBG("%s %d", slot->path + 1, online);
DBG("%s %d", ril_slot_debug_prefix(slot), online);
GASSERT(slot->modem);
GASSERT(slot->modem == modem);
@@ -807,14 +996,15 @@ static void ril_debug_trace_update(struct ril_slot *slot)
static const char *ril_plugin_log_prefix(struct ril_slot *slot)
{
return ril_plugin_multisim(slot->plugin) ? (slot->path + 1) : "";
return ril_plugin_multisim(slot->plugin) ?
ril_slot_debug_prefix(slot) : "";
}
static void ril_plugin_create_modem(struct ril_slot *slot)
{
struct ril_modem *modem;
DBG("%s", slot->path);
DBG("%s", ril_slot_debug_prefix(slot));
GASSERT(slot->io && slot->io->connected);
GASSERT(!slot->modem);
@@ -863,42 +1053,6 @@ static void ril_plugin_check_modem(struct ril_slot *slot)
}
}
static void ril_plugin_imei_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_slot *slot = user_data;
char *imei = NULL;
GASSERT(slot->imei_req_id);
slot->imei_req_id = 0;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
imei = grilio_parser_get_utf8(&rilp);
DBG("%s", imei);
/*
* slot->imei should be either NULL (when we get connected
* to rild the very first time) or match the already known
* IMEI (if rild crashed and we have reconnected)
*/
GASSERT(!slot->imei || !g_strcmp0(slot->imei, imei));
} else {
ofono_error("Slot %u IMEI query error: %s", slot->config.slot,
ril_error_to_string(status));
}
g_free(slot->imei);
slot->pub.imei = slot->imei = (imei ? imei : g_strdup("ERROR"));
ril_plugin_check_modem(slot);
ril_plugin_update_ready(slot->plugin);
}
/*
* It seems to be necessary to kick (with RIL_REQUEST_RADIO_POWER) the
* modems with power on after one of the modems has been powered off.
@@ -921,9 +1075,34 @@ static void ril_plugin_radio_state_changed(GRilIoChannel *io, guint code,
}
}
static void ril_plugin_radio_caps_cb(const struct ril_radio_capability *cap,
void *user_data)
{
struct ril_slot *slot = user_data;
DBG("radio caps %s", cap ? "ok" : "NOT supported");
GASSERT(slot->caps_check_id);
slot->caps_check_id = 0;
if (cap) {
struct ril_plugin_priv *plugin = slot->plugin;
if (!plugin->caps_manager) {
plugin->caps_manager = ril_radio_caps_manager_new
(plugin->data_manager);
}
GASSERT(!slot->caps);
slot->caps = ril_radio_caps_new(plugin->caps_manager,
ril_plugin_log_prefix(slot), slot->io, slot->radio,
slot->network, &slot->config, cap);
}
}
static void ril_plugin_slot_connected(struct ril_slot *slot)
{
struct ril_plugin_priv *plugin = slot->plugin;
const struct ril_plugin_settings *ps = &plugin->settings;
const char *log_prefix = ril_plugin_log_prefix(slot);
GRilIoRequest* req;
@@ -934,17 +1113,19 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
GASSERT(!slot->io_event_id[IO_EVENT_CONNECTED]);
/*
* Modem will be registered after RIL_REQUEST_GET_IMEI successfully
* completes. By the time ofono starts, rild may not be completely
* functional. Waiting until it responds to RIL_REQUEST_GET_IMEI
* (and retrying the request on failure) gives rild time to finish
* whatever it's doing during initialization.
* Modem will be registered after RIL_REQUEST_DEVICE_IDENTITY
* successfully completes. By the time ofono starts, rild may
* not be completely functional. Waiting until it responds to
* RIL_REQUEST_DEVICE_IDENTITY (and retrying the request on
* failure) gives rild time to finish whatever it's doing during
* initialization.
*/
GASSERT(!slot->imei_req_id);
req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
slot->imei_req_id = grilio_channel_send_request_full(slot->io, req,
RIL_REQUEST_GET_IMEI, ril_plugin_imei_cb, NULL, slot);
slot->imei_req_id = grilio_channel_send_request_full(slot->io,
req, RIL_REQUEST_DEVICE_IDENTITY,
ril_plugin_device_identity_cb, NULL, slot);
grilio_request_unref(req);
GASSERT(!slot->radio);
@@ -961,6 +1142,10 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
slot->sim_flags);
slot->sim_card_state_event_id = ril_sim_card_add_state_changed_handler(
slot->sim_card, ril_plugin_sim_state_changed, slot);
/* ril_sim_card is expected to perform RIL_REQUEST_GET_SIM_STATUS
* asynchronously and report back when request has completed: */
GASSERT(!slot->sim_card->status);
GASSERT(!slot->received_sim_status);
GASSERT(!slot->network);
slot->network = ril_network_new(slot->io, log_prefix, slot->radio,
@@ -968,15 +1153,27 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
ril_sim_info_set_network(slot->sim_info, slot->network);
GASSERT(!slot->data);
slot->data = ril_data_new(slot->plugin->data_manager, log_prefix,
slot->radio, slot->network, slot->io, slot->allow_data_opt);
slot->data = ril_data_new(plugin->data_manager, log_prefix,
slot->radio, slot->network, slot->io, &slot->data_opt,
&slot->config);
GASSERT(!slot->cell_info);
if (slot->io->ril_version > 8) {
if (slot->io->ril_version >= 9) {
slot->cell_info = ril_cell_info_new(slot->io, log_prefix,
plugin->display, slot->radio, slot->sim_card);
}
GASSERT(!slot->caps);
GASSERT(!slot->caps_check_id);
if (ril_plugin_multisim(plugin) &&
(ps->set_radio_cap == RIL_SET_RADIO_CAP_ENABLED ||
(ps->set_radio_cap == RIL_SET_RADIO_CAP_AUTO &&
slot->io->ril_version >= 11))) {
/* Check if RIL really support radio capability management */
slot->caps_check_id = ril_radio_caps_check(slot->io,
ril_plugin_radio_caps_cb, slot);
}
ril_plugin_send_screen_state(slot);
ril_plugin_check_modem(slot);
ril_plugin_update_ready(plugin);
@@ -1059,11 +1256,17 @@ static struct ril_slot *ril_plugin_slot_new(const char *sockpath,
slot->path = g_strdup(path);
slot->name = g_strdup(name);
slot->config.slot = slot_index;
slot->config.enable_4g = RILMODEM_DEFAULT_4G;
slot->config.techs = RILMODEM_DEFAULT_TECHS;
slot->config.empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
slot->allow_data_opt = RILMODEM_DEFAULT_DATA_OPT;
slot->data_opt.allow_data = RILMODEM_DEFAULT_DATA_OPT;
slot->data_opt.data_call_format = RILMODEM_DEFAULT_DATA_CALL_FORMAT;
slot->data_opt.data_call_retry_limit =
RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT;
slot->data_opt.data_call_retry_delay_ms =
RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY;
slot->pub.errors = g_hash_table_new(g_str_hash, g_str_equal);
return slot;
}
@@ -1103,7 +1306,8 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
char *sock = g_key_file_get_string(file, group, RILCONF_SOCKET, NULL);
if (sock) {
int value;
char* strval;
char *strval;
char **strv;
char *sub = ril_config_get_string(file, group, RILCONF_SUB);
slot = ril_plugin_slot_new(NULL, NULL, NULL,
@@ -1131,9 +1335,52 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
DBG("%s: timeout %d", group, slot->timeout);
}
ril_config_get_boolean(file, group, RILCONF_4G,
&slot->config.enable_4g);
DBG("%s: 4G %s", group, slot->config.enable_4g ? "on" : "off");
strv = ril_config_get_strings(file, group, RILCONF_TECHS, ',');
if (strv) {
char **p;
slot->config.techs = 0;
for (p = strv; *p; p++) {
const char *s = *p;
enum ofono_radio_access_mode m;
if (!s[0]) {
continue;
}
if (!strcmp(s, "all")) {
slot->config.techs =
OFONO_RADIO_ACCESS_MODE_ALL;
break;
}
if (!ofono_radio_access_mode_from_string(s,
&m)) {
ofono_warn("Unknown technology %s "
"in [%s] section of %s", s,
group, RILMODEM_CONF_FILE);
continue;
}
if (m == OFONO_RADIO_ACCESS_MODE_ANY) {
slot->config.techs =
OFONO_RADIO_ACCESS_MODE_ALL;
break;
}
slot->config.techs |= m;
}
g_strfreev(strv);
}
/* "enable4G" is deprecated */
value = slot->config.techs;
if (ril_config_get_flag(file, group, RILCONF_4G,
OFONO_RADIO_ACCESS_MODE_LTE, &value)) {
slot->config.techs = value;
}
DBG("%s: technologies 0x%02x", group, slot->config.techs);
if (ril_config_get_boolean(file, group, RILCONF_EMPTY_PIN_QUERY,
&slot->config.empty_pin_query)) {
@@ -1150,18 +1397,44 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
"on" : "off");
}
strval = ril_config_get_string(file, group,
RILCONF_ALLOW_DATA_REQ);
if (strval) {
slot->allow_data_opt =
!strcasecmp(strval, "on") ? RIL_ALLOW_DATA_ON :
!strcasecmp(strval, "off")? RIL_ALLOW_DATA_OFF :
RIL_ALLOW_DATA_AUTO;
if (ril_config_get_enum(file, group, RILCONF_ALLOW_DATA_REQ,
&value, "auto", RIL_ALLOW_DATA_AUTO,
"on", RIL_ALLOW_DATA_ENABLED,
"off", RIL_ALLOW_DATA_DISABLED, NULL)) {
DBG("%s: %s %s", group, RILCONF_ALLOW_DATA_REQ,
slot->allow_data_opt==RIL_ALLOW_DATA_ON? "on":
slot->allow_data_opt==RIL_ALLOW_DATA_OFF? "off":
value == RIL_ALLOW_DATA_ENABLED ? "enabled":
value == RIL_ALLOW_DATA_DISABLED ? "disabled":
"auto");
g_free(strval);
slot->data_opt.allow_data = value;
}
if (ril_config_get_enum(file, group, RILCONF_DATA_CALL_FORMAT,
&value, "auto", RIL_DATA_CALL_FORMAT_AUTO,
"6", RIL_DATA_CALL_FORMAT_6,
"9", RIL_DATA_CALL_FORMAT_9,
"11", RIL_DATA_CALL_FORMAT_11, NULL)) {
if (value == RIL_DATA_CALL_FORMAT_AUTO) {
DBG("%s: %s auto", group,
RILCONF_DATA_CALL_FORMAT);
} else {
DBG("%s: %s %d", group,
RILCONF_DATA_CALL_FORMAT, value);
}
slot->data_opt.data_call_format = value;
}
if (ril_config_get_integer(file, group,
RILCONF_DATA_CALL_RETRY_LIMIT, &value) && value >= 0) {
DBG("%s: %s %d", group,
RILCONF_DATA_CALL_RETRY_LIMIT, value);
slot->data_opt.data_call_retry_limit = value;
}
if (ril_config_get_integer(file, group,
RILCONF_DATA_CALL_RETRY_DELAY, &value) && value >= 0) {
DBG("%s: %s %d ms", group,
RILCONF_DATA_CALL_RETRY_DELAY, value);
slot->data_opt.data_call_retry_delay_ms = value;
}
slot->ecclist_file = ril_config_get_string(file, group,
@@ -1174,6 +1447,27 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
g_free(slot->ecclist_file);
slot->ecclist_file = NULL;
}
slot->config.local_hangup_reasons = ril_config_get_ints(file,
group, RILCONF_LOCAL_HANGUP_REASONS);
strval = ril_config_ints_to_string(
slot->config.local_hangup_reasons, ',');
if (strval) {
DBG("%s: %s %s", group, RILCONF_LOCAL_HANGUP_REASONS,
strval);
g_free(strval);
}
slot->config.remote_hangup_reasons = ril_config_get_ints(file,
group, RILCONF_REMOTE_HANGUP_REASONS);
strval = ril_config_ints_to_string(
slot->config.remote_hangup_reasons, ',');
if (strval) {
DBG("%s: %s %s", group, RILCONF_REMOTE_HANGUP_REASONS,
strval);
g_free(strval);
}
} else {
DBG("no socket path in %s", group);
}
@@ -1186,8 +1480,12 @@ static void ril_plugin_delete_slot(struct ril_slot *slot)
ril_plugin_shutdown_slot(slot, TRUE);
ril_sim_info_unref(slot->sim_info);
ril_sim_settings_unref(slot->sim_settings);
gutil_ints_unref(slot->config.local_hangup_reasons);
gutil_ints_unref(slot->config.remote_hangup_reasons);
g_hash_table_destroy(slot->pub.errors);
g_free(slot->path);
g_free(slot->imei);
g_free(slot->imeisv);
g_free(slot->name);
g_free(slot->sockpath);
g_free(slot->sub);
@@ -1253,10 +1551,20 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
}
} else if (!strcmp(group, RILCONF_SETTINGS_GROUP)) {
/* Plugin configuration */
int value;
ril_config_get_flag(file, group,
RILCONF_SETTINGS_3GHANDOVER,
RIL_DATA_MANAGER_3GLTE_HANDOVER,
&ps->dm_flags);
if (ril_config_get_enum(file, group,
RILCONF_SETTINGS_SET_RADIO_CAP, &value,
"auto", RIL_SET_RADIO_CAP_AUTO,
"on", RIL_SET_RADIO_CAP_ENABLED,
"off", RIL_SET_RADIO_CAP_DISABLED, NULL)) {
ps->set_radio_cap = value;
}
}
}
@@ -1341,7 +1649,7 @@ static void ril_plugin_switch_user()
static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
{
if (slot->pub.enabled) {
DBG("%s enabled", slot->path + 1);
DBG("%s enabled", ril_slot_debug_prefix(slot));
ril_plugin_check_modem(slot);
}
}
@@ -1349,7 +1657,7 @@ static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
static void ril_plugin_update_disabled_slot(struct ril_slot *slot)
{
if (!slot->pub.enabled) {
DBG("%s disabled", slot->path + 1);
DBG("%s disabled", ril_slot_debug_prefix(slot));
ril_plugin_shutdown_slot(slot, FALSE);
ril_plugin_update_modem_paths_full(slot->plugin);
}
@@ -1580,10 +1888,7 @@ static void ril_plugin_debug_notify(struct ofono_debug_desc *desc)
static int ril_plugin_init(void)
{
char *enabled_slots;
struct ril_plugin_settings ps;
/* Default settings */
ps.dm_flags = RILMODEM_DEFAULT_DM_FLAGS;
struct ril_plugin_settings *ps;
DBG("");
GASSERT(!ril_plugin);
@@ -1610,10 +1915,12 @@ static int ril_plugin_init(void)
ril_plugin_switch_user();
ril_plugin = g_new0(struct ril_plugin_priv, 1);
ril_plugin->slots = ril_plugin_load_config(RILMODEM_CONF_FILE, &ps);
ps = &ril_plugin->settings;
ps->dm_flags = RILMODEM_DEFAULT_DM_FLAGS;
ril_plugin->slots = ril_plugin_load_config(RILMODEM_CONF_FILE, ps);
ril_plugin_init_slots(ril_plugin);
ril_plugin->dbus = ril_plugin_dbus_new(&ril_plugin->pub);
ril_plugin->data_manager = ril_data_manager_new(ps.dm_flags);
ril_plugin->data_manager = ril_data_manager_new(ps->dm_flags);
ril_plugin->display = mce_display_new();
ril_plugin->display_on = ril_plugin_display_on(ril_plugin->display);
@@ -1726,6 +2033,7 @@ static void ril_plugin_exit(void)
g_slist_free_full(ril_plugin->slots, ril_plugin_destroy_slot);
ril_plugin_dbus_free(ril_plugin->dbus);
ril_data_manager_unref(ril_plugin->data_manager);
ril_radio_caps_manager_unref(ril_plugin->caps_manager);
gutil_disconnect_handlers(ril_plugin->display,
ril_plugin->display_event_id, DISPLAY_EVENT_COUNT);
mce_display_unref(ril_plugin->display);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -48,10 +48,12 @@ typedef struct ril_slot_info const *ril_slot_info_ptr;
struct ril_slot_info {
const char *path;
const char *imei;
const char *imeisv;
const char *ecclist_file;
gboolean enabled;
gboolean sim_present;
const struct ril_slot_config *config;
GHashTable *errors;
};
struct ril_plugin {
@@ -68,6 +70,7 @@ struct ril_plugin {
struct ril_modem {
GRilIoChannel *io;
const char *imei;
const char *imeisv;
const char *log_prefix;
const char *ecclist_file;
struct ofono_modem *ofono;
@@ -123,6 +126,8 @@ void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
gboolean present);
void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
int index, const char *id, const char *message);
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -46,7 +46,7 @@ struct ril_plugin_dbus {
#define RIL_DBUS_PATH "/"
#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
#define RIL_DBUS_INTERFACE_VERSION (5)
#define RIL_DBUS_INTERFACE_VERSION (6)
#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
@@ -57,8 +57,11 @@ struct ril_plugin_dbus {
#define RIL_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
#define RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
#define RIL_DBUS_SIGNAL_READY_CHANGED "ReadyChanged"
#define RIL_DBUS_SIGNAL_MODEM_ERROR "ModemError"
#define RIL_DBUS_IMSI_AUTO "auto"
#define RIL_DBUS_ERROR_SIGNATURE "si"
static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
{
return slot->enabled;
@@ -167,6 +170,48 @@ static void ril_plugin_dbus_message_append_path_array(DBusMessage *msg,
ril_plugin_dbus_append_path_array(&iter, dbus, fn);
}
static void ril_plugin_dbus_append_modem_error(DBusMessageIter *it,
const char *id, dbus_uint32_t count)
{
DBusMessageIter sub;
dbus_message_iter_open_container(it, DBUS_TYPE_STRUCT, NULL, &sub);
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id);
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &count);
dbus_message_iter_close_container(it, &sub);
}
static void ril_plugin_dbus_append_modem_errors(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
DBusMessageIter slots;
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
"a(" RIL_DBUS_ERROR_SIGNATURE ")", &slots);
while (*ptr) {
const struct ril_slot_info *slot = *ptr++;
DBusMessageIter errors;
dbus_message_iter_open_container(&slots, DBUS_TYPE_ARRAY,
"(" RIL_DBUS_ERROR_SIGNATURE ")", &errors);
if (g_hash_table_size(slot->errors)) {
gpointer key, value;
GHashTableIter iter;
g_hash_table_iter_init(&iter, slot->errors);
while (g_hash_table_iter_next(&iter, &key, &value)) {
ril_plugin_dbus_append_modem_error(&errors,
key, GPOINTER_TO_INT(value));
}
}
dbus_message_iter_close_container(&slots, &errors);
}
dbus_message_iter_close_container(it, &slots);
}
static void ril_plugin_dbus_signal_path_array(struct ril_plugin_dbus *dbus,
const char *name, ril_plugin_dbus_slot_select_fn fn)
{
@@ -257,6 +302,19 @@ void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
DBUS_TYPE_INVALID);
}
void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
int index, const char *id, const char *message)
{
const char *path = dbus->plugin->slots[index]->path;
if (!message) message = "";
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
RIL_DBUS_SIGNAL_MODEM_ERROR,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_STRING, &id,
DBUS_TYPE_STRING, &message,
DBUS_TYPE_INVALID);
}
static DBusMessage *ril_plugin_dbus_reply_with_path_array(DBusMessage *msg,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
{
@@ -375,6 +433,13 @@ static void ril_plugin_dbus_append_all5(DBusMessageIter *it,
ril_plugin_dbus_append_boolean(it, dbus->plugin->ready);
}
static void ril_plugin_dbus_append_all6(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all5(it, dbus);
ril_plugin_dbus_append_modem_errors(it, dbus);
}
static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -410,6 +475,13 @@ static DBusMessage *ril_plugin_dbus_get_all5(DBusConnection *conn,
ril_plugin_dbus_append_all5);
}
static DBusMessage *ril_plugin_dbus_get_all6(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all6);
}
static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -554,6 +626,13 @@ static DBusMessage *ril_plugin_dbus_get_ready(DBusConnection *conn,
return reply;
}
static DBusMessage *ril_plugin_dbus_get_modem_errors(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_modem_errors);
}
static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -697,28 +776,44 @@ static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
* talking to.
*/
#define RIL_DBUS_VERSION_ARG {"version", "i"}
#define RIL_DBUS_AVAILABLE_MODEMS_ARG {"availableModems", "ao"}
#define RIL_DBUS_ENABLED_MODEMS_ARG {"enabledModems", "ao" }
#define RIL_DBUS_DEFAULT_DATA_SIM_ARG {"defaultDataSim", "s" }
#define RIL_DBUS_DEFAULT_VOICE_SIM_ARG {"defaultVoiceSim", "s" }
#define RIL_DBUS_DEFAULT_DATA_MODEM_ARG {"defaultDataModem", "s" }
#define RIL_DBUS_DEFAULT_VOICE_MODEM_ARG {"defaultVoiceModem" , "s"}
#define RIL_DBUS_PRESENT_SIMS_ARG {"presentSims" , "ab"}
#define RIL_DBUS_IMEI_ARG {"imei" , "as"}
#define RIL_DBUS_MMS_SIM_ARG {"mmsSim", "s"}
#define RIL_DBUS_MMS_MODEM_ARG {"mmsModem" , "s"}
#define RIL_DBUS_READY_ARG {"ready" , "b"}
#define RIL_DBUS_MODEM_ERRORS_ARG {"errors" , \
"aa(" RIL_DBUS_ERROR_SIGNATURE ")"}
#define RIL_DBUS_GET_ALL_ARGS \
{"version", "i" }, \
{"availableModems", "ao" }, \
{"enabledModems", "ao" }, \
{"defaultDataSim", "s" }, \
{"defaultVoiceSim", "s" }, \
{"defaultDataModem", "s" }, \
{"defaultVoiceModem" , "s"}
RIL_DBUS_VERSION_ARG, \
RIL_DBUS_AVAILABLE_MODEMS_ARG, \
RIL_DBUS_ENABLED_MODEMS_ARG, \
RIL_DBUS_DEFAULT_DATA_SIM_ARG, \
RIL_DBUS_DEFAULT_VOICE_SIM_ARG, \
RIL_DBUS_DEFAULT_DATA_MODEM_ARG, \
RIL_DBUS_DEFAULT_VOICE_MODEM_ARG
#define RIL_DBUS_GET_ALL2_ARGS \
RIL_DBUS_GET_ALL_ARGS, \
{"presentSims" , "ab"}
RIL_DBUS_PRESENT_SIMS_ARG
#define RIL_DBUS_GET_ALL3_ARGS \
RIL_DBUS_GET_ALL2_ARGS, \
{"imei" , "as"}
RIL_DBUS_IMEI_ARG
#define RIL_DBUS_GET_ALL4_ARGS \
RIL_DBUS_GET_ALL3_ARGS, \
{"mmsSim", "s" }, \
{"mmsModem" , "s"}
RIL_DBUS_MMS_SIM_ARG, \
RIL_DBUS_MMS_MODEM_ARG
#define RIL_DBUS_GET_ALL5_ARGS \
RIL_DBUS_GET_ALL4_ARGS, \
{"ready" , "b"}
RIL_DBUS_READY_ARG
#define RIL_DBUS_GET_ALL6_ARGS \
RIL_DBUS_GET_ALL5_ARGS, \
RIL_DBUS_MODEM_ERRORS_ARG
static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
@@ -735,42 +830,48 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_ASYNC_METHOD("GetAll5",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL5_ARGS),
ril_plugin_dbus_get_all5) },
{ GDBUS_ASYNC_METHOD("GetAll6",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL6_ARGS),
ril_plugin_dbus_get_all6) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
NULL, GDBUS_ARGS(RIL_DBUS_VERSION_ARG),
ril_plugin_dbus_get_interface_version) },
{ GDBUS_METHOD("GetAvailableModems",
NULL, GDBUS_ARGS({ "modems", "ao" }),
NULL, GDBUS_ARGS(RIL_DBUS_AVAILABLE_MODEMS_ARG),
ril_plugin_dbus_get_available_modems) },
{ GDBUS_METHOD("GetEnabledModems",
NULL, GDBUS_ARGS({ "modems", "ao" }),
NULL, GDBUS_ARGS(RIL_DBUS_ENABLED_MODEMS_ARG),
ril_plugin_dbus_get_enabled_modems) },
{ GDBUS_METHOD("GetPresentSims",
NULL, GDBUS_ARGS({ "presentSims", "ab" }),
NULL, GDBUS_ARGS(RIL_DBUS_PRESENT_SIMS_ARG),
ril_plugin_dbus_get_present_sims) },
{ GDBUS_ASYNC_METHOD("GetIMEI",
NULL, GDBUS_ARGS({ "imei", "as" }),
NULL, GDBUS_ARGS(RIL_DBUS_IMEI_ARG),
ril_plugin_dbus_get_imei) },
{ GDBUS_METHOD("GetDefaultDataSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG),
ril_plugin_dbus_get_default_data_sim) },
{ GDBUS_METHOD("GetDefaultVoiceSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG),
ril_plugin_dbus_get_default_voice_sim) },
{ GDBUS_METHOD("GetMmsSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG),
ril_plugin_dbus_get_mms_sim) },
{ GDBUS_METHOD("GetDefaultDataModem",
NULL, GDBUS_ARGS({ "path", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG),
ril_plugin_dbus_get_default_data_modem) },
{ GDBUS_METHOD("GetDefaultVoiceModem",
NULL, GDBUS_ARGS({ "path", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG),
ril_plugin_dbus_get_default_voice_modem) },
{ GDBUS_METHOD("GetMmsModem",
NULL, GDBUS_ARGS({ "path", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG),
ril_plugin_dbus_get_mms_modem) },
{ GDBUS_METHOD("GetReady",
NULL, GDBUS_ARGS({ "ready", "b" }),
NULL, GDBUS_ARGS(RIL_DBUS_READY_ARG),
ril_plugin_dbus_get_ready) },
{ GDBUS_METHOD("GetModemErrors",
NULL, GDBUS_ARGS(RIL_DBUS_MODEM_ERRORS_ARG),
ril_plugin_dbus_get_modem_errors) },
{ GDBUS_METHOD("SetEnabledModems",
GDBUS_ARGS({ "modems", "ao" }), NULL,
ril_plugin_dbus_set_enabled_modems) },
@@ -788,24 +889,28 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
static const GDBusSignalTable ril_plugin_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
GDBUS_ARGS({ "modems", "ao" })) },
GDBUS_ARGS(RIL_DBUS_ENABLED_MODEMS_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
GDBUS_ARGS({"index", "i" },
{"present" , "b"})) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_READY_CHANGED,
GDBUS_ARGS({ "ready", "b" })) },
GDBUS_ARGS(RIL_DBUS_READY_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MODEM_ERROR,
GDBUS_ARGS({"path","o"},
{"error_id", "s"},
{"message", "s"})) },
{ }
};

View File

@@ -0,0 +1,832 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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_radio_caps.h"
#include "ril_radio.h"
#include "ril_network.h"
#include "ril_sim_settings.h"
#include "ril_data.h"
#include "ril_log.h"
#include <grilio_queue.h>
#include <grilio_channel.h>
#include <grilio_parser.h>
#include <grilio_request.h>
#define SET_CAPS_TIMEOUT_MS (5*1000)
#define GET_CAPS_TIMEOUT_MS (5*1000)
#define GET_CAPS_RETRIES 60
/*
* This code is doing something similar to what
* com.android.internal.telephony.ProxyController
* is doing.
*/
struct ril_radio_caps {
gint ref_count;
guint slot;
char *log_prefix;
GRilIoQueue *q;
GRilIoChannel *io;
gulong pref_mode_event_id;
gulong max_pref_mode_event_id;
gulong radio_event_id;
gulong ril_event_id;
int tx_id;
struct ril_radio *radio;
struct ril_network *network;
struct ril_radio_caps_manager *mgr;
struct ril_radio_capability cap;
struct ril_radio_capability old_cap;
struct ril_radio_capability new_cap;
};
struct ril_radio_caps_manager {
gint ref_count;
GPtrArray *caps_list;
guint check_id;
int tx_pending;
int tx_id;
int tx_phase_index;
gboolean tx_failed;
struct ril_data_manager *data_manager;
};
struct ril_radio_caps_check_data {
ril_radio_caps_check_cb cb;
void *data;
};
struct ril_radio_caps_request_tx_phase {
const char *name;
enum ril_radio_capability_phase phase;
enum ril_radio_capability_status status;
gboolean send_new_cap;
};
static const struct ril_radio_caps_request_tx_phase
ril_radio_caps_tx_phase[] = {
{ "START", RC_PHASE_START, RC_STATUS_NONE, FALSE },
{ "APPLY", RC_PHASE_APPLY, RC_STATUS_NONE, TRUE },
{ "FINISH", RC_PHASE_FINISH, RC_STATUS_SUCCESS, FALSE }
};
static const struct ril_radio_caps_request_tx_phase
ril_radio_caps_fail_phase =
{ "ABORT", RC_PHASE_FINISH, RC_STATUS_FAIL, FALSE };
#define DBG_(caps, fmt, args...) DBG("%s" fmt, (caps)->log_prefix, ##args)
static void ril_radio_caps_manager_next_phase
(struct ril_radio_caps_manager *self);
static void ril_radio_caps_manager_schedule_check
(struct ril_radio_caps_manager *self);
static gboolean ril_radio_caps_parse(const char *log_prefix,
const void *data, guint len, struct ril_radio_capability *cap)
{
GRilIoParser rilp;
guint32 version, tx, phase, rat;
memset(cap, 0, sizeof(*cap));
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &version) &&
grilio_parser_get_uint32(&rilp, &tx) &&
grilio_parser_get_uint32(&rilp, &phase) &&
grilio_parser_get_uint32(&rilp, &rat)) {
guint32 status;
char *uuid = grilio_parser_get_utf8(&rilp);
if (grilio_parser_get_uint32(&rilp, &status) &&
grilio_parser_at_end(&rilp)) {
DBG("%sversion=%d,tx=%d,phase=%d,rat=0x%x,"
"uuid=%s,status=%d", log_prefix, version,
tx, phase, rat, uuid, status);
cap->version = version;
cap->session = tx;
cap->phase = phase;
cap->rat = rat;
cap->status = status;
if (uuid) {
strncpy(cap->logicalModemUuid, uuid,
G_N_ELEMENTS(cap->logicalModemUuid));
g_free(uuid);
}
return TRUE;
}
g_free(uuid);
}
return FALSE;
}
static void ril_radio_caps_check_done(GRilIoChannel* io, int ril_status,
const void* data, guint len, void* user_data)
{
struct ril_radio_caps_check_data *check = user_data;
const struct ril_radio_capability *result = NULL;
struct ril_radio_capability cap;
if (ril_status == RIL_E_SUCCESS &&
ril_radio_caps_parse("", data, len, &cap)) {
GASSERT(cap.rat);
if (cap.rat) {
result = &cap;
}
}
check->cb(result, check->data);
}
static gboolean ril_radio_caps_check_retry(GRilIoRequest* request,
int ril_status, const void* resp, guint len, void* user_data)
{
/*
* RIL_E_REQUEST_NOT_SUPPORTED is not listed among the valid
* RIL_REQUEST_GET_RADIO_CAPABILITY errors in ril.h but some
* RILs (e.g. Jolla C) return is anyway.
*/
switch (ril_status) {
case RIL_E_SUCCESS:
case RIL_E_REQUEST_NOT_SUPPORTED:
case RIL_E_OPERATION_NOT_ALLOWED:
return FALSE;
default:
return TRUE;
}
}
guint ril_radio_caps_check(GRilIoChannel *io, ril_radio_caps_check_cb cb,
void *data)
{
guint id;
GRilIoRequest *req = grilio_request_new();
struct ril_radio_caps_check_data *check =
g_new0(struct ril_radio_caps_check_data, 1);
check->cb = cb;
check->data = data;
grilio_request_set_retry(req, GET_CAPS_TIMEOUT_MS, GET_CAPS_RETRIES);
grilio_request_set_retry_func(req, ril_radio_caps_check_retry);
id = grilio_channel_send_request_full(io, req,
RIL_REQUEST_GET_RADIO_CAPABILITY,
ril_radio_caps_check_done, g_free, check);
grilio_request_unref(req);
return id;
}
/*==========================================================================*
* ril_radio_caps
*==========================================================================*/
static enum ofono_radio_access_mode ril_radio_caps_access_mode
(const struct ril_radio_caps *caps)
{
const enum ril_radio_access_family raf = caps->cap.rat;
if (raf & (RAF_LTE | RAF_LTE_CA)) {
return OFONO_RADIO_ACCESS_MODE_LTE;
} else if (raf & RAF_UMTS) {
return OFONO_RADIO_ACCESS_MODE_UMTS;
} else if (raf & (RAF_EDGE | RAF_GPRS | RAF_GSM)) {
return OFONO_RADIO_ACCESS_MODE_GSM;
} else {
return OFONO_RADIO_ACCESS_MODE_ANY;
}
}
static gboolean ril_radio_caps_pref_mode_limit
(const struct ril_radio_caps *caps)
{
struct ril_network *network = caps->network;
struct ril_sim_settings *settings = network->settings;
if (network->max_pref_mode == settings->pref_mode) {
return network->max_pref_mode;
} else if (network->max_pref_mode == OFONO_RADIO_ACCESS_MODE_ANY) {
return settings->pref_mode;
} else {
return network->max_pref_mode;
}
}
static gboolean ril_radio_caps_ok(const struct ril_radio_caps *caps,
const enum ofono_radio_access_mode limit)
{
return caps->radio->state != RADIO_STATE_ON ||
limit == OFONO_RADIO_ACCESS_MODE_ANY ||
ril_radio_caps_access_mode(caps) <= limit;
}
static void ril_radio_caps_radio_event(struct ril_radio *radio, void *arg)
{
struct ril_radio_caps *self = arg;
DBG_(self, "");
ril_radio_caps_manager_schedule_check(self->mgr);
}
static void ril_radio_caps_settings_event(struct ril_sim_settings *settings,
void *arg)
{
struct ril_radio_caps *self = arg;
DBG_(self, "");
ril_radio_caps_manager_schedule_check(self->mgr);
}
static void ril_radio_caps_network_event(struct ril_network *network,
void *arg)
{
struct ril_radio_caps *self = arg;
DBG_(self, "");
ril_radio_caps_manager_schedule_check(self->mgr);
}
static void ril_radio_caps_changed_cb(GRilIoChannel *io, guint code,
const void *data, guint len, void *arg)
{
struct ril_radio_caps *self = arg;
DBG_(self, "");
GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
if (ril_radio_caps_parse(self->log_prefix, data, len, &self->cap)) {
ril_radio_caps_manager_schedule_check(self->mgr);
}
}
static void ril_radio_caps_finish_init(struct ril_radio_caps *self)
{
GASSERT(ril_radio_caps_access_mode(self));
/* Register for update notifications */
self->ril_event_id = grilio_channel_add_unsol_event_handler(self->io,
ril_radio_caps_changed_cb, RIL_UNSOL_RADIO_CAPABILITY, self);
/* Schedule capability check */
ril_radio_caps_manager_schedule_check(self->mgr);
}
static void ril_radio_caps_initial_query_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_radio_caps *self = user_data;
if (ril_status == RIL_E_SUCCESS) {
ril_radio_caps_parse(self->log_prefix, data, len, &self->cap);
}
if (self->cap.rat) {
ril_radio_caps_finish_init(self);
} else {
DBG_(self, "failed to query radio capabilities");
}
}
static gint ril_caps_compare_cb(gconstpointer a, gconstpointer b)
{
const struct ril_radio_caps *c1 = *(void**)a;
const struct ril_radio_caps *c2 = *(void**)b;
return c1->slot < c2->slot ? (-1) : c1->slot > c2->slot ? 1 : 0;
}
static void ril_radio_caps_free(struct ril_radio_caps *self)
{
struct ril_radio_caps_manager *mgr = self->mgr;
struct ril_sim_settings *settings = self->network->settings;
ril_network_remove_handler(self->network, self->max_pref_mode_event_id);
ril_sim_settings_remove_handler(settings, self->pref_mode_event_id);
ril_radio_remove_handler(self->radio, self->radio_event_id);
g_ptr_array_remove(mgr->caps_list, self);
ril_radio_caps_manager_unref(mgr);
grilio_queue_cancel_all(self->q, FALSE);
grilio_queue_unref(self->q);
grilio_channel_remove_handlers(self->io, &self->ril_event_id, 1);
grilio_channel_unref(self->io);
ril_radio_unref(self->radio);
ril_network_unref(self->network);
g_free(self->log_prefix);
g_slice_free(struct ril_radio_caps, self);
}
struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
const char *log_prefix, GRilIoChannel *io,
struct ril_radio *radio, struct ril_network *network,
const struct ril_slot_config *config,
const struct ril_radio_capability *cap)
{
GASSERT(mgr);
if (G_LIKELY(mgr)) {
struct ril_sim_settings *settings = network->settings;
struct ril_radio_caps *self =
g_slice_new0(struct ril_radio_caps);
self->ref_count = 1;
self->slot = config->slot;
self->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
self->q = grilio_queue_new(io);
self->io = grilio_channel_ref(io);
self->mgr = ril_radio_caps_manager_ref(mgr);
self->radio = ril_radio_ref(radio);
self->radio_event_id = ril_radio_add_state_changed_handler(
radio, ril_radio_caps_radio_event, self);
self->network = ril_network_ref(network);
self->pref_mode_event_id =
ril_sim_settings_add_pref_mode_changed_handler(
settings, ril_radio_caps_settings_event, self);
self->max_pref_mode_event_id =
ril_network_add_max_pref_mode_changed_handler(
network, ril_radio_caps_network_event, self);
/* Order list elements according to slot numbers */
g_ptr_array_add(mgr->caps_list, self);
g_ptr_array_sort(mgr->caps_list, ril_caps_compare_cb);
if (cap) {
/* Current capabilities are provided by the caller */
self->cap = *cap;
ril_radio_caps_finish_init(self);
} else {
/* Need to query current capabilities */
GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, GET_CAPS_TIMEOUT_MS,
GET_CAPS_RETRIES);
grilio_queue_send_request_full(self->q, req,
RIL_REQUEST_GET_RADIO_CAPABILITY,
ril_radio_caps_initial_query_cb,
NULL, self);
grilio_request_unref(req);
}
return self;
}
return NULL;
}
struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *self)
{
if (G_LIKELY(self)) {
GASSERT(self->ref_count > 0);
g_atomic_int_inc(&self->ref_count);
}
return self;
}
void ril_radio_caps_unref(struct ril_radio_caps *self)
{
if (G_LIKELY(self)) {
GASSERT(self->ref_count > 0);
if (g_atomic_int_dec_and_test(&self->ref_count)) {
ril_radio_caps_free(self);
}
}
}
/*==========================================================================*
* ril_radio_caps_manager
*==========================================================================*/
/**
* Checks that all radio caps have been initialized (i.e. all the initial
* GET_RADIO_CAPABILITY requests have completed) and there's no transaction
* in progress.
*/
static gboolean ril_radio_caps_manager_ready
(struct ril_radio_caps_manager *self)
{
if (self->caps_list && !self->tx_pending) {
const GPtrArray *list = self->caps_list;
guint i;
for (i = 0; i < list->len; i++) {
const struct ril_radio_caps *caps = list->pdata[i];
if (caps->radio->state == RADIO_STATE_ON &&
!caps->cap.rat) {
DBG_(caps, "not ready");
return FALSE;
}
DBG_(caps, "radio=%s,raf=0x%x(%s),uuid=%s,limit=%s",
(caps->radio->state == RADIO_STATE_ON) ?
"on" : "off", caps->cap.rat,
ofono_radio_access_mode_to_string
(ril_radio_caps_access_mode(caps)),
caps->cap.logicalModemUuid,
ofono_radio_access_mode_to_string
(ril_radio_caps_pref_mode_limit(caps)));
}
return TRUE;
}
return FALSE;
}
static int ril_radio_caps_manager_first_mismatch
(struct ril_radio_caps_manager *self)
{
guint i;
const GPtrArray *list = self->caps_list;
for (i = 0; i < list->len; i++) {
const struct ril_radio_caps *caps = list->pdata[i];
if (!ril_radio_caps_ok(caps,
ril_radio_caps_pref_mode_limit(caps))) {
return i;
}
}
DBG("nothing to do");
return -1;
}
static int ril_radio_caps_manager_find_mismatch
(struct ril_radio_caps_manager *self,
const guint *order, const gboolean *done)
{
guint i;
const GPtrArray *list = self->caps_list;
for (i = 0; i < list->len; i++) {
if (!done[i] && !ril_radio_caps_ok(list->pdata[order[i]],
ril_radio_caps_pref_mode_limit(list->pdata[i]))) {
return i;
}
}
return -1;
}
static int ril_radio_caps_manager_find_match
(struct ril_radio_caps_manager *self,
guint from, const guint *order,
const gboolean *done)
{
guint i;
const GPtrArray *list = self->caps_list;
const struct ril_radio_caps *src = list->pdata[order[from]];
for (i = 0; i < list->len; i++) {
if (!done[i] && ril_radio_caps_ok(src,
ril_radio_caps_pref_mode_limit(list->pdata[i]))) {
return i;
}
}
return -1;
}
/**
* Updates the order of capabilities (i.e. which slots should get
* assigned which capabilities). Returns FALSE if nothing can be
* done due to impossible constraints. If everything is already
* fine, we shouldn't even get here - the caller makes sure of that.
*/
static gboolean ril_radio_caps_manager_update_caps
(struct ril_radio_caps_manager *self, int mismatch)
{
guint i;
int from, to;
gboolean ok = TRUE;
const GPtrArray *list = self->caps_list;
guint *order = g_new(guint, list->len);
gboolean *done = g_new(gboolean, list->len);
for (i = 0; i < list->len; i++) {
const struct ril_radio_caps *caps = list->pdata[i];
/* Not touching powered off modems */
done[i] = (caps->radio->state != RADIO_STATE_ON);
order[i] = i;
}
/* The first mismatch is already known */
to = ril_radio_caps_manager_find_match(self, mismatch, order, done);
if (to < 0) {
ok = FALSE;
} else {
DBG("%d <-> %d", mismatch, to);
order[mismatch] = to;
order[to] = mismatch;
done[to] = TRUE;
}
/* Handle other mismatched slots (if any) */
while (ok && (from = ril_radio_caps_manager_find_mismatch(self, order,
done)) >= 0) {
to = ril_radio_caps_manager_find_match(self, from, order,
done);
if (to < 0) {
ok = FALSE;
} else {
const guint tmp = order[from];
DBG("%d <-> %d", order[from], order[to]);
order[from] = order[to];
order[to] = tmp;
done[to] = TRUE;
}
}
if (ok) {
for (i = 0; i < list->len; i++) {
struct ril_radio_caps *caps = list->pdata[i];
caps->new_cap = caps->old_cap = caps->cap;
}
/* Update the rafs */
for (i = 0; i < list->len; i++) {
struct ril_radio_caps *src = list->pdata[i];
struct ril_radio_caps *dest = list->pdata[order[i]];
dest->new_cap = src->cap;
}
}
g_free(order);
g_free(done);
return ok;
}
static void ril_radio_caps_manager_issue_requests
(struct ril_radio_caps_manager *self,
const struct ril_radio_caps_request_tx_phase *phase,
GRilIoChannelResponseFunc handler)
{
guint i;
const GPtrArray *list = self->caps_list;
DBG("%s transaction %d", phase->name, self->tx_id);
for (i = 0; i < list->len; i++) {
struct ril_radio_caps *caps = list->pdata[i];
/* Ignore the modems not associated with this transaction */
if (caps->tx_id == self->tx_id) {
GRilIoRequest *req = grilio_request_new();
const struct ril_radio_capability *cap =
phase->send_new_cap ? &caps->new_cap :
&caps->old_cap;
/* Encode and send the request */
grilio_request_append_int32(req,
RIL_RADIO_CAPABILITY_VERSION);
grilio_request_append_int32(req, self->tx_id);
grilio_request_append_int32(req, phase->phase);
grilio_request_append_int32(req, cap->rat);
grilio_request_append_utf8(req, cap->logicalModemUuid);
grilio_request_append_int32(req, phase->status);
grilio_request_set_timeout(req, SET_CAPS_TIMEOUT_MS);
grilio_queue_send_request_full(caps->q, req,
RIL_REQUEST_SET_RADIO_CAPABILITY,
handler, NULL, caps);
grilio_request_unref(req);
/* Count it */
self->tx_pending++;
}
}
}
static void ril_radio_caps_manager_next_transaction
(struct ril_radio_caps_manager *self)
{
guint i;
const GPtrArray *list = self->caps_list;
for (i = 0; i < list->len; i++) {
struct ril_radio_caps *caps = list->pdata[i];
grilio_queue_cancel_all(caps->q, FALSE);
}
self->tx_pending = 0;
self->tx_failed = FALSE;
self->tx_phase_index = -1;
self->tx_id++;
if (self->tx_id <= 0) self->tx_id = 1;
}
static void ril_radio_caps_manager_abort_cb(GRilIoChannel *io,
int ril_status, const void *data, guint len, void *user_data)
{
struct ril_radio_caps *caps = user_data;
struct ril_radio_caps_manager *self = caps->mgr;
GASSERT(self->tx_pending > 0);
if (!(--self->tx_pending)) {
DBG("transaction aborted");
}
}
static void ril_radio_caps_manager_abort_transaction
(struct ril_radio_caps_manager *self)
{
guint i;
const GPtrArray *list = self->caps_list;
const int prev_tx_id = self->tx_id;
/* Generate new transaction id */
DBG("aborting transaction %d", prev_tx_id);
ril_radio_caps_manager_next_transaction(self);
/* Re-associate the modems with the new transaction */
for (i = 0; i < list->len; i++) {
struct ril_radio_caps *caps = list->pdata[i];
if (caps->tx_id == prev_tx_id) {
caps->tx_id = self->tx_id;
}
}
/*
* Issue a FINISH with RC_STATUS_FAIL. That's what
* com.android.internal.telephony.ProxyController does
* when something goes wrong.
*/
ril_radio_caps_manager_issue_requests(self, &ril_radio_caps_fail_phase,
ril_radio_caps_manager_abort_cb);
}
static void ril_radio_caps_manager_next_phase_cb(GRilIoChannel *io,
int ril_status, const void *data, guint len, void *user_data)
{
struct ril_radio_caps *caps = user_data;
struct ril_radio_caps_manager *self = caps->mgr;
gboolean ok = FALSE;
GASSERT(self->tx_pending > 0);
if (ril_status == RIL_E_SUCCESS) {
struct ril_radio_capability cap;
if (ril_radio_caps_parse(caps->log_prefix, data, len, &cap) &&
cap.status == RC_STATUS_SUCCESS) {
caps->cap = cap;
ok = TRUE;
}
}
if (!ok) {
if (!self->tx_failed) {
self->tx_failed = TRUE;
DBG("transaction %d failed", self->tx_id);
}
}
if (!(--self->tx_pending)) {
if (self->tx_failed) {
ril_radio_caps_manager_abort_transaction(self);
} else {
ril_radio_caps_manager_next_phase(self);
}
}
}
static void ril_radio_caps_manager_next_phase
(struct ril_radio_caps_manager *self)
{
/* Note: -1 > 2 if 2 is unsigned (which turns -1 into 4294967295) */
const int max_index = G_N_ELEMENTS(ril_radio_caps_tx_phase) - 1;
GASSERT(!self->tx_pending);
if (self->tx_phase_index >= max_index) {
guint i;
const GPtrArray *list = self->caps_list;
DBG("transaction %d is done", self->tx_id);
ril_radio_caps_manager_schedule_check(self);
ril_data_manager_assert_data_on(self->data_manager);
for (i = 0; i < list->len; i++) {
struct ril_radio_caps *caps = list->pdata[i];
ril_network_assert_pref_mode(caps->network, FALSE);
}
} else {
const struct ril_radio_caps_request_tx_phase *phase =
ril_radio_caps_tx_phase +
(++self->tx_phase_index);
ril_radio_caps_manager_issue_requests(self, phase,
ril_radio_caps_manager_next_phase_cb);
}
}
static void ril_radio_caps_manager_check(struct ril_radio_caps_manager *self)
{
DBG("");
if (ril_radio_caps_manager_ready(self)) {
const int first = ril_radio_caps_manager_first_mismatch(self);
if (first >= 0 &&
ril_radio_caps_manager_update_caps(self, first)) {
guint i;
const GPtrArray *list = self->caps_list;
/* Start the new request transaction */
ril_radio_caps_manager_next_transaction(self);
DBG("new transaction %d", self->tx_id);
/* Ignore the modems that are powered off */
for (i = 0; i < list->len; i++) {
struct ril_radio_caps *caps = list->pdata[i];
if (caps->radio->state == RADIO_STATE_ON) {
/* Associate it with the transaction */
caps->tx_id = self->tx_id;
}
}
ril_radio_caps_manager_next_phase(self);
}
}
}
static gboolean ril_radio_caps_manager_check_cb(gpointer user_data)
{
struct ril_radio_caps_manager *self = user_data;
GASSERT(self->check_id);
self->check_id = 0;
ril_radio_caps_manager_check(self);
return G_SOURCE_REMOVE;
}
static void ril_radio_caps_manager_schedule_check
(struct ril_radio_caps_manager *self)
{
if (!self->check_id && !self->tx_pending) {
self->check_id = g_idle_add(ril_radio_caps_manager_check_cb,
self);
}
}
static void ril_radio_caps_manager_free(struct ril_radio_caps_manager *self)
{
GASSERT(!self->caps_list->len);
g_ptr_array_free(self->caps_list, TRUE);
if (self->check_id) {
g_source_remove(self->check_id);
}
ril_data_manager_unref(self->data_manager);
g_slice_free(struct ril_radio_caps_manager, self);
}
struct ril_radio_caps_manager *ril_radio_caps_manager_new
(struct ril_data_manager *dm)
{
struct ril_radio_caps_manager *self =
g_slice_new0(struct ril_radio_caps_manager);
self->ref_count = 1;
self->caps_list = g_ptr_array_new();
self->tx_phase_index = -1;
self->data_manager = ril_data_manager_ref(dm);
return self;
}
struct ril_radio_caps_manager *ril_radio_caps_manager_ref
(struct ril_radio_caps_manager *self)
{
if (G_LIKELY(self)) {
GASSERT(self->ref_count > 0);
g_atomic_int_inc(&self->ref_count);
}
return self;
}
void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *self)
{
if (G_LIKELY(self)) {
GASSERT(self->ref_count > 0);
if (g_atomic_int_dec_and_test(&self->ref_count)) {
ril_radio_caps_manager_free(self);
}
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,58 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_RADIO_CAPS_H
#define RIL_RADIO_CAPS_H
#include "ril_types.h"
struct ril_data_manager;
struct ril_radio_caps;
struct ril_radio_caps_manager;
struct ril_radio_capability;
/* ril_radio_capability pointer is NULL if functionality is unsupported */
typedef void (*ril_radio_caps_check_cb)(const struct ril_radio_capability *cap,
void *user_data);
/* The check can be cancelled with grilio_channel_cancel_request */
guint ril_radio_caps_check(GRilIoChannel *io, ril_radio_caps_check_cb cb,
void *user_data);
/* There should be a single ril_radio_caps_manager shared by all all modems */
struct ril_radio_caps_manager *ril_radio_caps_manager_new
(struct ril_data_manager *dm);
struct ril_radio_caps_manager *ril_radio_caps_manager_ref
(struct ril_radio_caps_manager *mgr);
void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr);
/* And one ril_radio_caps object per modem */
struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
const char *log_prefix, GRilIoChannel *io,
struct ril_radio *radio, struct ril_network *net,
const struct ril_slot_config *config,
const struct ril_radio_capability *cap /* optional */);
struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps);
void ril_radio_caps_unref(struct ril_radio_caps *caps);
#endif /* RIL_RADIO_CAPS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -113,15 +113,11 @@ static gboolean ril_radio_settings_query_available_rats_cb(gpointer data)
struct ofono_error error;
struct ril_radio_settings_cbd *cbd = data;
struct ril_radio_settings *rsd = cbd->rsd;
guint rats = OFONO_RADIO_ACCESS_MODE_GSM | OFONO_RADIO_ACCESS_MODE_UMTS;
if (cbd->rsd->settings->enable_4g) {
rats |= OFONO_RADIO_ACCESS_MODE_LTE;
}
GASSERT(cbd->rsd->source_id);
GASSERT(rsd->source_id);
rsd->source_id = 0;
cbd->cb.available_rats(ril_error_ok(&error), rats, cbd->data);
cbd->cb.available_rats(ril_error_ok(&error), rsd->settings->techs,
cbd->data);
return G_SOURCE_REMOVE;
}
@@ -132,8 +128,8 @@ static void ril_radio_settings_query_available_rats(
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
DBG_(rsd, "");
ril_radio_settings_later(rsd, ril_radio_settings_query_available_rats_cb,
cb, data);
ril_radio_settings_later(rsd,
ril_radio_settings_query_available_rats_cb, cb, data);
}
static gboolean ril_radio_settings_register(gpointer user_data)

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -65,6 +65,13 @@
*
* The same applies to the app_type.
*/
enum ril_sim_card_event {
SIM_CARD_STATUS_EVENT,
SIM_CARD_APP_EVENT,
SIM_CARD_EVENT_COUNT
};
struct ril_sim {
GRilIoChannel *io;
GRilIoQueue *q;
@@ -76,7 +83,8 @@ struct ril_sim {
gboolean empty_pin_query_allowed;
gboolean inserted;
guint idle_id;
gulong card_status_id;
gulong card_event_id[SIM_CARD_EVENT_COUNT];
guint query_pin_retries_id;
const char *log_prefix;
char *allocated_log_prefix;
@@ -85,6 +93,7 @@ struct ril_sim {
ofono_sim_passwd_cb_t query_passwd_state_cb;
void *query_passwd_state_cb_data;
guint query_passwd_state_timeout_id;
gulong query_passwd_state_sim_status_refresh_id;
};
struct ril_sim_io_response {
@@ -100,7 +109,6 @@ struct ril_sim_cbd {
ofono_sim_read_cb_t read;
ofono_sim_write_cb_t write;
ofono_sim_imsi_cb_t imsi;
ofono_sim_pin_retries_cb_t retries;
ofono_query_facility_lock_cb_t query_facility_lock;
gpointer ptr;
} cb;
@@ -119,6 +127,49 @@ struct ril_sim_pin_cbd {
gulong card_status_id;
};
struct ril_sim_retry_query_cbd {
struct ril_sim *sd;
ofono_sim_pin_retries_cb_t cb;
void *data;
guint query_index;
};
struct ril_sim_retry_query {
const char *name;
enum ofono_sim_password_type passwd_type;
guint req_code;
GRilIoRequest *(*new_req)(struct ril_sim *sd);
};
static GRilIoRequest *ril_sim_empty_sim_pin_req(struct ril_sim *sd);
static GRilIoRequest *ril_sim_empty_sim_puk_req(struct ril_sim *sd);
static void ril_sim_query_retry_count_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data);
static const struct ril_sim_retry_query ril_sim_retry_query_types[] = {
{
"pin",
OFONO_SIM_PASSWORD_SIM_PIN,
RIL_REQUEST_ENTER_SIM_PIN,
ril_sim_empty_sim_pin_req
},{
"pin2",
OFONO_SIM_PASSWORD_SIM_PIN2,
RIL_REQUEST_ENTER_SIM_PIN2,
ril_sim_empty_sim_pin_req
},{
"puk",
OFONO_SIM_PASSWORD_SIM_PUK,
RIL_REQUEST_ENTER_SIM_PUK,
ril_sim_empty_sim_puk_req
},{
"puk2",
OFONO_SIM_PASSWORD_SIM_PUK2,
RIL_REQUEST_ENTER_SIM_PUK2,
ril_sim_empty_sim_puk_req
}
};
#define DBG_(sd,fmt,args...) DBG("%s" fmt, (sd)->log_prefix, ##args)
#define ril_sim_cbd_free g_free
@@ -379,20 +430,11 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
DBG_(sd, "");
/*
* In case sim card has been removed prior to this callback has been
* called we must not call the core call back method as otherwise the
* core will crash.
*/
if (!sd->inserted) {
ofono_error("No SIM card");
return;
}
ril_error_init_failure(&error);
res = ril_sim_parse_io_response(data, len);
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
if (!sd->inserted) {
DBG_(sd, "No SIM card");
} else if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
gboolean ok = FALSE;
guchar access[3] = { 0x00, 0x00, 0x00 };
guchar file_status = EF_STATUS_VALID;
@@ -700,6 +742,12 @@ static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
sd->query_passwd_state_timeout_id = 0;
}
if (sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
sd->query_passwd_state_sim_status_refresh_id = 0;
}
if (sd->query_passwd_state_cb) {
ofono_sim_passwd_cb_t cb = sd->query_passwd_state_cb;
void *data = sd->query_passwd_state_cb_data;
@@ -718,6 +766,34 @@ static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
}
}
static void ril_sim_check_perm_lock(struct ril_sim *sd)
{
struct ril_sim_card *sc = sd->card;
/*
* Zero number of retries in the PUK state indicates to the ofono
* client that the card is permanently locked. This is different
* from the case when the number of retries is negative (which
* means that PUK is required but the number of remaining attempts
* is not available).
*/
if (sc->app && sc->app->app_state == RIL_APPSTATE_PUK &&
sc->app->pin1_state == RIL_PINSTATE_ENABLED_PERM_BLOCKED) {
/*
* It makes no sense for RIL to return non-zero number of
* remaining attempts in PERM_LOCKED state. So when we get
* here, the number of retries has to be negative (unknown)
* or zero. Otherwise, something must be broken.
*/
GASSERT(sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] <= 0);
if (sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] < 0) {
sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = 0;
DBG_(sd, "SIM card is locked");
}
}
}
static void ril_sim_invalidate_passwd_state(struct ril_sim *sd)
{
guint i;
@@ -727,10 +803,16 @@ static void ril_sim_invalidate_passwd_state(struct ril_sim *sd)
sd->retries[i] = -1;
}
ril_sim_check_perm_lock(sd);
ril_sim_finish_passwd_state_query(sd, OFONO_SIM_PASSWORD_INVALID);
}
static void ril_sim_status_cb(struct ril_sim_card *sc, void *user_data)
static void ril_sim_app_changed_cb(struct ril_sim_card *sc, void *user_data)
{
ril_sim_check_perm_lock((struct ril_sim *)user_data);
}
static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
{
struct ril_sim *sd = user_data;
@@ -739,6 +821,7 @@ static void ril_sim_status_cb(struct ril_sim_card *sc, void *user_data)
if (sc->app) {
enum ofono_sim_password_type ps;
ril_sim_check_perm_lock(sd);
if (!sd->inserted) {
sd->inserted = TRUE;
ofono_info("SIM card OK");
@@ -773,13 +856,29 @@ static int ril_sim_parse_retry_count(const void *data, guint len)
return retry_count;
}
static GRilIoRequest *ril_sim_enter_sim_req(struct ril_sim *sd, const char *pw)
static GRilIoRequest *ril_sim_enter_sim_pin_req(struct ril_sim *sd,
const char *pin)
{
const char *app_id = ril_sim_app_id(sd);
if (app_id) {
GRilIoRequest *req = grilio_request_new();
grilio_request_append_int32(req, ENTER_SIM_PIN_PARAMS);
grilio_request_append_utf8(req, pw);
grilio_request_append_utf8(req, pin);
grilio_request_append_utf8(req, app_id);
return req;
}
return NULL;
}
static GRilIoRequest *ril_sim_enter_sim_puk_req(struct ril_sim *sd,
const char *puk, const char *pin)
{
const char *app_id = ril_sim_app_id(sd);
if (app_id) {
GRilIoRequest *req = grilio_request_new();
grilio_request_append_int32(req, ENTER_SIM_PUK_PARAMS);
grilio_request_append_utf8(req, puk);
grilio_request_append_utf8(req, pin);
grilio_request_append_utf8(req, app_id);
return req;
}
@@ -790,63 +889,90 @@ static GRilIoRequest *ril_sim_enter_sim_req(struct ril_sim *sd, const char *pw)
* Some RIL implementations allow to query the retry count
* by sending the empty pin in any state.
*/
static void ril_sim_query_pin2_retries_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
static GRilIoRequest *ril_sim_empty_sim_pin_req(struct ril_sim *sd)
{
struct ril_sim_cbd *cbd = user_data;
struct ril_sim *sd = cbd->sd;
ofono_sim_pin_retries_cb_t cb = cbd->cb.retries;
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
const int retry_count = ril_sim_parse_retry_count(data, len);
DBG_(sd, "pin2 retry_count=%d", retry_count);
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = retry_count;
} else {
ofono_error("pin2 retry query is not supported");
sd->empty_pin_query_allowed = FALSE;
}
cb(ril_error_ok(&error), sd->retries, cbd->data);
return ril_sim_enter_sim_pin_req(sd, "");
}
static gboolean ril_sim_query_pin2_retry_count(struct ril_sim *sd,
static GRilIoRequest *ril_sim_empty_sim_puk_req(struct ril_sim *sd)
{
return ril_sim_enter_sim_puk_req(sd, "", "");
}
static struct ril_sim_retry_query_cbd *ril_sim_retry_query_cbd_new(
struct ril_sim *sd, guint query_index,
ofono_sim_pin_retries_cb_t cb, void *data)
{
if (sd->empty_pin_query_allowed &&
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN2] < 0) {
GRilIoRequest *req = ril_sim_enter_sim_req(sd, "");
if (req) {
DBG_(sd, "querying pin2 retry count...");
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PIN2,
ril_sim_query_pin2_retries_cb,
ril_sim_cbd_free,
ril_sim_cbd_new(sd, cb, data));
grilio_request_unref(req);
return TRUE;
}
}
return FALSE;
struct ril_sim_retry_query_cbd *cbd =
g_new(struct ril_sim_retry_query_cbd, 1);
cbd->sd = sd;
cbd->cb = cb;
cbd->data = data;
cbd->query_index = query_index;
return cbd;
}
static void ril_sim_query_pin_retries_cb(GRilIoChannel *io, int status,
static gboolean ril_sim_query_retry_count(struct ril_sim *sd,
guint start_index, ofono_sim_pin_retries_cb_t cb, void *data)
{
guint id = 0;
if (sd->empty_pin_query_allowed) {
guint i = start_index;
/* Find the first unknown retry count that we can query. */
while (i < G_N_ELEMENTS(ril_sim_retry_query_types)) {
const struct ril_sim_retry_query *query =
ril_sim_retry_query_types + i;
if (sd->retries[query->passwd_type] < 0) {
GRilIoRequest *req = query->new_req(sd);
if (req) {
DBG_(sd, "querying %s retry count...",
query->name);
id = grilio_queue_send_request_full(
sd->q, req, query->req_code,
ril_sim_query_retry_count_cb,
g_free,
ril_sim_retry_query_cbd_new(
sd, i, cb, data));
grilio_request_unref(req);
}
break;
}
i++;
}
}
return id;
}
static void ril_sim_query_retry_count_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd *cbd = user_data;
struct ril_sim_retry_query_cbd *cbd = user_data;
struct ril_sim *sd = cbd->sd;
ofono_sim_pin_retries_cb_t cb = cbd->cb.retries;
struct ofono_error error;
GASSERT(sd->query_pin_retries_id);
sd->query_pin_retries_id = 0;
if (status == RIL_E_SUCCESS) {
const int retry_count = ril_sim_parse_retry_count(data, len);
DBG_(sd, "pin retry_count=%d", retry_count);
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] = retry_count;
if (ril_sim_query_pin2_retry_count(sd, cb, cbd->data)) {
/*
* ril_sim_query_pin2_retries_cb will invoke
* the completion callback
*/
const struct ril_sim_retry_query *query =
ril_sim_retry_query_types + cbd->query_index;
DBG_(sd, "%s retry_count=%d", query->name, retry_count);
sd->retries[query->passwd_type] = retry_count;
/* Submit the next request */
if ((sd->query_pin_retries_id =
ril_sim_query_retry_count(sd, cbd->query_index + 1,
cbd->cb, cbd->data)) != 0) {
/* The next request is pending */
return;
}
} else {
@@ -854,43 +980,32 @@ static void ril_sim_query_pin_retries_cb(GRilIoChannel *io, int status,
sd->empty_pin_query_allowed = FALSE;
}
cb(ril_error_ok(&error), sd->retries, cbd->data);
}
static gboolean ril_sim_query_pin_retry_count(struct ril_sim *sd,
ofono_sim_pin_retries_cb_t cb, void *data)
{
if (sd->empty_pin_query_allowed &&
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] < 0) {
GRilIoRequest *req = ril_sim_enter_sim_req(sd, "");
if (req) {
DBG_(sd, "querying pin retry count...");
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PIN,
ril_sim_query_pin_retries_cb,
ril_sim_cbd_free,
ril_sim_cbd_new(sd, cb, data));
grilio_request_unref(req);
return TRUE;
}
}
return FALSE;
cbd->cb(ril_error_ok(&error), sd->retries, cbd->data);
}
static void ril_sim_query_pin_retries(struct ofono_sim *sim,
ofono_sim_pin_retries_cb_t cb, void *data)
{
struct ofono_error error;
struct ril_sim *sd = ril_sim_get_data(sim);
DBG_(sd, "");
if (ril_sim_query_pin_retry_count(sd, cb, data) ||
ril_sim_query_pin2_retry_count(sd, cb, data)) {
/* Wait for completion of PIN and then PIN2 query */
return;
}
grilio_queue_cancel_request(sd->q, sd->query_pin_retries_id, FALSE);
sd->query_pin_retries_id = ril_sim_query_retry_count(sd, 0, cb, data);
if (!sd->query_pin_retries_id) {
struct ofono_error error;
cb(ril_error_ok(&error), sd->retries, data);
/* Nothing to wait for */
cb(ril_error_ok(&error), sd->retries, data);
}
}
static void ril_sim_query_passwd_state_complete_cb(struct ril_sim_card *sc,
void *user_data)
{
struct ril_sim *sd = user_data;
GASSERT(sd->query_passwd_state_sim_status_refresh_id);
ril_sim_finish_passwd_state_query(sd, ril_sim_passwd_state(sd));
}
static gboolean ril_sim_query_passwd_state_timeout_cb(gpointer user_data)
@@ -908,29 +1023,41 @@ static void ril_sim_query_passwd_state(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
enum ofono_sim_password_type passwd_state = ril_sim_passwd_state(sd);
struct ofono_error error;
if (sd->query_passwd_state_timeout_id) {
g_source_remove(sd->query_passwd_state_timeout_id);
sd->query_passwd_state_timeout_id = 0;
}
if (passwd_state != OFONO_SIM_PASSWORD_INVALID) {
DBG_(sd, "%d", passwd_state);
sd->query_passwd_state_cb = NULL;
sd->query_passwd_state_cb_data = NULL;
sd->ofono_passwd_state = passwd_state;
cb(ril_error_ok(&error), passwd_state, data);
if (!sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
sd->query_passwd_state_sim_status_refresh_id = 0;
}
/* Always request fresh status, just in case. */
ril_sim_card_request_status(sd->card);
sd->query_passwd_state_cb = cb;
sd->query_passwd_state_cb_data = data;
if (ril_sim_passwd_state(sd) != OFONO_SIM_PASSWORD_INVALID) {
/* Just wait for GET_SIM_STATUS completion */
DBG_(sd, "waiting for SIM status query to complete");
sd->query_passwd_state_sim_status_refresh_id =
ril_sim_card_add_status_received_handler(sd->card,
ril_sim_query_passwd_state_complete_cb, sd);
} else {
/* Wait for the state to change */
DBG_(sd, "waiting for the SIM state to change");
sd->query_passwd_state_cb = cb;
sd->query_passwd_state_cb_data = data;
sd->query_passwd_state_timeout_id =
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
ril_sim_query_passwd_state_timeout_cb, sd);
}
/*
* We still need to complete the request somehow, even if
* GET_STATUS never completes or SIM status never changes.
*/
sd->query_passwd_state_timeout_id =
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
ril_sim_query_passwd_state_timeout_cb, sd);
}
static gboolean ril_sim_pin_change_state_timeout_cb(gpointer user_data)
@@ -980,20 +1107,30 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
struct ril_sim_pin_cbd *cbd = user_data;
struct ril_sim *sd = cbd->sd;
const int retry_count = ril_sim_parse_retry_count(data, len);
enum ofono_sim_password_type type = cbd->passwd_type;
DBG_(sd, "result=%d passwd_type=%d retry_count=%d",
ril_status, cbd->passwd_type, retry_count);
if (ril_status == RIL_E_SUCCESS && retry_count == 0 &&
sd->empty_pin_query_allowed &&
(cbd->passwd_type == OFONO_SIM_PASSWORD_SIM_PIN ||
cbd->passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)) {
/* Will query it */
sd->retries[cbd->passwd_type] = -1;
if (ril_status == RIL_E_SUCCESS && retry_count == 0) {
enum ofono_sim_password_type associated_pin =
__ofono_sim_puk2pin(type);
/*
* If PIN/PUK request has succeeded, zero retry count
* makes no sense, we have to assume that it's unknown.
* If it can be queried, it will be queried later. If
* it can't be queried it will remain unknown.
*/
sd->retries[type] = -1;
if (associated_pin != OFONO_SIM_PASSWORD_INVALID) {
/* Successful PUK requests affect PIN retry count */
sd->retries[associated_pin] = -1;
}
} else {
sd->retries[cbd->passwd_type] = retry_count;
sd->retries[type] = retry_count;
}
ril_sim_check_perm_lock(sd);
cbd->ril_status = ril_status;
if (cbd->card_status_id && (!cbd->state_event_count ||
ril_sim_app_in_transient_state(sd))) {
@@ -1023,6 +1160,13 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
} else {
cbd->cb(ril_error_failure(&error), cbd->data);
}
/* To avoid assert in ril_sim_pin_req_done: */
if (cbd->card_status_id) {
ril_sim_card_remove_handler(cbd->card,
cbd->card_status_id);
cbd->card_status_id = 0;
}
}
}
@@ -1030,18 +1174,21 @@ static void ril_sim_pin_send(struct ofono_sim *sim, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
GRilIoRequest *req = grilio_request_new();
GRilIoRequest *req = ril_sim_enter_sim_pin_req(sd, passwd);
grilio_request_append_int32(req, ENTER_SIM_PIN_PARAMS);
grilio_request_append_utf8(req, passwd);
grilio_request_append_utf8(req, ril_sim_app_id(sd));
if (req) {
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PIN, ril_sim_pin_change_state_cb,
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
OFONO_SIM_PASSWORD_SIM_PIN, TRUE, cb, data));
grilio_request_unref(req);
} else {
struct ofono_error error;
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PIN,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PIN,
TRUE, cb, data));
grilio_request_unref(req);
DBG_(sd, "sorry");
cb(ril_error_failure(&error), data);
}
}
static guint ril_perso_change_state(struct ofono_sim *sim,
@@ -1146,19 +1293,22 @@ static void ril_sim_pin_send_puk(struct ofono_sim *sim,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
GRilIoRequest *req = grilio_request_sized_new(60);
GRilIoRequest *req = ril_sim_enter_sim_puk_req(sd, puk, passwd);
grilio_request_append_int32(req, ENTER_SIM_PUK_PARAMS);
grilio_request_append_utf8(req, puk);
grilio_request_append_utf8(req, passwd);
grilio_request_append_utf8(req, ril_sim_app_id(sd));
if (req) {
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd,
ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PUK, ril_sim_pin_change_state_cb,
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
OFONO_SIM_PASSWORD_SIM_PUK, TRUE, cb, data));
grilio_request_unref(req);
} else {
struct ofono_error error;
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PUK,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PUK,
TRUE, cb, data));
grilio_request_unref(req);
DBG_(sd, "sorry");
cb(ril_error_failure(&error), data);
}
}
static void ril_sim_change_passwd(struct ofono_sim *sim,
@@ -1238,11 +1388,15 @@ static gboolean ril_sim_register(gpointer user)
ofono_sim_register(sd->sim);
/* Register for change notifications */
sd->card_status_id = ril_sim_card_add_status_changed_handler(sd->card,
ril_sim_status_cb, sd);
sd->card_event_id[SIM_CARD_STATUS_EVENT] =
ril_sim_card_add_status_changed_handler(sd->card,
ril_sim_status_changed_cb, sd);
sd->card_event_id[SIM_CARD_APP_EVENT] =
ril_sim_card_add_app_changed_handler(sd->card,
ril_sim_app_changed_cb, sd);
/* Check the current state */
ril_sim_status_cb(sd->card, sd);
ril_sim_status_changed_cb(sd->card, sd);
return FALSE;
}
@@ -1289,7 +1443,13 @@ static void ril_sim_remove(struct ofono_sim *sim)
g_source_remove(sd->query_passwd_state_timeout_id);
}
ril_sim_card_remove_handler(sd->card, sd->card_status_id);
if (sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
}
ril_sim_card_remove_handlers(sd->card, sd->card_event_id,
G_N_ELEMENTS(sd->card_event_id));
ril_sim_card_unref(sd->card);
grilio_channel_unref(sd->io);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -64,8 +64,6 @@ G_DEFINE_TYPE(RilSimCard, ril_sim_card, G_TYPE_OBJECT)
#define RIL_SIMCARD_STATE_CHANGED (0x01)
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
static void ril_sim_card_request_status(struct ril_sim_card *self);
static gboolean ril_sim_card_app_equal(const struct ril_sim_card_app *a1,
const struct ril_sim_card_app *a2)
{
@@ -338,6 +336,7 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
}
if (i == num_apps) {
GASSERT(grilio_parser_at_end(&rilp));
return status;
} else {
ril_sim_card_status_free(status);
@@ -365,7 +364,7 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
}
}
static void ril_sim_card_request_status(struct ril_sim_card *self)
void ril_sim_card_request_status(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -55,6 +55,7 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
void ril_sim_card_unref(struct ril_sim_card *sc);
void ril_sim_card_request_status(struct ril_sim_card *self);
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,8 @@
#include "ril_sim_info.h"
#include "ril_log.h"
#include <gutil_misc.h>
#include <ofono/dbus.h>
#include <gdbus.h>
@@ -32,7 +34,7 @@ enum sim_info_event_id {
};
struct ril_sim_info_dbus {
struct ril_modem *md;
struct ril_modem *modem;
struct ril_sim_info *info;
DBusConnection *conn;
char *path;
@@ -113,35 +115,43 @@ static DBusMessage *ril_sim_info_dbus_get_spn(DBusConnection *conn,
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->spn);
}
#define RIL_SIM_INFO_DBUS_VERSION_ARG {"version", "i"}
#define RIL_SIM_INFO_DBUS_ICCID_ARG {"iccid", "s"}
#define RIL_SIM_INFO_DBUS_IMSI_ARG {"imsi", "s"}
#define RIL_SIM_INFO_DBUS_SPN_ARG {"spn" , "s"}
#define RIL_SIM_INFO_DBUS_GET_ALL_ARGS \
RIL_SIM_INFO_DBUS_VERSION_ARG, \
RIL_SIM_INFO_DBUS_ICCID_ARG, \
RIL_SIM_INFO_DBUS_IMSI_ARG, \
RIL_SIM_INFO_DBUS_SPN_ARG
static const GDBusMethodTable ril_sim_info_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS({"version", "i" },
{"iccid", "s" },
{"imsi", "s" },
{"spn" , "s"}),
NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_GET_ALL_ARGS),
ril_sim_info_dbus_get_all) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_VERSION_ARG),
ril_sim_info_dbus_get_version) },
{ GDBUS_METHOD("GetCardIdentifier",
NULL, GDBUS_ARGS({ "iccid", "s" }),
NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_ICCID_ARG),
ril_sim_info_dbus_get_iccid) },
{ GDBUS_METHOD("GetSubscriberIdentity",
NULL, GDBUS_ARGS({ "imsi", "s" }),
NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_IMSI_ARG),
ril_sim_info_dbus_get_imsi) },
{ GDBUS_METHOD("GetServiceProviderName",
NULL, GDBUS_ARGS({ "spn", "s" }),
NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_SPN_ARG),
ril_sim_info_dbus_get_spn) },
{ }
};
static const GDBusSignalTable ril_sim_info_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
GDBUS_ARGS({ "iccid", "s" })) },
GDBUS_ARGS(RIL_SIM_INFO_DBUS_ICCID_ARG)) },
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
GDBUS_ARGS({ "imsi", "s" })) },
GDBUS_ARGS(RIL_SIM_INFO_DBUS_IMSI_ARG)) },
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
GDBUS_ARGS({ "spn", "s" })) },
GDBUS_ARGS(RIL_SIM_INFO_DBUS_SPN_ARG)) },
{ }
};
@@ -156,23 +166,20 @@ static void ril_sim_info_dbus_emit(struct ril_sim_info_dbus *dbus,
static void ril_sim_info_dbus_iccid_cb(struct ril_sim_info *info, void *arg)
{
struct ril_sim_info_dbus *dbus = arg;
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
info->iccid);
ril_sim_info_dbus_emit((struct ril_sim_info_dbus *)arg,
RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL, info->iccid);
}
static void ril_sim_info_dbus_imsi_cb(struct ril_sim_info *info, void *arg)
{
struct ril_sim_info_dbus *dbus = arg;
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
info->imsi);
ril_sim_info_dbus_emit((struct ril_sim_info_dbus *)arg,
RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL, info->imsi);
}
static void ril_sim_info_dbus_spn_cb(struct ril_sim_info *info, void *arg)
{
struct ril_sim_info_dbus *dbus = arg;
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
info->spn);
ril_sim_info_dbus_emit((struct ril_sim_info_dbus *)arg,
RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL, info->spn);
}
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
@@ -181,7 +188,7 @@ struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
struct ril_sim_info_dbus *dbus = g_new0(struct ril_sim_info_dbus, 1);
DBG("%s", ril_modem_get_path(md));
dbus->md = md;
dbus->modem = md;
dbus->path = g_strdup(ril_modem_get_path(md));
dbus->info = ril_sim_info_ref(info);
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
@@ -205,7 +212,7 @@ struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
return dbus;
} else {
ofono_error("CellInfo D-Bus register failed");
ofono_error("SimInfo D-Bus register failed");
ril_sim_info_dbus_free(dbus);
return NULL;
}
@@ -214,19 +221,15 @@ struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus)
{
if (dbus) {
unsigned int i;
DBG("%s", dbus->path);
g_dbus_unregister_interface(dbus->conn, dbus->path,
RIL_SIM_INFO_DBUS_INTERFACE);
ofono_modem_remove_interface(dbus->md->ofono,
ofono_modem_remove_interface(dbus->modem->ofono,
RIL_SIM_INFO_DBUS_INTERFACE);
dbus_connection_unref(dbus->conn);
for (i=0; i<G_N_ELEMENTS(dbus->handler_id); i++) {
ril_sim_info_remove_handler(dbus->info,
dbus->handler_id[i]);
}
gutil_disconnect_handlers(dbus->info, dbus->handler_id,
G_N_ELEMENTS(dbus->handler_id));
ril_sim_info_unref(dbus->info);
g_free(dbus->path);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,8 +26,12 @@
#define RIL_SIM_STORE_GROUP "Settings"
#define RIL_SIM_STORE_PREF_MODE "TechnologyPreference"
#define RIL_SIM_STORE_PREF_MODE_DEFAULT(self) ((self)->enable_4g ? \
OFONO_RADIO_ACCESS_MODE_LTE : OFONO_RADIO_ACCESS_MODE_UMTS)
#define RIL_SIM_STORE_PREF_MODE_DEFAULT(self) (\
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
OFONO_RADIO_ACCESS_MODE_LTE : \
((self)->techs & OFONO_RADIO_ACCESS_MODE_UMTS) ? \
OFONO_RADIO_ACCESS_MODE_UMTS : \
OFONO_RADIO_ACCESS_MODE_GSM)
typedef GObjectClass RilSimSettingsClass;
typedef struct ril_sim_settings RilSimSettings;
@@ -84,8 +88,7 @@ static void ril_sim_settings_reload(struct ril_sim_settings *self)
mode_str = g_key_file_get_string(priv->storage,
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_PREF_MODE, NULL);
if (ofono_radio_access_mode_from_string(mode_str, &mode)) {
if (!self->enable_4g &&
mode == OFONO_RADIO_ACCESS_MODE_LTE) {
if (!(self->techs & mode)) {
mode = OFONO_RADIO_ACCESS_MODE_ANY;
}
} else {
@@ -154,22 +157,18 @@ static void ril_sim_settings_imsi_watch_done(void *user_data)
priv->imsi_watch_id = 0;
}
static void ril_sim_settings_ready(struct ril_sim_settings *self)
static void ril_sim_settings_state_check(struct ril_sim_settings *self,
enum ofono_sim_state new_state)
{
struct ril_sim_settings_priv *priv = self->priv;
GASSERT(!priv->imsi_watch_id);
priv->imsi_watch_id = ofono_sim_add_imsi_watch(priv->sim,
ril_sim_settings_imsi_watch_cb, self,
ril_sim_settings_imsi_watch_done);
if (new_state != OFONO_SIM_STATE_READY) {
ril_sim_settings_set_imsi(self, NULL);
}
}
static void ril_sim_settings_state_watch(enum ofono_sim_state new_state,
void *user_data)
{
if (new_state == OFONO_SIM_STATE_READY) {
ril_sim_settings_ready(RIL_SIM_SETTINGS(user_data));
}
ril_sim_settings_state_check(RIL_SIM_SETTINGS(user_data), new_state);
}
static void ril_sim_settings_state_watch_done(void *user_data)
@@ -191,13 +190,19 @@ void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
if (priv->imsi_watch_id) {
ofono_sim_remove_imsi_watch(priv->sim,
priv->imsi_watch_id);
/* ril_sim_settings_imsi_watch_done clears it */
/*
* ril_sim_settings_imsi_watch_done
* clears it
*/
GASSERT(!priv->imsi_watch_id);
}
if (priv->state_watch_id) {
ofono_sim_remove_state_watch(priv->sim,
priv->state_watch_id);
/* ril_sim_settings_state_watch_done clears it */
/*
* ril_sim_settings_state_watch_done
* clears it
*/
GASSERT(!priv->state_watch_id);
}
priv->sim = sim;
@@ -207,13 +212,25 @@ void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
ril_sim_settings_state_watch, self,
ril_sim_settings_state_watch_done);
GASSERT(priv->state_watch_id);
if (ofono_sim_get_state(sim) ==
OFONO_SIM_STATE_READY) {
ril_sim_settings_ready(self);
}
} else {
ril_sim_settings_set_imsi(self, NULL);
ril_sim_settings_state_check(self,
ofono_sim_get_state(sim));
/*
* ofono_sim_add_imsi_watch immediately
* calls the event callback if IMSI is
* already known. It's useless though
* because we still have to check the
* current state in case if IMSI is not
* available yet.
*/
priv->imsi_watch_id =
ofono_sim_add_imsi_watch(priv->sim,
ril_sim_settings_imsi_watch_cb, self,
ril_sim_settings_imsi_watch_done);
GASSERT(priv->state_watch_id);
}
/* Luckily, ofono_sim_get_imsi handles NULL pointer */
ril_sim_settings_set_imsi(self,
ofono_sim_get_imsi(sim));
}
}
}
@@ -249,7 +266,7 @@ void ril_sim_settings_remove_handlers(struct ril_sim_settings *self,
struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc)
{
struct ril_sim_settings *self = g_object_new(RIL_SIM_SETTINGS_TYPE, 0);
self->enable_4g = sc->enable_4g;
self->techs = sc->techs;
self->slot = sc->slot;
self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
return self;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,16 +18,14 @@
#include "ril_types.h"
#include <ofono/radio-settings.h>
struct ril_sim_settings_priv;
struct ril_sim_settings {
GObject object;
struct ril_sim_settings_priv *priv;
gboolean enable_4g;
guint slot;
const char *imsi;
enum ofono_radio_access_mode techs;
enum ofono_radio_access_mode pref_mode;
};

View File

@@ -35,6 +35,17 @@
#
#3GLTEHandover=true
# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
# This option allows you to forcibly enable or disable use of this request.
# It's involved in 3G/LTE handover between the modems, meaning that it only
# makes sense if you have more than one slot.
#
# Possible values are auto, on and off
#
# Default is auto (enable for RIL version >= 11)
#
#SetRadioCapability=auto
[ril_0]
# Required entry, defines the RIL socket path
@@ -67,9 +78,15 @@ socket=/dev/socket/rild
#
#timeout=0
# Setting this one to false would disable 4G technology selection.
# Comma-separated list of radio technologies supported by the modem.
# Valid technologies are "gsm", "umts" and "lte". The special value
# "all" means that all technologies are supported.
#
# By default 4G is enabled
# The default is all
#
#technologies=all
# This one is deprecated, use the technologies entry instead (above).
#
#enable4G=true
@@ -100,7 +117,7 @@ socket=/dev/socket/rild
# This option allows you to forcibly enable or disable use of this request.
# Possible values are auto, on and off
#
# Default is auto (usage based on the RIL version)
# Default is auto (enable for RIL version >= 11)
#
#allowDataReq=auto
@@ -113,3 +130,41 @@ socket=/dev/socket/rild
# Default is true
#
#emptyPinQuery=true
# Different RILs use different data call structures which don't necessarily
# match the format specified in the data list header. The header may have
# version 9 but the list may contain RIL_Data_Call_Response_v6 structures,
# list version 10 may contain RIL_Data_Call_Response_v11 and so on. By default
# ofono assumes that the version from the list header matches the contents
# but sometimes you have to explicitly tell ofono which one to use.
# Possible values are 6, 9, 11 and auto.
#
# Default is auto
#
#dataCallFormat=auto
# Data call may fail with status 65535 which according to ril.h means that
# we need to retry silently. The maximum number of retries is limited by
# this parameter. Usually, one retry is enough. The first retry occurs
# immediately, the subsequent ones after dataCallRetryDelay (see below)
#
# Default is 4
#
#dataCallRetryLimit=4
# Delay between data call retries, in milliseconds. Note that the first
# retry occurs immediately after the first failure, the delays are only
# applied if the first retry fails too.
#
# Default is 200 ms
#
#dataCallRetryDelay=200
# Additional local and remote hangup reasons. Remote reasons are checked
# first. Normally, RIL plugin figures it out automatically. You would only
# need to define these if your RIL does something unusual.
#
# No default
#
#remoteHangupReasons=20
#localHangupReasons=23

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,11 +23,12 @@
#include <grilio_types.h>
#include <gutil_macros.h>
#include <ofono/types.h>
struct ofono_modem;
struct ofono_sim;
#include <ofono/types.h>
#include <ofono/radio-settings.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
@@ -51,8 +52,10 @@ struct ril_cell_info;
struct ril_slot_config {
guint slot;
gboolean enable_4g;
enum ofono_radio_access_mode techs;
gboolean empty_pin_query;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
};
#endif /* RIL_TYPES_H */

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -48,7 +48,8 @@ const char *ril_error_to_string(int error)
RIL_E_(MODE_NOT_SUPPORTED);
RIL_E_(FDN_CHECK_FAILURE);
RIL_E_(ILLEGAL_SIM_OR_ME);
RIL_E_(UNUSED);
RIL_E_(MISSING_RESOURCE);
RIL_E_(NO_SUCH_ELEMENT);
RIL_E_(DIAL_MODIFIED_TO_USSD);
RIL_E_(DIAL_MODIFIED_TO_SS);
RIL_E_(DIAL_MODIFIED_TO_DIAL);
@@ -57,11 +58,39 @@ const char *ril_error_to_string(int error)
RIL_E_(USSD_MODIFIED_TO_USSD);
RIL_E_(SS_MODIFIED_TO_DIAL);
RIL_E_(SS_MODIFIED_TO_USSD);
RIL_E_(SS_MODIFIED_TO_SS);
RIL_E_(SUBSCRIPTION_NOT_SUPPORTED);
RIL_E_(MISSING_RESOURCE);
RIL_E_(NO_SUCH_ELEMENT);
RIL_E_(INVALID_PARAMETER);
RIL_E_(SS_MODIFIED_TO_SS);
RIL_E_(LCE_NOT_SUPPORTED);
RIL_E_(NO_MEMORY);
RIL_E_(INTERNAL_ERR);
RIL_E_(SYSTEM_ERR);
RIL_E_(MODEM_ERR);
RIL_E_(INVALID_STATE);
RIL_E_(NO_RESOURCES);
RIL_E_(SIM_ERR);
RIL_E_(INVALID_ARGUMENTS);
RIL_E_(INVALID_SIM_STATE);
RIL_E_(INVALID_MODEM_STATE);
RIL_E_(INVALID_CALL_ID);
RIL_E_(NO_SMS_TO_ACK);
RIL_E_(NETWORK_ERR);
RIL_E_(REQUEST_RATE_LIMITED);
RIL_E_(SIM_BUSY);
RIL_E_(SIM_FULL);
RIL_E_(NETWORK_REJECT);
RIL_E_(OPERATION_NOT_ALLOWED);
RIL_E_(EMPTY_RECORD);
RIL_E_(INVALID_SMS_FORMAT);
RIL_E_(ENCODING_ERR);
RIL_E_(INVALID_SMSC_ADDRESS);
RIL_E_(NO_SUCH_ENTRY);
RIL_E_(NETWORK_NOT_READY);
RIL_E_(NOT_PROVISIONED);
RIL_E_(NO_SUBSCRIPTION);
RIL_E_(NO_NETWORK_FOUND);
RIL_E_(DEVICE_IN_USE);
RIL_E_(ABORTED);
RIL_E_(INVALID_RESPONSE);
default:
snprintf(unknown, sizeof(unknown), "%d", error);
return unknown;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,7 +21,10 @@
#include "common.h"
#include <gutil_ints.h>
#include <gutil_ring.h>
#include <gutil_idlequeue.h>
#include <gutil_intarray.h>
#define FLAG_NEED_CLIP 1
@@ -38,12 +41,14 @@ struct ril_voicecall {
GRilIoQueue *q;
struct ofono_voicecall *vc;
struct ril_ecclist *ecclist;
unsigned int local_release;
unsigned char flags;
ofono_voicecall_cb_t cb;
void *data;
guint timer_id;
GUtilRing* dtmf_queue;
GUtilIntArray *local_release_ids;
GUtilIdleQueue *idleq;
GUtilRing *dtmf_queue;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
guint send_dtmf_id;
guint clcc_poll_id;
gulong event_id[VOICECALL_EVENT_COUNT];
@@ -52,35 +57,48 @@ struct ril_voicecall {
gulong ecclist_change_id;
};
struct ril_voicecall_change_state_req {
struct ril_voicecall_request_data {
int ref_count;
int pending_call_count;
int success;
struct ofono_voicecall *vc;
ofono_voicecall_cb_t cb;
gpointer data;
int affected_types;
};
struct lastcause_req {
struct ofono_voicecall *vc;
struct ril_voicecall *vd;
int id;
};
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
/*
* structs ofono_voicecall and voicecall are fully defined
* in src/voicecall.c; we need (read) access to the
* call objects, so partially redefine them here.
*/
struct ofono_voicecall {
GSList *call_list;
/* ... */
};
struct ril_voicecall_request_data *ril_voicecall_request_data_new
(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall_request_data *req =
g_slice_new0(struct ril_voicecall_request_data);
struct voicecall {
struct ofono_call *call;
/* ... */
};
req->ref_count = 1;
req->vc = vc;
req->cb = cb;
req->data = data;
return req;
}
static void ril_voicecall_request_data_unref
(struct ril_voicecall_request_data *req)
{
if (!--req->ref_count) {
g_slice_free(struct ril_voicecall_request_data, req);
}
}
static void ril_voicecall_request_data_free(gpointer data)
{
ril_voicecall_request_data_unref(data);
}
static inline struct ril_voicecall *ril_voicecall_get_data(
struct ofono_voicecall *vc)
@@ -166,38 +184,76 @@ static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
}
/* Valid call statuses have value >= 0 */
static int call_status_with_id(struct ofono_voicecall *vc, int id)
static int ril_voicecall_status_with_id(struct ofono_voicecall *vc,
unsigned int id)
{
GSList *l;
struct voicecall *v;
struct ofono_call *call = ofono_voicecall_find_call(vc, id);
GASSERT(vc);
return call ? call->status : -1;
}
for (l = vc->call_list; l; l = l->next) {
v = l->data;
if (v->call->id == id) {
return v->call->status;
/* Tries to parse the payload as a uint followed by a string */
static int ril_voicecall_parse_lastcause_1(const void *data, guint len)
{
int result = -1;
if (len > 8) {
int code;
char *msg = NULL;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &code) && code >= 0 &&
(msg = grilio_parser_get_utf8(&rilp)) &&
grilio_parser_at_end(&rilp)) {
DBG("%d \"%s\"", code, msg);
result = code;
}
g_free(msg);
}
return -1;
return result;
}
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct lastcause_req *reqdata = user_data;
struct ofono_voicecall *vc = reqdata->vc;
int tmp;
struct ril_voicecall *vd = reqdata->vd;
struct ofono_voicecall *vc = vd->vc;
int id = reqdata->id;
int call_status;
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
grilio_parser_get_int32(&rilp, &last_cause);
int last_cause;
/*
* According to ril.h:
*
* "response" is a "int *"
* ((int *)response)[0] is RIL_LastCallFailCause. GSM failure
* reasons are mapped to cause codes defined in TS 24.008 Annex H
* where possible.
*
* However some RILs feel free to invent their own formats,
* try those first.
*/
last_cause = ril_voicecall_parse_lastcause_1(data, len);
if (last_cause < 0) {
GRilIoParser rilp;
int num, code;
/* Default format described in ril.h */
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &num) && num == 1 &&
grilio_parser_get_int32(&rilp, &code) &&
grilio_parser_at_end(&rilp)) {
last_cause = code;
} else {
ofono_warn("Unable to parse last call fail cause");
last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
}
}
/*
@@ -208,7 +264,14 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
* from a network failure.
*/
switch (last_cause) {
if (gutil_ints_contains(vd->remote_hangup_reasons, last_cause)) {
DBG("hangup cause %d => remote hangup", last_cause);
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
} else if (gutil_ints_contains(vd->local_hangup_reasons, last_cause)) {
DBG("hangup cause %d => local hangup", last_cause);
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
} else {
switch (last_cause) {
case CALL_FAIL_UNOBTAINABLE_NUMBER:
case CALL_FAIL_NORMAL:
case CALL_FAIL_BUSY:
@@ -216,19 +279,19 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
case CALL_FAIL_CHANNEL_UNACCEPTABLE:
case CALL_FAIL_OPERATOR_DETERMINED_BARRING:
case CALL_FAIL_NO_USER_RESPONDING:
case CALL_FAIL_USER_ALERTING_NO_ANSWER:
case CALL_FAIL_NO_ANSWER_FROM_USER:
case CALL_FAIL_CALL_REJECTED:
case CALL_FAIL_NUMBER_CHANGED:
case CALL_FAIL_ANONYMOUS_CALL_REJECTION:
case CALL_FAIL_PRE_EMPTION:
case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
case CALL_FAIL_INCOMPLETE_NUMBER:
case CALL_FAIL_INVALID_NUMBER_FORMAT:
case CALL_FAIL_FACILITY_REJECTED:
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
break;
case CALL_FAIL_NORMAL_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
call_status = ril_voicecall_status_with_id(vc, id);
if (call_status == CALL_STATUS_ACTIVE ||
call_status == CALL_STATUS_HELD ||
call_status == CALL_STATUS_DIALING ||
@@ -240,7 +303,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
break;
case CALL_FAIL_ERROR_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
call_status = ril_voicecall_status_with_id(vc, id);
if (call_status == CALL_STATUS_DIALING ||
call_status == CALL_STATUS_ALERTING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
@@ -250,6 +313,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
default:
reason = OFONO_DISCONNECT_REASON_ERROR;
break;
}
}
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
@@ -285,7 +349,9 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
struct ofono_call *oc = o ? o->data : NULL;
if (oc && (nc == NULL || (nc->id > oc->id))) {
if (vd->local_release & (1 << oc->id)) {
/* old call is gone */
if (gutil_int_array_remove_all_fast(
vd->local_release_ids, oc->id)) {
ofono_voicecall_disconnected(vd->vc, oc->id,
OFONO_DISCONNECT_REASON_LOCAL_HANGUP,
NULL);
@@ -295,7 +361,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
struct lastcause_req *reqdata =
g_new0(struct lastcause_req, 1);
reqdata->vc = vd->vc;
reqdata->vd = vd;
reqdata->id = oc->id;
grilio_queue_send_request_full(vd->q, NULL,
RIL_REQUEST_LAST_CALL_FAIL_CAUSE,
@@ -365,9 +431,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
}
g_slist_free_full(vd->calls, g_free);
vd->calls = calls;
vd->local_release = 0;
}
static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
@@ -386,52 +450,43 @@ static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
static void ril_voicecall_request_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_voicecall_change_state_req *req = user_data;
struct ril_voicecall_request_data *req = user_data;
struct ril_voicecall *vd = ril_voicecall_get_data(req->vc);
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
GSList *l;
if (req->affected_types) {
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
if (req->affected_types & (1 << call->status)) {
vd->local_release |= (1 << call->id);
}
}
}
ril_error_init_ok(&error);
} else {
ofono_error("generic fail");
ril_error_init_failure(&error);
}
ril_voicecall_clcc_poll(vd);
/* We have to callback after we schedule a poll if required */
if (req->cb) {
/*
* The ofono API call is considered successful if at least one
* associated RIL request succeeds.
*/
if (status == RIL_E_SUCCESS) {
req->success++;
}
/*
* Only invoke the callback if this is the last request associated
* with this ofono api call (pending call count becomes zero).
*/
if (!--req->pending_call_count && req->cb) {
struct ofono_error error;
if (req->success) {
ril_error_init_ok(&error);
} else {
ril_error_init_failure(&error);
}
req->cb(&error, req->data);
}
}
static void ril_voicecall_request(const guint rreq, struct ofono_voicecall *vc,
unsigned int affected_types, GRilIoRequest *ioreq,
ofono_voicecall_cb_t cb, void *data)
static void ril_voicecall_request(const guint code, struct ofono_voicecall *vc,
GRilIoRequest *req, ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ril_voicecall_change_state_req *req;
req = g_new0(struct ril_voicecall_change_state_req, 1);
req->vc = vc;
req->cb = cb;
req->data = data;
req->affected_types = affected_types;
grilio_queue_send_request_full(vd->q, ioreq, rreq,
ril_voicecall_request_cb, g_free, req);
grilio_queue_send_request_full(ril_voicecall_get_data(vc)->q, req,
code, ril_voicecall_request_cb,
ril_voicecall_request_data_free,
ril_voicecall_request_data_new(vc, cb, data));
}
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
@@ -489,47 +544,68 @@ static void ril_voicecall_dial(struct ofono_voicecall *vc,
grilio_request_unref(req);
}
static void ril_voicecall_submit_hangup_req(struct ofono_voicecall *vc,
int id, struct ril_voicecall_request_data *req)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
GRilIoRequest *ioreq = grilio_request_array_int32_new(1, id);
/* Append the call id to the list of calls being released locally */
GASSERT(!gutil_int_array_contains(vd->local_release_ids, id));
gutil_int_array_append(vd->local_release_ids, id);
/* Send request to RIL. ril_voicecall_request_data_free will unref
* the request data */
req->ref_count++;
req->pending_call_count++;
grilio_queue_send_request_full(vd->q, ioreq, RIL_REQUEST_HANGUP,
ril_voicecall_request_cb,
ril_voicecall_request_data_free, req);
grilio_request_unref(ioreq);
}
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ofono_error error;
GSList *l;
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
GRilIoRequest *req = grilio_request_sized_new(8);
if (vd->calls) {
GSList *l;
struct ril_voicecall_request_data *req =
ril_voicecall_request_data_new(vc, cb, data);
/* TODO: Hangup just the active ones once we have call
* state tracking (otherwise it can't handle ringing) */
DBG("Hanging up call with id %d", call->id);
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
grilio_request_append_int32(req, call->id);
/*
* Here the idea is that we submit (potentially) multiple
* hangup requests to RIL and invoke the callback after
* the last request has completed (pending call count
* becomes zero).
*/
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
/* Send request to RIL */
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req,
NULL, NULL);
grilio_request_unref(req);
/* Send request to RIL */
DBG("Hanging up call with id %d", call->id);
ril_voicecall_submit_hangup_req(vc, call->id, req);
}
/* Release our reference */
ril_voicecall_request_data_unref(req);
} else {
/* No calls */
struct ofono_error error;
cb(ril_error_ok(&error), data);
}
/* TODO: Deal in case of an error at hungup */
cb(ril_error_ok(&error), data);
}
static void ril_voicecall_hangup_specific(struct ofono_voicecall *vc,
static void ril_voicecall_release_specific(struct ofono_voicecall *vc,
int id, ofono_voicecall_cb_t cb, void *data)
{
GRilIoRequest *req = grilio_request_sized_new(8);
struct ofono_error error;
struct ril_voicecall_request_data *req =
ril_voicecall_request_data_new(vc, cb, data);
DBG("Hanging up call with id %d", id);
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
grilio_request_append_int32(req, id);
/* Send request to RIL */
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req, NULL, NULL);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
ril_voicecall_submit_hangup_req(vc, id, req);
ril_voicecall_request_data_unref(req);
}
static void ril_voicecall_call_state_changed_event(GRilIoChannel *io,
@@ -584,7 +660,7 @@ static void ril_voicecall_answer(struct ofono_voicecall *vc,
{
/* Send request to RIL */
DBG("Answering current call");
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, 0, NULL, cb, data);
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, NULL, cb, data);
}
static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
@@ -653,29 +729,25 @@ static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd)
static void ril_voicecall_create_multiparty(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_CONFERENCE,
vc, 0, NULL, cb, data);
ril_voicecall_request(RIL_REQUEST_CONFERENCE, vc, NULL, cb, data);
}
static void ril_voicecall_transfer(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_EXPLICIT_CALL_TRANSFER,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
ofono_voicecall_cb_t cb, void *data)
{
GRilIoRequest *req = grilio_request_sized_new(8);
GRilIoRequest *req = grilio_request_array_int32_new(1, id);
struct ofono_error error;
DBG("Private chat with id %d", id);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, id);
ril_voicecall_request(RIL_REQUEST_SEPARATE_CONNECTION,
vc, 0, req, NULL, NULL);
vc, req, NULL, NULL);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
}
@@ -683,51 +755,50 @@ static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
static void ril_voicecall_swap_without_accept(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_hold_all_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_release_all_held(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_release_all_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static gboolean ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
static void ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
{
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1); /* size of array */
grilio_request_append_int32(req, 1); /* notifications enabled */
GRilIoRequest *req = grilio_request_array_int32_new(1, 1);
grilio_queue_send_request(vd->q, req,
RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION);
grilio_request_unref(req);
/* Makes this a single shot */
return FALSE;
}
static void ril_voicecall_ringback_tone_event(GRilIoChannel *io,
@@ -755,12 +826,10 @@ static void ril_voicecall_ecclist_changed(struct ril_ecclist *list, void *data)
ofono_voicecall_en_list_notify(vd->vc, vd->ecclist->list);
}
static gboolean ril_delayed_register(gpointer user_data)
static void ril_voicecall_register(gpointer user_data)
{
struct ril_voicecall *vd = user_data;
GASSERT(vd->timer_id);
vd->timer_id = 0;
ofono_voicecall_register(vd->vc);
/* Emergency Call Codes */
@@ -794,15 +863,13 @@ static gboolean ril_delayed_register(gpointer user_data)
grilio_channel_add_unsol_event_handler(vd->io,
ril_voicecall_ringback_tone_event,
RIL_UNSOL_RINGBACK_TONE, vd);
/* This makes the timeout a single-shot */
return FALSE;
}
static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
const struct ril_slot_config *cfg = &modem->config;
struct ril_voicecall *vd;
DBG("");
@@ -810,13 +877,17 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
vd->io = grilio_channel_ref(ril_modem_io(modem));
vd->q = grilio_queue_new(vd->io);
vd->dtmf_queue = gutil_ring_new();
vd->local_hangup_reasons = gutil_ints_ref(cfg->local_hangup_reasons);
vd->remote_hangup_reasons = gutil_ints_ref(cfg->remote_hangup_reasons);
vd->local_release_ids = gutil_int_array_new();
vd->idleq = gutil_idle_queue_new();
vd->vc = vc;
vd->timer_id = g_idle_add(ril_delayed_register, vd);
if (modem->ecclist_file) {
vd->ecclist = ril_ecclist_new(modem->ecclist_file);
}
ril_voicecall_clear_dtmf_queue(vd);
ofono_voicecall_set_data(vc, vd);
gutil_idle_queue_add(vd->idleq, ril_voicecall_register, vd);
return 0;
}
@@ -828,10 +899,6 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
ofono_voicecall_set_data(vc, NULL);
g_slist_free_full(vd->calls, g_free);
if (vd->timer_id > 0) {
g_source_remove(vd->timer_id);
}
ril_ecclist_remove_handler(vd->ecclist, vd->ecclist_change_id);
ril_ecclist_unref(vd->ecclist);
@@ -841,6 +908,10 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
grilio_queue_cancel_all(vd->q, FALSE);
grilio_queue_unref(vd->q);
gutil_ring_unref(vd->dtmf_queue);
gutil_ints_unref(vd->local_hangup_reasons);
gutil_ints_unref(vd->remote_hangup_reasons);
gutil_int_array_free(vd->local_release_ids, TRUE);
gutil_idle_queue_free(vd->idleq);
g_free(vd);
}
@@ -851,7 +922,7 @@ const struct ofono_voicecall_driver ril_voicecall_driver = {
.dial = ril_voicecall_dial,
.answer = ril_voicecall_answer,
.hangup_all = ril_voicecall_hangup_all,
.release_specific = ril_voicecall_hangup_specific,
.release_specific = ril_voicecall_release_specific,
.send_tones = ril_voicecall_send_dtmf,
.create_multiparty = ril_voicecall_create_multiparty,
.transfer = ril_voicecall_transfer,

View File

@@ -0,0 +1,213 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2016 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <glib.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/cbs.h>
#include "util.h"
#include <gril.h>
#include <parcel.h>
#include "rilmodem.h"
#include "vendor.h"
struct cbs_data {
GRil *ril;
unsigned int vendor;
};
static void ril_cbs_set_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_cbs_set_cb_t cb = cbd->cb;
struct cbs_data *cd = cbd->user;
if (message->error == RIL_E_SUCCESS) {
CALLBACK_WITH_SUCCESS(cb, cbd->data);
} else {
ofono_error("%s RILD reply failure: %s",
g_ril_request_id_to_string(cd->ril, message->req),
ril_error_to_string(message->error));
CALLBACK_WITH_FAILURE(cb, cbd->data);
}
}
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
ofono_cbs_set_cb_t cb, void *user_data)
{
struct cbs_data *cd = ofono_cbs_get_data(cbs);
struct cb_data *cbd = cb_data_new(cb, user_data, cd);
int i = 0, from, to;
const char *p, *pto;
char **segments;
struct parcel rilp;
segments = g_strsplit(topics, ",", 0);
while (segments[i])
i++;
parcel_init(&rilp);
parcel_w_int32(&rilp, i);
i = 0;
while (segments[i]) {
p = segments[i++];
from = atoi(p);
to = from;
pto = strchr(p, '-');
if (pto)
to = atoi(pto + 1);
parcel_w_int32(&rilp, from);
parcel_w_int32(&rilp, to);
parcel_w_int32(&rilp, 0);
parcel_w_int32(&rilp, 0xFF);
parcel_w_int32(&rilp, 1);
}
g_strfreev(segments);
if (g_ril_send(cd->ril, RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, &rilp,
ril_cbs_set_cb, cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, user_data);
}
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
ofono_cbs_set_cb_t cb, void *user_data)
{
ril_cbs_set_topics(cbs, "", cb, user_data);
}
static void ril_cbs_received(struct ril_msg *message, gpointer user_data)
{
struct ofono_cbs *cbs = user_data;
struct cbs_data *cd = ofono_cbs_get_data(cbs);
struct parcel rilp;
int pdulen;
unsigned char *pdu;
g_ril_print_unsol_no_args(cd->ril, message);
DBG("req: %d; data_len: %d", message->req, (int) message->buf_len);
g_ril_init_parcel(message, &rilp);
pdu = parcel_r_raw(&rilp, &pdulen);
if (!pdu || pdulen != 88) {
ofono_error("%s: it isn't a gsm cell broadcast msg", __func__);
return;
}
ofono_cbs_notify(cbs, pdu, pdulen);
g_free(pdu);
}
static void ril_cbs_register(const struct ofono_error *error, void *data)
{
struct ofono_cbs *cbs = data;
struct cbs_data *cd = ofono_cbs_get_data(cbs);
g_ril_register(cd->ril, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
ril_cbs_received, cbs);
ofono_cbs_register(cbs);
}
static void get_cbs_config_cb(struct ril_msg *message,
gpointer user_data)
{
struct ofono_cbs *cbs = user_data;
if (message->error != RIL_E_SUCCESS) {
ofono_error("%s: RIL error %s", __func__,
ril_error_to_string(message->error));
ofono_cbs_remove(cbs);
return;
}
ril_cbs_clear_topics(cbs, ril_cbs_register, cbs);
}
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
void *user)
{
GRil *ril = user;
struct cbs_data *data;
data = g_new0(struct cbs_data, 1);
data->ril = g_ril_clone(ril);
data->vendor = vendor;
ofono_cbs_set_data(cbs, data);
if (g_ril_send(ril, RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, NULL,
get_cbs_config_cb, cbs, NULL) == 0)
ofono_error("%s: send failed", __func__);
return 0;
}
static void ril_cbs_remove(struct ofono_cbs *cbs)
{
struct cbs_data *data = ofono_cbs_get_data(cbs);
ofono_cbs_set_data(cbs, NULL);
g_ril_unref(data->ril);
g_free(data);
}
static struct ofono_cbs_driver driver = {
.name = RILMODEM,
.probe = ril_cbs_probe,
.remove = ril_cbs_remove,
.set_topics = ril_cbs_set_topics,
.clear_topics = ril_cbs_clear_topics,
};
void ril_cbs_init(void)
{
ofono_cbs_driver_register(&driver);
}
void ril_cbs_exit(void)
{
ofono_cbs_driver_unregister(&driver);
}

View File

@@ -198,6 +198,7 @@ static void ril_rat_mode_cb(struct ril_msg *message, gpointer user_data)
* capabilities, so it is sort of the default for MTK modems.
*/
switch (net_type) {
case PREF_NET_TYPE_WCDMA:
case PREF_NET_TYPE_GSM_WCDMA:
case PREF_NET_TYPE_GSM_WCDMA_AUTO:
mode = OFONO_RADIO_ACCESS_MODE_UMTS;

View File

@@ -53,6 +53,7 @@ static int rilmodem_init(void)
ril_call_barring_init();
ril_netmon_init();
ril_stk_init();
ril_cbs_init();
return 0;
}
@@ -76,6 +77,7 @@ static void rilmodem_exit(void)
ril_call_barring_exit();
ril_netmon_exit();
ril_stk_exit();
ril_cbs_exit();
}
OFONO_PLUGIN_DEFINE(rilmodem, "RIL modem driver", VERSION,

View File

@@ -75,3 +75,6 @@ extern void ril_netmon_exit(void);
extern void ril_stk_init(void);
extern void ril_stk_exit(void);
extern void ril_cbs_init(void);
extern void ril_cbs_exit(void);

View File

@@ -79,7 +79,7 @@
* The same applies to the app_type.
*/
static void ril_pin_change_state(struct ofono_sim *sim,
static void ril_set_facility_lock(struct ofono_sim *sim,
enum ofono_sim_password_type passwd_type,
int enable, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data);
@@ -1083,7 +1083,7 @@ static void ril_query_passwd_state(struct ofono_sim *sim,
CALLBACK_WITH_SUCCESS(cb, sd->passwd_state, data);
}
static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
static void ril_enter_sim_pin_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
@@ -1101,36 +1101,17 @@ static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
g_ril_init_parcel(message, &rilp);
/* maguro/infineon: no data is returned */
if (parcel_data_avail(&rilp) == 0)
goto done;
parcel_r_int32(&rilp);
switch (g_ril_vendor(sd->ril)) {
case OFONO_RIL_VENDOR_AOSP:
case OFONO_RIL_VENDOR_QCOM_MSIM:
/*
* The number of retries is valid only when a wrong password has
* been introduced in Nexus 4. TODO: check Nexus 5 behaviour.
*/
if (message->error == RIL_E_PASSWORD_INCORRECT)
sd->retries[sd->passwd_type] = parcel_r_int32(&rilp);
if (message->error == RIL_E_SUCCESS)
sd->retries[sd->passwd_type] = -1;
else
sd->retries[sd->passwd_type] = parcel_r_int32(&rilp);
g_ril_append_print_buf(sd->ril, "{%d}",
sd->retries[sd->passwd_type]);
g_ril_print_response(sd->ril, message);
g_ril_append_print_buf(sd->ril, "{%d}",
sd->retries[sd->passwd_type]);
g_ril_print_response(sd->ril, message);
break;
/* Taken care of elsewhere */
case OFONO_RIL_VENDOR_INFINEON:
case OFONO_RIL_VENDOR_MTK:
break;
default:
break;
}
done:
if (message->error == RIL_E_SUCCESS) {
CALLBACK_WITH_SUCCESS(cb, cbd->data);
return;
@@ -1167,30 +1148,13 @@ static void ril_pin_send(struct ofono_sim *sim, const char *passwd,
g_ril_append_print_buf(sd->ril, "(%s,aid=%s)", passwd, sd->aid_str);
if (g_ril_send(sd->ril, RIL_REQUEST_ENTER_SIM_PIN, &rilp,
ril_pin_change_state_cb, cbd, g_free) > 0)
ril_enter_sim_pin_cb, cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
static void enter_pin_done(const struct ofono_error *error, void *data)
{
struct change_state_cbd *csd = data;
struct sim_data *sd = ofono_sim_get_data(csd->sim);
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
ofono_error("%s: wrong password", __func__);
sd->unlock_pending = FALSE;
CALLBACK_WITH_FAILURE(csd->cb, csd->data);
} else {
ril_pin_change_state(csd->sim, csd->passwd_type, csd->enable,
csd->passwd, csd->cb, csd->data);
}
g_free(csd);
}
static const char *const clck_cpwd_fac[] = {
[OFONO_SIM_PASSWORD_SIM_PIN] = "SC",
[OFONO_SIM_PASSWORD_SIM_PIN2] = "P2",
@@ -1204,7 +1168,45 @@ static const char *const clck_cpwd_fac[] = {
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
static void ril_pin_change_state(struct ofono_sim *sim,
static void ril_set_facility_lock_cb(struct ril_msg *message,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
struct ofono_sim *sim = cbd->user;
struct sim_data *sd = ofono_sim_get_data(sim);
struct parcel rilp;
/*
* There is no reason to ask SIM status until
* unsolicited sim status change indication
* Looks like state does not change before that.
*/
DBG("Enter password: type %d, result %d",
sd->passwd_type, message->error);
g_ril_init_parcel(message, &rilp);
parcel_r_int32(&rilp);
if (message->error == RIL_E_SUCCESS)
sd->retries[sd->passwd_type] = -1;
else
sd->retries[sd->passwd_type] = parcel_r_int32(&rilp);
g_ril_append_print_buf(sd->ril, "{%d}",
sd->retries[sd->passwd_type]);
g_ril_print_response(sd->ril, message);
if (message->error == RIL_E_SUCCESS) {
CALLBACK_WITH_SUCCESS(cb, cbd->data);
return;
}
CALLBACK_WITH_FAILURE(cb, cbd->data);
}
static void ril_set_facility_lock(struct ofono_sim *sim,
enum ofono_sim_password_type passwd_type,
int enable, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
@@ -1213,29 +1215,8 @@ static void ril_pin_change_state(struct ofono_sim *sim,
struct cb_data *cbd;
struct parcel rilp;
/*
* If we want to unlock a password that has not been entered yet,
* we enter it before trying to unlock. We need sd->unlock_pending as
* the password still has not yet been refreshed when this function is
* called from enter_pin_done().
*/
if (ofono_sim_get_password_type(sim) == passwd_type
&& enable == FALSE && sd->unlock_pending == FALSE) {
struct change_state_cbd *csd = g_malloc0(sizeof(*csd));
csd->sim = sim;
csd->passwd_type = passwd_type;
csd->enable = enable;
csd->passwd = passwd;
csd->cb = cb;
csd->data = data;
sd->unlock_pending = TRUE;
ril_pin_send(sim, passwd, enter_pin_done, csd);
return;
}
sd->unlock_pending = FALSE;
sd->passwd_type = passwd_type;
if (passwd_type >= ARRAY_SIZE(clck_cpwd_fac) ||
clck_cpwd_fac[passwd_type] == NULL)
@@ -1257,7 +1238,7 @@ static void ril_pin_change_state(struct ofono_sim *sim,
sd->aid_str);
if (g_ril_send(sd->ril, RIL_REQUEST_SET_FACILITY_LOCK, &rilp,
ril_pin_change_state_cb, cbd, g_free) > 0)
ril_set_facility_lock_cb, cbd, g_free) > 0)
return;
g_free(cbd);
@@ -1265,6 +1246,37 @@ error:
CALLBACK_WITH_FAILURE(cb, data);
}
static void ril_enter_sim_puk_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
struct ofono_sim *sim = cbd->user;
struct sim_data *sd = ofono_sim_get_data(sim);
struct parcel rilp;
g_ril_init_parcel(message, &rilp);
parcel_r_int32(&rilp);
if (message->error != RIL_E_SUCCESS) {
sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = parcel_r_int32(&rilp);
} else {
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] = -1;
sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = -1;
}
g_ril_append_print_buf(sd->ril, "{%d}",
sd->retries[OFONO_SIM_PASSWORD_SIM_PUK]);
g_ril_print_response(sd->ril, message);
if (message->error == RIL_E_SUCCESS) {
CALLBACK_WITH_SUCCESS(cb, cbd->data);
return;
}
CALLBACK_WITH_FAILURE(cb, cbd->data);
}
static void ril_pin_send_puk(struct ofono_sim *sim,
const char *puk, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
@@ -1286,7 +1298,7 @@ static void ril_pin_send_puk(struct ofono_sim *sim,
puk, passwd, sd->aid_str);
if (g_ril_send(sd->ril, RIL_REQUEST_ENTER_SIM_PUK, &rilp,
ril_pin_change_state_cb, cbd, g_free) > 0)
ril_enter_sim_puk_cb, cbd, g_free) > 0)
return;
g_free(cbd);
@@ -1324,7 +1336,7 @@ static void ril_change_passwd(struct ofono_sim *sim,
g_ril_append_print_buf(sd->ril, "(old=%s,new=%s,aid=%s)",
old_passwd, new_passwd, sd->aid_str);
if (g_ril_send(sd->ril, request, &rilp, ril_pin_change_state_cb,
if (g_ril_send(sd->ril, request, &rilp, ril_enter_sim_pin_cb,
cbd, g_free) > 0)
return;
@@ -1413,12 +1425,17 @@ static void ril_query_facility_lock_cb(struct ril_msg *message,
struct sim_data *sd = cbd->user;
struct parcel rilp;
ofono_bool_t status;
int numparams;
if (message->error != RIL_E_SUCCESS)
goto error;
g_ril_init_parcel(message, &rilp);
numparams = parcel_r_int32(&rilp);
if (numparams < 1)
goto error;
status = (ofono_bool_t) parcel_r_int32(&rilp);
g_ril_append_print_buf(sd->ril, "{%d}", status);
@@ -1437,7 +1454,7 @@ static void ril_query_facility_lock(struct ofono_sim *sim,
void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data, sim);
struct cb_data *cbd = cb_data_new(cb, data, sd);
struct parcel rilp;
parcel_init(&rilp);
@@ -1483,7 +1500,7 @@ static struct ofono_sim_driver driver = {
.query_pin_retries = ril_query_pin_retries,
.reset_passwd = ril_pin_send_puk,
.change_passwd = ril_change_passwd,
.lock = ril_pin_change_state,
.lock = ril_set_facility_lock,
.query_facility_lock = ril_query_facility_lock,
};

View File

@@ -598,6 +598,13 @@ void g_at_mux_unref(GAtMux *mux)
}
}
static void read_watcher_destroy_notify(gpointer user_data)
{
GAtMux *mux = user_data;
mux->read_watch = 0;
}
gboolean g_at_mux_start(GAtMux *mux)
{
if (mux->channel == NULL)
@@ -611,7 +618,8 @@ gboolean g_at_mux_start(GAtMux *mux)
mux->read_watch = g_io_add_watch_full(mux->channel, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
received_data, mux, NULL);
received_data, mux,
read_watcher_destroy_notify);
mux->shutdown = FALSE;

View File

@@ -374,6 +374,12 @@ static void handle_response(struct ril_s *p, struct ril_msg *message)
if (req->callback)
req->callback(message, req->user_data);
/* gril may have been destroyed in the request callback */
if (p->destroyed) {
ril_request_destroy(req);
return;
}
len = g_queue_get_length(p->out_queue);
for (i = 0; i < len; i++) {

View File

@@ -75,7 +75,8 @@ extern char print_buf[];
#define g_ril_print_request(gril, token, req) \
G_RIL_TRACE(gril, "[%d,%04d]> %s %s", \
g_ril_get_slot(gril), token, \
g_ril_request_id_to_string(gril, req), print_buf)
g_ril_request_id_to_string(gril, req), print_buf); \
print_buf[0] = '\0';
#define g_ril_print_request_no_args(gril, token, req) \
G_RIL_TRACE(gril, "[%d,%04d]> %s", \
g_ril_get_slot(gril), token, \
@@ -85,7 +86,8 @@ extern char print_buf[];
g_ril_get_slot(gril), \
message->serial_no, \
g_ril_request_id_to_string(gril, message->req), \
print_buf)
print_buf); \
print_buf[0] = '\0';
#define g_ril_print_response_no_args(gril, message) \
G_RIL_TRACE(gril, "[%d,%04d]< %s", \
g_ril_get_slot(gril), message->serial_no, \

View File

@@ -55,7 +55,6 @@ enum ofono_gprs_auth_method {
struct ofono_gprs_primary_context {
unsigned int cid;
int direction;
char apn[OFONO_GPRS_MAX_APN_LENGTH + 1];
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];

View File

@@ -172,6 +172,8 @@ void ofono_voicecall_ssn_mt_notify(struct ofono_voicecall *vc, unsigned int id,
int code, int index,
const struct ofono_phone_number *ph);
struct ofono_call *ofono_voicecall_find_call(struct ofono_voicecall *vc,
unsigned int id);
void ofono_voicecall_ringback_tone_notify(struct ofono_voicecall *vc,
const ofono_bool_t playTone);

View File

@@ -1,8 +1,7 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2012-2015 Jolla Ltd.
* Copyright (C) 2012-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,11 +11,6 @@
* 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
@@ -35,9 +29,34 @@
#include "ofono.h"
#define NTD_WAIT_TIMEOUT (500) /* ms */
/*
* There are 3 distinct states here:
*
* 1. !valid
*
* Initial state, no time/timezone information whatsoever.
*
* 2. valid && !mccmnc
*
* Time/timezone information has been received from the network,
* but no MCC and MNC yet.
*
* 3. valid && mccmnc
*
* Time/timezone information is fully available.
*
*/
struct nt_data {
struct ofono_modem *modem;
struct ofono_netreg *netreg;
unsigned int netreg_watch_id;
unsigned int netreg_status_watch_id;
guint mccmnc_wait_id;
gboolean time_available;
gboolean time_pending;
gboolean valid;
time_t nw_time_utc;
time_t received;
@@ -47,27 +66,11 @@ struct nt_data {
char *mcc;
char *mnc;
char* path;
DBusConnection *conn;
};
static struct nt_data *nettime_new(const char *path)
{
struct nt_data *ntd = g_new0(struct nt_data, 1);
ntd->path = g_strdup(path);
ntd->conn = dbus_connection_ref(ofono_dbus_get_connection());
return ntd;
}
static void nettime_free(struct nt_data *ntd)
{
dbus_connection_unref(ntd->conn);
g_free(ntd->path);
g_free(ntd->mcc);
g_free(ntd->mnc);
g_free(ntd);
}
#define DBG_(ntd,fmt,args...) \
DBG("%s " fmt, ofono_modem_get_path((ntd)->modem), ##args)
static gboolean nettime_encode_time_format(struct tm *tm,
const struct ofono_network_time *time)
@@ -110,7 +113,7 @@ static int nettime_fill_time_notification(DBusMessage *msg, struct nt_data *ntd)
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
"{sv}",
&iter_array);
if (ntd->time_pending) {
if (ntd->valid && ntd->mcc && ntd->mnc) {
if (ntd->time_available) {
utc_long = (dbus_int64_t) ntd->nw_time_utc;
ofono_dbus_dict_append(&iter_array,
@@ -145,7 +148,7 @@ static int nettime_fill_time_notification(DBusMessage *msg, struct nt_data *ntd)
DBUS_TYPE_STRING,
&ntd->mnc);
} else {
DBG("fill_time_notification: time not available");
DBG_(ntd, "time not available");
}
dbus_message_iter_close_container(&iter, &iter_array);
@@ -177,23 +180,209 @@ static const GDBusSignalTable nettime_signals[] = {
{ }
};
static void nettime_send_signal(struct nt_data *ntd)
{
DBusMessage *signal =
dbus_message_new_signal(ofono_modem_get_path(ntd->modem),
OFONO_NETWORK_TIME_INTERFACE, "NetworkTimeChanged");
DBG_(ntd, "");
nettime_fill_time_notification(signal, ntd);
g_dbus_send_message(ntd->conn, signal);
}
static void nettime_set_mcc_mnc(struct nt_data *ntd, const char *mcc,
const char *mnc)
{
if (g_strcmp0(ntd->mcc, mcc)) {
g_free(ntd->mcc);
ntd->mcc = g_strdup(mcc);
}
if (g_strcmp0(ntd->mnc, mnc)) {
g_free(ntd->mnc);
ntd->mnc = g_strdup(mnc);
}
if (ntd->mcc && ntd->mnc) {
DBG_(ntd, "MCC: %s, MNC: %s", ntd->mcc, ntd->mnc);
if (ntd->mccmnc_wait_id) {
/* We have been waiting for MCC and MNC */
g_source_remove(ntd->mccmnc_wait_id);
ntd->mccmnc_wait_id = 0;
nettime_send_signal(ntd);
}
}
}
static void nettime_netreg_status_watch_cb(int status, int lac, int ci,
int tech, const char *mcc, const char *mnc,
void *userdata)
{
nettime_set_mcc_mnc(userdata, mcc, mnc);
}
static void nettime_netreg_status_watch_done(void *userdata)
{
struct nt_data *ntd = userdata;
DBG_(ntd, "");
ntd->netreg_status_watch_id = 0;
}
static void nettime_set_netreg(struct nt_data *ntd,
struct ofono_netreg *netreg)
{
if (ntd->netreg != netreg) {
ntd->valid = FALSE;
ntd->netreg = netreg;
if (netreg) {
nettime_set_mcc_mnc(ntd,
ofono_netreg_get_mcc(netreg),
ofono_netreg_get_mnc(netreg));
ntd->netreg_status_watch_id =
__ofono_netreg_add_status_watch(netreg,
nettime_netreg_status_watch_cb, ntd,
nettime_netreg_status_watch_done);
} else {
g_free(ntd->mcc);
g_free(ntd->mnc);
ntd->mcc = NULL;
ntd->mnc = NULL;
ntd->netreg_status_watch_id = 0;
}
}
}
static void nettime_netreg_watch_cb(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond, void *userdata)
{
struct nt_data *ntd = userdata;
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
DBG_(ntd, "registered");
nettime_set_netreg(ntd, __ofono_atom_get_data(atom));
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
DBG_(ntd, "unregistered");
nettime_set_netreg(ntd, NULL);
}
}
static void nettime_netreg_watch_done(void *userdata)
{
struct nt_data *ntd = userdata;
DBG_(ntd, "");
ntd->netreg_watch_id = 0;
}
static gboolean nettime_timeout_cb(gpointer data)
{
struct nt_data *ntd = data;
DBG_(ntd, "timed out");
ntd->mccmnc_wait_id = 0;
ntd->valid = FALSE;
return G_SOURCE_REMOVE;
}
static struct nt_data *nettime_new(struct ofono_modem *modem)
{
struct nt_data *ntd = g_new0(struct nt_data, 1);
struct ofono_atom *netreg_atom = __ofono_modem_find_atom(modem,
OFONO_ATOM_TYPE_NETREG);
ntd->modem = modem;
ntd->conn = dbus_connection_ref(ofono_dbus_get_connection());
ntd->netreg_watch_id = __ofono_modem_add_atom_watch(modem,
OFONO_ATOM_TYPE_NETREG, nettime_netreg_watch_cb,
ntd, nettime_netreg_watch_done);
if (netreg_atom) {
nettime_set_netreg(ntd, __ofono_atom_get_data(netreg_atom));
}
return ntd;
}
static void nettime_free(struct nt_data *ntd)
{
if (ntd->mccmnc_wait_id)
g_source_remove(ntd->mccmnc_wait_id);
if (ntd->netreg_status_watch_id)
__ofono_netreg_remove_status_watch(ntd->netreg,
ntd->netreg_status_watch_id);
if (ntd->netreg_watch_id)
__ofono_modem_remove_atom_watch(ntd->modem,
ntd->netreg_watch_id);
dbus_connection_unref(ntd->conn);
g_free(ntd->mcc);
g_free(ntd->mnc);
g_free(ntd);
}
static void nettime_info_received(struct ofono_nettime_context *context,
struct ofono_network_time *info)
{
struct nt_data *ntd = context->data;
struct tm t;
if (!ntd)
return;
ntd->received = nettime_get_monotonic_time();
ntd->valid = TRUE;
ntd->dst = info->dst;
ntd->time_zone = info->utcoff;
ntd->time_available = nettime_encode_time_format(&t, info);
if (ntd->time_available) {
ntd->nw_time_utc = timegm(&t);
}
DBG_(ntd, "time: %04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d (DST=%d)",
info->year, info->mon, info->mday, info->hour,
info->min, info->sec, info->utcoff > 0 ? '+' : '-',
abs(info->utcoff) / 3600, (abs(info->utcoff) % 3600) / 60,
info->dst);
DBG_(ntd, "UTC timestamp: %li, Received (monotonic time): %li",
ntd->nw_time_utc, ntd->received);
if (ntd->mcc && ntd->mnc) {
DBG_(ntd, "MCC: %s, MNC: %s", ntd->mcc, ntd->mnc);
nettime_send_signal(ntd);
} else {
DBG_(ntd, "no MCC/MNC yet");
if (ntd->mccmnc_wait_id)
g_source_remove(ntd->mccmnc_wait_id);
ntd->mccmnc_wait_id = g_timeout_add(NTD_WAIT_TIMEOUT,
nettime_timeout_cb, ntd);
}
}
static int nettime_probe(struct ofono_nettime_context *context)
{
struct nt_data *ntd = nettime_new(ofono_modem_get_path(context->modem));
struct nt_data *ntd = nettime_new(context->modem);
const char *path = ofono_modem_get_path(context->modem);
DBG("Network time probe for modem: %p (%s)", context->modem, ntd->path);
if (g_dbus_register_interface(ntd->conn, ntd->path,
DBG("Network time probe for modem: %p (%s)", context->modem, path);
if (g_dbus_register_interface(ntd->conn, path,
OFONO_NETWORK_TIME_INTERFACE, nettime_methods,
nettime_signals, NULL, ntd, NULL)) {
context->data = ntd;
ofono_info("Registered interface %s, path %s",
OFONO_NETWORK_TIME_INTERFACE, ntd->path);
OFONO_NETWORK_TIME_INTERFACE, path);
ofono_modem_add_interface(context->modem,
OFONO_NETWORK_TIME_INTERFACE);
return 0;
} else {
ofono_error("Could not register interface %s, path %s",
OFONO_NETWORK_TIME_INTERFACE, ntd->path);
OFONO_NETWORK_TIME_INTERFACE, path);
nettime_free(ntd);
return 1;
}
@@ -202,77 +391,16 @@ static int nettime_probe(struct ofono_nettime_context *context)
static void nettime_remove(struct ofono_nettime_context *context)
{
struct nt_data *ntd = context->data;
const char *path = ofono_modem_get_path(context->modem);
DBG("Network time remove for modem: %p (%s)", context->modem,
ofono_modem_get_path(context->modem));
DBG("Network time remove for modem: %p (%s)", context->modem, path);
ofono_modem_remove_interface(context->modem,
OFONO_NETWORK_TIME_INTERFACE);
if (!g_dbus_unregister_interface(ntd->conn, ntd->path,
OFONO_NETWORK_TIME_INTERFACE)) {
ofono_error("Network time: could not unregister interface %s"
" for %s", OFONO_NETWORK_TIME_INTERFACE, ntd->path);
}
g_dbus_unregister_interface(ntd->conn, path,
OFONO_NETWORK_TIME_INTERFACE);
nettime_free(ntd);
}
static void nettime_send_signal(struct nt_data *ntd)
{
DBusMessage *signal = dbus_message_new_signal(ntd->path,
OFONO_NETWORK_TIME_INTERFACE,
"NetworkTimeChanged");
nettime_fill_time_notification(signal, ntd);
g_dbus_send_message(ntd->conn, signal);
}
static void nettime_info_received(struct ofono_nettime_context *context,
struct ofono_network_time *info)
{
struct nt_data *ntd = context->data;
struct ofono_netreg *netreg;
const char *mcc;
const char *mnc;
struct tm t;
if (!ntd)
return;
netreg = __ofono_atom_get_data(__ofono_modem_find_atom(
context->modem, OFONO_ATOM_TYPE_NETREG));
mcc = ofono_netreg_get_mcc(netreg);
mnc = ofono_netreg_get_mnc(netreg);
if (!mcc || !mnc) {
DBG("Incomplete network time received, ignoring");
return;
}
g_free(ntd->mcc);
g_free(ntd->mnc);
ntd->mcc = g_strdup(mcc);
ntd->mnc = g_strdup(mnc);
ntd->received = nettime_get_monotonic_time();
ntd->time_pending = TRUE;
ntd->dst = info->dst;
ntd->time_zone = info->utcoff;
ntd->time_available = nettime_encode_time_format(&t, info);
if (ntd->time_available) {
ntd->nw_time_utc = timegm(&t);
}
nettime_send_signal(ntd);
DBG("modem: %p (%s)", context->modem, ntd->path);
DBG("time: %04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d (DST=%d)",
info->year, info->mon, info->mday, info->hour,
info->min, info->sec, info->utcoff > 0 ? '+' : '-',
abs(info->utcoff) / 3600, (abs(info->utcoff) % 3600) / 60,
info->dst);
DBG("UTC timestamp: %li, Received (monotonic time): %li",
ntd->nw_time_utc, ntd->received);
DBG("MCC: %s, MNC: %s", ntd->mcc, ntd->mnc);
}
static struct ofono_nettime_driver driver = {
.name = "Network Time",
.probe = nettime_probe,

View File

@@ -3,7 +3,6 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,7 +23,6 @@
#include <config.h>
#endif
#define _GNU_SOURCE
#include <errno.h>
#include <string.h>
@@ -37,114 +35,9 @@
#include <ofono/modem.h>
#include <ofono/gprs-provision.h>
#include "provision.h"
#include "mbpi.h"
struct provision_ap_defaults {
enum ofono_gprs_context_type type;
const char *name;
const char *apn;
};
static gboolean provision_match_name(const struct ofono_gprs_provision_data *ap,
const char* spn)
{
return (ap->provider_name && strcasestr(ap->provider_name, spn)) ||
(ap->name && strcasestr(ap->name, spn)) ||
(ap->apn && strcasestr(ap->apn, spn));
}
static void provision_free_ap(gpointer data)
{
mbpi_ap_free(data);
}
static gint provision_compare_ap(gconstpointer a, gconstpointer b, gpointer data)
{
const struct ofono_gprs_provision_data *ap1 = a;
const struct ofono_gprs_provision_data *ap2 = b;
const char* spn = data;
if (spn) {
const gboolean match1 = provision_match_name(ap1, spn);
const gboolean match2 = provision_match_name(ap2, spn);
if (match1 && !match2) {
return -1;
} else if (match2 && !match1) {
return 1;
}
}
if (ap1->provider_primary && !ap2->provider_primary) {
return -1;
} else if (ap2->provider_primary && !ap1->provider_primary) {
return 1;
} else {
return 0;
}
}
/* Picks best ap, deletes the rest. Creates one if necessary */
static GSList *provision_pick_best_ap(GSList *list, const char* spn,
const enum ofono_gprs_proto default_proto,
const struct provision_ap_defaults *defaults)
{
/* Sort the list */
list = g_slist_sort_with_data(list, provision_compare_ap, (void*)spn);
if (list) {
/* Pick the best one, delete the rest */
GSList *best = list;
g_slist_free_full(g_slist_remove_link(list, best),
provision_free_ap);
return best;
} else {
/* or create one from the default data */
struct ofono_gprs_provision_data *ap =
g_new0(struct ofono_gprs_provision_data, 1);
ap->proto = default_proto;
ap->type = defaults->type;
ap->name = g_strdup(defaults->name);
ap->apn = g_strdup(defaults->apn);
return g_slist_append(NULL, ap);
}
}
/* Returns the list containing exactly one INTERNET and one MMS access point */
static GSList *provision_normalize_apn_list(GSList *apns, const char* spn)
{
static const struct provision_ap_defaults internet_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
static const struct provision_ap_defaults mms_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
GSList *internet_apns = NULL;
GSList *mms_apns = NULL;
/* Split internet and mms apns, delete all others */
while (apns) {
GSList *link = apns;
struct ofono_gprs_provision_data *ap = link->data;
apns = g_slist_remove_link(apns, link);
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
internet_apns = g_slist_concat(internet_apns, link);
} else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
mms_apns = g_slist_concat(mms_apns, link);
} else {
g_slist_free_full(link, provision_free_ap);
}
}
/* Pick the best ap of each type and concatenate them */
return g_slist_concat(
provision_pick_best_ap(internet_apns, spn,
mbpi_default_internet_proto, &internet_defaults),
provision_pick_best_ap(mms_apns, spn,
mbpi_default_mms_proto, &mms_defaults));
}
int provision_get_settings(const char *mcc, const char *mnc,
static int provision_get_settings(const char *mcc, const char *mnc,
const char *spn,
struct ofono_gprs_provision_data **settings,
int *count)
@@ -155,26 +48,21 @@ int provision_get_settings(const char *mcc, const char *mnc,
int ap_count;
int i;
ofono_info("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
DBG("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
/*
* Passing FALSE to mbpi_lookup_apn() would return
* an empty list if duplicates are found.
*/
apns = mbpi_lookup_apn(mcc, mnc, TRUE, &error);
if (error != NULL) {
ofono_error("%s", error->message);
g_error_free(error);
}
apns = mbpi_lookup_apn(mcc, mnc, FALSE, &error);
if (apns == NULL) {
if (error != NULL) {
ofono_error("%s", error->message);
g_error_free(error);
}
ofono_info("Found %d APs in MBPI", g_slist_length(apns));
apns = provision_normalize_apn_list(apns, spn);
if (apns == NULL)
return -ENOENT;
}
ap_count = g_slist_length(apns);
ofono_info("Provisioning %d APs", ap_count);
DBG("Found %d APs", ap_count);
*settings = g_try_new0(struct ofono_gprs_provision_data, ap_count);
if (*settings == NULL) {
@@ -193,11 +81,11 @@ int provision_get_settings(const char *mcc, const char *mnc,
for (l = apns, i = 0; l; l = l->next, i++) {
struct ofono_gprs_provision_data *ap = l->data;
ofono_info("Name: '%s'", ap->name);
ofono_info("APN: '%s'", ap->apn);
ofono_info("Type: %s", mbpi_ap_type(ap->type));
ofono_info("Username: '%s'", ap->username);
ofono_info("Password: '%s'", ap->password);
DBG("Name: '%s'", ap->name);
DBG("APN: '%s'", ap->apn);
DBG("Type: %s", mbpi_ap_type(ap->type));
DBG("Username: '%s'", ap->username);
DBG("Password: '%s'", ap->password);
memcpy(*settings + i, ap,
sizeof(struct ofono_gprs_provision_data));

View File

@@ -239,6 +239,7 @@ void ril_post_online(struct ofono_modem *modem)
struct ofono_gprs *gprs;
struct ofono_gprs_context *gc;
ofono_cbs_create(modem, rd->vendor, RILMODEM, rd->ril);
ofono_netreg_create(modem, rd->vendor, RILMODEM, rd->ril);
ofono_ussd_create(modem, rd->vendor, RILMODEM, rd->ril);
ofono_call_settings_create(modem, rd->vendor, RILMODEM, rd->ril);
@@ -409,15 +410,30 @@ int ril_enable(struct ofono_modem *modem)
return -EINPROGRESS;
}
static void power_off_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
struct ril_data *rd = cbd->user;
struct ofono_modem *modem = cbd->data;
if (rd) {
g_ril_unref(rd->ril);
rd->ril = NULL;
}
ofono_modem_set_powered(modem, FALSE);
}
int ril_disable(struct ofono_modem *modem)
{
struct ril_data *rd = ofono_modem_get_data(modem);
struct cb_data *cbd = cb_data_new(NULL, modem, rd);
DBG("%p", modem);
ril_send_power(rd, FALSE, NULL, NULL);
ril_send_power(rd, FALSE, power_off_cb, cbd);
return 0;
return -EINPROGRESS;
}
static struct ofono_modem_driver ril_driver = {

View File

@@ -29,6 +29,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <glib.h>
@@ -52,11 +53,22 @@
#include "drivers/rilmodem/rilmodem.h"
#include "drivers/rilmodem/vendor.h"
#include "gdbus.h"
#include "ofono.h"
#define THERMAL_MANAGEMENT_INTERFACE OFONO_SERVICE ".sofia3gr.ThermalManagement"
struct ril_data {
GRil *ril;
};
struct ril_thermal_management {
DBusMessage *pending;
struct ofono_modem *modem;
dbus_bool_t throttling;
};
static int ril_send_power(GRil *ril, ofono_bool_t online,
GRilResponseFunc func,
gpointer user_data,
@@ -129,7 +141,14 @@ static int ril_probe(struct ofono_modem *modem)
static void ril_remove(struct ofono_modem *modem)
{
DBusConnection *conn = ofono_dbus_get_connection();
struct ril_data *rd = ofono_modem_get_data(modem);
const char *path = ofono_modem_get_path(modem);
if (g_dbus_unregister_interface(conn, path,
THERMAL_MANAGEMENT_INTERFACE))
ofono_modem_remove_interface(modem,
THERMAL_MANAGEMENT_INTERFACE);
ofono_modem_set_data(modem, NULL);
@@ -137,6 +156,270 @@ static void ril_remove(struct ofono_modem *modem)
g_free(rd);
}
static void set_rf_power_status_cb(struct ril_msg *message, gpointer user_data)
{
DBusConnection *conn = ofono_dbus_get_connection();
struct ril_thermal_management *tm = user_data;
struct ril_data *rd = ofono_modem_get_data(tm->modem);
const char *path = ofono_modem_get_path(tm->modem);
DBG("");
if (message->error != RIL_E_SUCCESS) {
ofono_error("%s RILD reply failure: %s",
g_ril_request_id_to_string(rd->ril, message->req),
ril_error_to_string(message->error));
__ofono_dbus_pending_reply(&tm->pending,
__ofono_error_failed(tm->pending));
return;
}
/* Change the throttling state */
tm->throttling = tm->throttling ? false : true;
__ofono_dbus_pending_reply(&tm->pending,
dbus_message_new_method_return(tm->pending));
ofono_dbus_signal_property_changed(conn, path,
THERMAL_MANAGEMENT_INTERFACE,
"TransmitPowerThrottling",
DBUS_TYPE_BOOLEAN,
&tm->throttling);
}
static DBusMessage *set_rf_power_status(DBusMessage *msg,
dbus_bool_t enable,
void *data)
{
struct ril_thermal_management *tm = data;
struct ril_data *rd = ofono_modem_get_data(tm->modem);
struct parcel rilp;
int cmd_id;
char buf[4];
DBG("");
if (tm->pending)
return __ofono_error_busy(msg);
parcel_init(&rilp);
parcel_w_int32(&rilp, 2);
/* RIL_OEM_HOOK_STRING_SET_RF_POWER_STATUS = 0x000000AC */
cmd_id = 0x000000AC;
sprintf(buf, "%d", cmd_id);
parcel_w_string(&rilp, buf);
memset(buf, 0, sizeof(buf));
sprintf(buf, "%d", enable ? 1 : 0);
parcel_w_string(&rilp, buf);
g_ril_append_print_buf(rd->ril, "{cmd_id=0x%02X,arg=%s}", cmd_id, buf);
if (g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
set_rf_power_status_cb, tm, NULL) == 0)
return __ofono_error_failed(msg);
tm->pending = dbus_message_ref(msg);
return NULL;
}
static DBusMessage *thermal_management_set_property(DBusConnection *conn,
DBusMessage *msg,
void *data)
{
struct ril_thermal_management *tm = data;
DBusMessageIter iter;
DBusMessageIter var;
const char *name;
dbus_bool_t throttling;
DBG("");
if (!ofono_modem_get_online(tm->modem))
return __ofono_error_not_available(msg);
if (!dbus_message_iter_init(msg, &iter))
return __ofono_error_invalid_args(msg);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &name);
if (!strcmp(name, "TransmitPowerThrottling")) {
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
return __ofono_error_invalid_args(msg);
dbus_message_iter_recurse(&iter, &var);
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &throttling);
if (tm->throttling == throttling)
/* Ignore set request if new state == current state */
return dbus_message_new_method_return(msg);
return set_rf_power_status(msg, throttling, tm);
}
return __ofono_error_invalid_args(msg);
}
static DBusMessage *thermal_management_get_properties(DBusConnection *conn,
DBusMessage *msg,
void *data)
{
struct ril_thermal_management *tm = data;
DBusMessage *reply;
DBusMessageIter iter;
DBusMessageIter dict;
DBG("");
reply = dbus_message_new_method_return(msg);
if (reply == NULL)
return NULL;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
OFONO_PROPERTIES_ARRAY_SIGNATURE,
&dict);
ofono_dbus_dict_append(&dict, "TransmitPowerThrottling",
DBUS_TYPE_BOOLEAN,
&tm->throttling);
dbus_message_iter_close_container(&iter, &dict);
return reply;
}
static const GDBusMethodTable thermal_management_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
thermal_management_get_properties) },
{ GDBUS_ASYNC_METHOD("SetProperty",
GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
NULL, thermal_management_set_property) },
{}
};
static const GDBusSignalTable thermal_management_signals[] = {
{ GDBUS_SIGNAL("PropertyChanged",
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
{ }
};
static void thermal_management_cleanup(void *data)
{
struct ril_thermal_management *tm = data;
if (tm->pending)
__ofono_dbus_pending_reply(&tm->pending,
__ofono_error_canceled(tm->pending));
g_free(tm);
}
static void get_rf_power_status_cb(struct ril_msg *message, gpointer user_data)
{
struct ofono_modem *modem = user_data;
struct ril_data *rd = ofono_modem_get_data(modem);
struct ril_thermal_management *tm;
DBusConnection *conn = ofono_dbus_get_connection();
struct parcel rilp;
gint numstr;
gchar *power_status;
char *endptr;
int enabled;
const char *path = ofono_modem_get_path(modem);
DBG("");
if (message->error != RIL_E_SUCCESS) {
ofono_error("%s RILD reply failure: %s",
g_ril_request_id_to_string(rd->ril, message->req),
ril_error_to_string(message->error));
return;
}
g_ril_init_parcel(message, &rilp);
numstr = parcel_r_int32(&rilp);
if (numstr < 1) {
ofono_error("RILD reply empty !");
return;
}
power_status = parcel_r_string(&rilp);
if (power_status == NULL || power_status == '\0')
return;
enabled = strtol(power_status, &endptr, 10);
/*
* power_status == endptr => conversion error
* *endptr != '\0' => partial conversion
*/
if (power_status == endptr || *endptr != '\0')
return;
tm = g_try_new0(struct ril_thermal_management, 1);
if (tm == NULL)
return;
tm->modem = modem;
tm->throttling = (enabled > 0) ? true : false;
if (!g_dbus_register_interface(conn, path, THERMAL_MANAGEMENT_INTERFACE,
thermal_management_methods,
thermal_management_signals,
NULL, tm, thermal_management_cleanup)) {
ofono_error("Could not register %s interface under %s",
THERMAL_MANAGEMENT_INTERFACE, path);
g_free(tm);
return;
}
ofono_modem_add_interface(modem, THERMAL_MANAGEMENT_INTERFACE);
}
static int ril_thermal_management_enable(struct ofono_modem *modem)
{
struct ril_data *rd = ofono_modem_get_data(modem);
struct parcel rilp;
int cmd_id;
char buf[4];
DBG("");
parcel_init(&rilp);
parcel_w_int32(&rilp, 1);
/* RIL_OEM_HOOK_STRING_GET_RF_POWER_STATUS = 0x000000AB */
cmd_id = 0x000000AB;
sprintf(buf, "%d", cmd_id);
parcel_w_string(&rilp, buf);
g_ril_append_print_buf(rd->ril, "{cmd_id=0x%02X}", cmd_id);
if (g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
get_rf_power_status_cb, modem, NULL) > 0)
return 0;
/* Error path */
return -EIO;
}
static void ril_pre_sim(struct ofono_modem *modem)
{
struct ril_data *rd = ofono_modem_get_data(modem);
@@ -145,6 +428,7 @@ static void ril_pre_sim(struct ofono_modem *modem)
ofono_devinfo_create(modem, 0, "rilmodem", rd->ril);
ofono_sim_create(modem, 0, "rilmodem", rd->ril);
ril_thermal_management_enable(modem);
}
static void ril_post_sim(struct ofono_modem *modem)
@@ -255,14 +539,45 @@ static int ril_enable(struct ofono_modem *modem)
return -EINPROGRESS;
}
static int ril_disable(struct ofono_modem *modem)
static void ril_send_power_off_cb(struct ril_msg *message, gpointer user_data)
{
struct ofono_modem *modem = (struct ofono_modem *) user_data;
struct ril_data *rd = ofono_modem_get_data(modem);
DBG("%p", modem);
ril_send_power(rd->ril, FALSE, NULL, NULL, NULL);
g_ril_unref(rd->ril);
return 0;
ofono_modem_set_powered(modem, FALSE);
}
static int ril_disable(struct ofono_modem *modem)
{
DBusConnection *conn = ofono_dbus_get_connection();
struct ril_data *rd = ofono_modem_get_data(modem);
const char *path = ofono_modem_get_path(modem);
struct parcel rilp;
int cmd_id;
char buf[4];
DBG("%p", modem);
if (g_dbus_unregister_interface(conn, path,
THERMAL_MANAGEMENT_INTERFACE))
ofono_modem_remove_interface(modem,
THERMAL_MANAGEMENT_INTERFACE);
/* RIL_OEM_HOOK_STRING_SET_MODEM_OFF = 0x000000CF */
cmd_id = 0x000000CF;
sprintf(buf, "%d", cmd_id);
parcel_init(&rilp);
parcel_w_int32(&rilp, 1);
parcel_w_string(&rilp, buf);
g_ril_append_print_buf(rd->ril, "{cmd_id=0x%02X}", cmd_id);
g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
ril_send_power_off_cb, modem, NULL);
return -EINPROGRESS;
}
static struct ofono_modem_driver ril_driver = {

362
ofono/plugins/sailfish_bt.c Normal file
View File

@@ -0,0 +1,362 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <glib.h>
#include <ofono.h>
#include <gdbus.h>
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include <ofono/log.h>
#define SFOS_BT_DBUS_CV_INTERFACE "org.nemomobile.ofono.bluetooth.CallVolume"
#define HFP_CALL_VOLUME_MAX 15
struct sfos_bt {
unsigned int emu_watch;
struct ofono_modem *modem;
struct ofono_emulator *em;
unsigned char speaker_volume;
unsigned char microphone_volume;
};
static GSList *modems;
static guint modemwatch_id;
static void set_hfp_microphone_volume(struct sfos_bt *sfos_bt,
unsigned char gain)
{
char buf[64];
snprintf(buf, sizeof(buf), "+VGM:%d", (int) gain);
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
}
static void set_hfp_speaker_volume(struct sfos_bt *sfos_bt,
unsigned char gain)
{
char buf[64];
snprintf(buf, sizeof(buf), "+VGS:%d", (int) gain);
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
}
static DBusMessage *cv_set_property(DBusConnection *conn, DBusMessage *msg,
void *data)
{
struct sfos_bt *sfos_bt = data;
DBusMessageIter iter;
DBusMessageIter var;
const char *property;
if (!dbus_message_iter_init(msg, &iter))
return __ofono_error_invalid_args(msg);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &property);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
return __ofono_error_invalid_args(msg);
dbus_message_iter_recurse(&iter, &var);
if (g_str_equal(property, "SpeakerVolume") == TRUE) {
unsigned char gain;
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BYTE)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &gain);
if (gain > HFP_CALL_VOLUME_MAX)
return __ofono_error_invalid_format(msg);
if (gain == sfos_bt->speaker_volume)
return dbus_message_new_method_return(msg);
DBG("SpeakerVolume:%d", gain);
sfos_bt->speaker_volume = gain;
set_hfp_speaker_volume(sfos_bt, gain);
return dbus_message_new_method_return(msg);
} else if (g_str_equal(property, "MicrophoneVolume") == TRUE) {
unsigned char gain;
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BYTE)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &gain);
if (gain > HFP_CALL_VOLUME_MAX)
return __ofono_error_invalid_format(msg);
if (gain == sfos_bt->microphone_volume)
return dbus_message_new_method_return(msg);
DBG("MicrophoneVolume:%d", gain);
sfos_bt->microphone_volume = gain;
set_hfp_microphone_volume(sfos_bt, gain);
return dbus_message_new_method_return(msg);
} else if (g_str_equal(property, "Muted") == TRUE) {
unsigned char gain;
dbus_bool_t muted;
/*Remove when supported*/
return __ofono_error_not_implemented(msg);
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &muted);
if (muted)
gain = 0;
else
gain = 7;/* rather gain = sfos->old_mic_vol */
if (gain == sfos_bt->microphone_volume)
return dbus_message_new_method_return(msg);
sfos_bt->microphone_volume = gain;
set_hfp_microphone_volume(sfos_bt, gain);
return dbus_message_new_method_return(msg);
}
return __ofono_error_invalid_args(msg);
}
static const GDBusMethodTable cv_methods[] = {
{ GDBUS_METHOD("SetProperty",
GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
NULL, cv_set_property) },
{ }
};
static const GDBusSignalTable cv_signals[] = {
{ GDBUS_SIGNAL("PropertyChanged",
GDBUS_ARGS({ "property", "s" }, { "value", "v" })) },
{ }
};
int sfos_bt_call_volume_set(struct ofono_modem *modem, unsigned char volume,
const char *gain)
{
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = ofono_modem_get_path(modem);
return ofono_dbus_signal_property_changed(conn, path,
SFOS_BT_DBUS_CV_INTERFACE,
gain,
DBUS_TYPE_BYTE, &volume);
}
static void set_gain(struct ofono_emulator *em,
struct ofono_emulator_request *req,
void *userdata, const char *gain)
{
struct sfos_bt *sfos_bt = userdata;
struct ofono_modem *modem = sfos_bt->modem;
struct ofono_error result;
unsigned char volume;
int val;
result.error = 0;
switch (ofono_emulator_request_get_type(req)) {
case OFONO_EMULATOR_REQUEST_TYPE_SET:
if (ofono_emulator_request_next_number(req, &val) == FALSE)
goto fail;
if (val < 0 || val > 0xffff || val > HFP_CALL_VOLUME_MAX)
goto fail;
DBG("gain:%d", val);
volume = (unsigned char) val;
if (sfos_bt_call_volume_set(modem, volume, gain)<= 0)
goto fail;
if (!g_strcmp0(gain, "SpeakerVolume"))
sfos_bt->speaker_volume = volume;
else
sfos_bt->microphone_volume = volume;
result.type = OFONO_ERROR_TYPE_NO_ERROR;
ofono_emulator_send_final(em, &result);
break;
default:
fail:
result.type = OFONO_ERROR_TYPE_FAILURE;
ofono_emulator_send_final(em, &result);
break;
}
}
static void sfos_bt_vgm_cb(struct ofono_emulator *em,
struct ofono_emulator_request *req, void *userdata)
{
const char *gain = "MicrophoneVolume";
set_gain(em, req, userdata, gain);
}
static void sfos_bt_vgs_cb(struct ofono_emulator *em,
struct ofono_emulator_request *req, void *userdata)
{
const char *gain = "SpeakerVolume";
set_gain(em, req, userdata, gain);
}
void sfos_bt_cv_dbus_new(struct sfos_bt *sfos_bt)
{
DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = sfos_bt->modem;
const char *path = ofono_modem_get_path(modem);
if (g_dbus_register_interface(conn, path,
SFOS_BT_DBUS_CV_INTERFACE, cv_methods,
cv_signals, NULL, sfos_bt, NULL)){
ofono_modem_add_interface(modem,SFOS_BT_DBUS_CV_INTERFACE);
return;
}
ofono_error("D-Bus register failed");
}
static void sfos_bt_remove_handler(struct ofono_emulator *em)
{
ofono_emulator_remove_handler(em, "+VGS");
ofono_emulator_remove_handler(em, "+VGM");
}
void sfos_bt_cv_dbus_free(struct sfos_bt *sfos_bt)
{
DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = sfos_bt->modem;
const char *path = ofono_modem_get_path(modem);
ofono_modem_remove_interface(modem, SFOS_BT_DBUS_CV_INTERFACE);
g_dbus_unregister_interface(conn, path,
SFOS_BT_DBUS_CV_INTERFACE);
}
static void sfos_bt_emu_watch_cb(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond,
void *data)
{
struct sfos_bt *sfos_bt = data;
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED){
sfos_bt->em = __ofono_atom_get_data(atom);
sfos_bt_cv_dbus_new(sfos_bt);
ofono_emulator_add_handler(sfos_bt->em, "+VGS",
sfos_bt_vgs_cb, sfos_bt, NULL);
ofono_emulator_add_handler(sfos_bt->em, "+VGM",
sfos_bt_vgm_cb, sfos_bt, NULL);
} else {
sfos_bt_cv_dbus_free(sfos_bt);
sfos_bt_remove_handler(sfos_bt->em);
sfos_bt->em = NULL;
}
}
static void sfos_bt_emu_watch_destroy(void *data)
{
struct sfos_bt *sfos_bt = data;
sfos_bt->emu_watch = 0;
}
static void sfos_bt_free(void *data)
{
struct sfos_bt *sfos_bt = data;
if (sfos_bt->emu_watch)
__ofono_modem_remove_atom_watch(sfos_bt->modem,
sfos_bt->emu_watch);
if (sfos_bt->em) {
sfos_bt_cv_dbus_free(sfos_bt);
sfos_bt_remove_handler(sfos_bt->em);
}
g_free(sfos_bt);
}
static gint sfos_bt_find_modem(gconstpointer listdata, gconstpointer modem)
{
const struct sfos_bt *sfos_bt = listdata;
return (sfos_bt->modem != modem);
}
static void modem_watch(struct ofono_modem *modem, gboolean added, void *user)
{
struct sfos_bt *sfos_bt;
DBG("modem: %p, added: %d", modem, added);
if (added) {
sfos_bt = g_new0(struct sfos_bt, 1);
modems = g_slist_append(modems, sfos_bt);
sfos_bt->emu_watch = __ofono_modem_add_atom_watch(modem,
OFONO_ATOM_TYPE_EMULATOR_HFP, sfos_bt_emu_watch_cb,
sfos_bt, sfos_bt_emu_watch_destroy);
sfos_bt->modem = modem;
} else {
GSList *link = g_slist_find_custom(modems, modem,
sfos_bt_find_modem);
if (link) {
sfos_bt_free(link->data);
modems = g_slist_delete_link(modems, link);
}
}
}
static void call_modemwatch(struct ofono_modem *modem, void *user)
{
modem_watch(modem, TRUE, user);
}
static int sfos_bt_init(void)
{
modemwatch_id = __ofono_modemwatch_add(modem_watch, NULL, NULL);
__ofono_modem_foreach(call_modemwatch, NULL);
return 0;
}
static void sfos_bt_exit(void)
{
DBG("");
__ofono_modemwatch_remove(modemwatch_id);
g_slist_free_full(modems, sfos_bt_free);
}
OFONO_PLUGIN_DEFINE(sfos_bt, "Sailfish OS Bluetooth Plugin", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT,
sfos_bt_init, sfos_bt_exit)

View File

@@ -0,0 +1,250 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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
#define _GNU_SOURCE
#include <errno.h>
#include <string.h>
#include <glib.h>
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/log.h>
#include <ofono/plugin.h>
#include <ofono/modem.h>
#include <ofono/gprs-provision.h>
#include "provision.h"
#include "mbpi.h"
struct provision_ap_defaults {
enum ofono_gprs_context_type type;
const char *name;
const char *apn;
};
static gint provision_match_strings(const char *s1, const char *s2)
{
gint match = 0;
/* Caller checks s2 for NULL */
if (s1) {
const gssize len1 = strlen(s1);
const gssize len2 = strlen(s2);
if (len1 == len2 && !strcmp(s1, s2)) {
/* Best match ever */
match = 3;
} else if (g_utf8_validate(s1, len1, NULL) &&
g_utf8_validate(s2, len2, NULL)) {
char *d1 = g_utf8_strdown(s1, len1);
char *d2 = g_utf8_strdown(s2, len2);
if (len1 == len2 && !strcmp(d1, d2)) {
/* Case insensitive match */
match = 2;
} else if ((len1 > len2 && strstr(d1, d2)) ||
(len2 > len1 && strstr(d2, d1))) {
/* Partial case insensitive match */
match = 1;
}
g_free(d1);
g_free(d2);
}
}
return match;
}
static gint provision_match_spn(const struct ofono_gprs_provision_data *ap,
const char *spn)
{
return provision_match_strings(ap->provider_name, spn) * 4 +
provision_match_strings(ap->name, spn);
}
static void provision_free_ap(gpointer data)
{
mbpi_ap_free(data);
}
static gint provision_compare_ap(gconstpointer a, gconstpointer b,
gpointer data)
{
const struct ofono_gprs_provision_data *ap1 = a;
const struct ofono_gprs_provision_data *ap2 = b;
const char *spn = data;
if (spn) {
const gint result = provision_match_spn(ap2, spn) -
provision_match_spn(ap1, spn);
if (result) {
return result;
}
}
if (ap1->provider_primary && !ap2->provider_primary) {
return -1;
} else if (ap2->provider_primary && !ap1->provider_primary) {
return 1;
}
return 0;
}
/* Picks best ap, deletes the rest. Creates one if necessary */
static GSList *provision_pick_best_ap(GSList *list, const char *spn,
const enum ofono_gprs_proto default_proto,
const struct provision_ap_defaults *defaults)
{
/* Sort the list */
list = g_slist_sort_with_data(list, provision_compare_ap, (void*)spn);
if (list) {
/* Pick the best one, delete the rest */
GSList *best = list;
g_slist_free_full(g_slist_remove_link(list, best),
provision_free_ap);
return best;
} else {
/* or create one from the default data */
struct ofono_gprs_provision_data *ap =
g_new0(struct ofono_gprs_provision_data, 1);
ap->proto = default_proto;
ap->type = defaults->type;
ap->name = g_strdup(defaults->name);
ap->apn = g_strdup(defaults->apn);
return g_slist_append(NULL, ap);
}
}
/* Returns the list containing exactly one INTERNET and one MMS access point */
static GSList *provision_normalize_apn_list(GSList *apns, const char *spn)
{
static const struct provision_ap_defaults internet_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
static const struct provision_ap_defaults mms_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
GSList *internet_apns = NULL;
GSList *mms_apns = NULL;
/* Split internet and mms apns, delete all others */
while (apns) {
GSList *link = apns;
struct ofono_gprs_provision_data *ap = link->data;
apns = g_slist_remove_link(apns, link);
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
internet_apns = g_slist_concat(internet_apns, link);
} else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
mms_apns = g_slist_concat(mms_apns, link);
} else {
g_slist_free_full(link, provision_free_ap);
}
}
/* Pick the best ap of each type and concatenate them */
return g_slist_concat(
provision_pick_best_ap(internet_apns, spn,
mbpi_default_internet_proto, &internet_defaults),
provision_pick_best_ap(mms_apns, spn,
mbpi_default_mms_proto, &mms_defaults));
}
int provision_get_settings(const char *mcc, const char *mnc,
const char *spn,
struct ofono_gprs_provision_data **settings,
int *count)
{
GSList *l;
GSList *apns;
GError *error = NULL;
int ap_count;
int i;
ofono_info("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
/*
* Passing FALSE to mbpi_lookup_apn() would return
* an empty list if duplicates are found.
*/
apns = mbpi_lookup_apn(mcc, mnc, TRUE, &error);
if (error != NULL) {
ofono_error("%s", error->message);
g_error_free(error);
}
DBG("Found %d APs in MBPI", g_slist_length(apns));
apns = provision_normalize_apn_list(apns, spn);
ap_count = g_slist_length(apns);
DBG("Provisioning %d APs", ap_count);
*settings = g_new0(struct ofono_gprs_provision_data, ap_count);
*count = ap_count;
for (l = apns, i = 0; l; l = l->next, i++) {
struct ofono_gprs_provision_data *ap = l->data;
ofono_info("Name: '%s'", ap->name);
ofono_info(" APN: '%s'", ap->apn);
ofono_info(" Type: %s", mbpi_ap_type(ap->type));
ofono_info(" Username: '%s'", ap->username);
ofono_info(" Password: '%s'", ap->password);
memcpy(*settings + i, ap,
sizeof(struct ofono_gprs_provision_data));
g_free(ap);
}
g_slist_free(apns);
return 0;
}
static struct ofono_gprs_provision_driver provision_driver = {
.name = "Provisioning",
.get_settings = provision_get_settings
};
static int provision_init(void)
{
DBG("");
return ofono_gprs_provision_driver_register(&provision_driver);
}
static void provision_exit(void)
{
DBG("");
ofono_gprs_provision_driver_unregister(&provision_driver);
}
OFONO_PLUGIN_DEFINE(provision, "Provisioning Plugin", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT,
provision_init, provision_exit)
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2014 Jolla Ltd.
* Copyright (C) 2013-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -9,7 +9,6 @@
* 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
@@ -536,6 +535,6 @@ static void pf_plugin_exit(void)
inotify_fd = -1;
}
OFONO_PLUGIN_DEFINE(push_forwarder, "Push Forwarder Plugin", VERSION,
OFONO_PLUGIN_DEFINE(pushforwarder, "Push Forwarder Plugin", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT, pf_plugin_init,
pf_plugin_exit)

View File

@@ -325,11 +325,14 @@ static gboolean setup_huawei(struct modem_info *modem)
if (g_strcmp0(info->label, "modem") == 0 ||
g_strcmp0(info->interface, "255/1/1") == 0 ||
g_strcmp0(info->interface, "255/2/1") == 0 ||
g_strcmp0(info->interface, "255/3/1") == 0 ||
g_strcmp0(info->interface, "255/1/49") == 0) {
mdm = info->devnode;
} else if (g_strcmp0(info->label, "pcui") == 0 ||
g_strcmp0(info->interface, "255/1/2") == 0 ||
g_strcmp0(info->interface, "255/2/2") == 0 ||
g_strcmp0(info->interface, "255/2/18") == 0 ||
g_strcmp0(info->interface, "255/3/18") == 0 ||
g_strcmp0(info->interface, "255/1/50") == 0) {
pcui = info->devnode;
} else if (g_strcmp0(info->label, "diag") == 0 ||

View File

@@ -135,6 +135,7 @@ struct pri_context {
struct ofono_gprs *gprs;
};
static void gprs_attached_update(struct ofono_gprs *gprs);
static void gprs_netreg_update(struct ofono_gprs *gprs);
static void gprs_deactivate_next(struct ofono_gprs *gprs);
static void write_context_settings(struct ofono_gprs *gprs,
@@ -1148,6 +1149,16 @@ static void pri_deactivate_callback(const struct ofono_error *error, void *data)
ofono_dbus_signal_property_changed(conn, ctx->path,
OFONO_CONNECTION_CONTEXT_INTERFACE,
"Active", DBUS_TYPE_BOOLEAN, &value);
/*
* If "Attached" property was about to be signalled as TRUE but there
* were still active contexts, try again to signal "Attached" property
* to registered applications after active contexts have been released.
*/
if (ctx->gprs->flags & GPRS_FLAG_ATTACHED_UPDATE) {
ctx->gprs->flags &= ~GPRS_FLAG_ATTACHED_UPDATE;
gprs_attached_update(ctx->gprs);
}
}
static void pri_read_settings_callback(const struct ofono_error *error,
@@ -2263,6 +2274,11 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
const char *path;
enum ofono_gprs_context_type type;
#ifdef DISABLE_ADD_REMOVE_CONTEXT
ofono_error("AddContext not allowed");
return __ofono_error_not_supported(msg);
#endif
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &typestr,
DBUS_TYPE_INVALID))
return __ofono_error_invalid_args(msg);
@@ -2344,6 +2360,11 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
const char *path;
const char *atompath;
#ifdef DISABLE_ADD_REMOVE_CONTEXT
ofono_error("RemoveContext not allowed");
return __ofono_error_not_supported(msg);
#endif
if (gprs->pending)
return __ofono_error_busy(msg);
@@ -2358,13 +2379,13 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
if (ctx == NULL)
return __ofono_error_not_found(msg);
/* This context is already being messed with */
if (ctx->pending)
return __ofono_error_busy(msg);
if (ctx->active) {
struct ofono_gprs_context *gc = ctx->context_driver;
/* This context is already being messed with */
if (ctx->pending)
return __ofono_error_busy(msg);
gprs->pending = dbus_message_ref(msg);
gc->driver->deactivate_primary(gc, ctx->context.cid,
gprs_deactivate_for_remove, ctx);

View File

@@ -203,7 +203,7 @@ static gboolean sco_accept(GIOChannel *io, GIOCondition cond,
send_new_connection(card->path, nsk, card->selected_codec);
close(nsk);
if (card->driver->sco_connected_hint)
if (card->driver && card->driver->sco_connected_hint)
card->driver->sco_connected_hint(card);
return TRUE;

View File

@@ -386,6 +386,9 @@ void __ofono_sim_refresh(struct ofono_sim *sim, GSList *file_list,
void __ofono_sim_recheck_pin(struct ofono_sim *sim);
enum ofono_sim_password_type __ofono_sim_puk2pin(
enum ofono_sim_password_type type);
#include <ofono/stk.h>
typedef void (*__ofono_sms_sim_download_cb_t)(ofono_bool_t ok,

View File

@@ -889,9 +889,13 @@ static void radio_load_settings(struct ofono_radio_settings *rs,
"GsmBand", rs->band_gsm);
}
if (error) {
g_error_free(error);
error = NULL;
}
rs->pending_band_gsm = rs->band_gsm;
error = NULL;
rs->band_umts = g_key_file_get_integer(rs->settings, SETTINGS_GROUP,
"UmtsBand", &error);
@@ -901,9 +905,13 @@ static void radio_load_settings(struct ofono_radio_settings *rs,
"UmtsBand", rs->band_umts);
}
if (error) {
g_error_free(error);
error = NULL;
}
rs->pending_band_umts = rs->band_umts;
error = NULL;
rs->mode = g_key_file_get_integer(rs->settings, SETTINGS_GROUP,
"TechnologyPreference", &error);
@@ -913,6 +921,11 @@ static void radio_load_settings(struct ofono_radio_settings *rs,
"TechnologyPreference", rs->mode);
}
if (error) {
g_error_free(error);
error = NULL;
}
DBG("TechnologyPreference: %d", rs->mode);
DBG("GsmBand: %d", rs->band_gsm);
DBG("UmtsBand: %d", rs->band_umts);

View File

@@ -197,7 +197,10 @@ static gboolean password_is_pin(enum ofono_sim_password_type type)
return FALSE;
}
static enum ofono_sim_password_type puk2pin(enum ofono_sim_password_type type)
#define puk2pin(type) __ofono_sim_puk2pin(type)
enum ofono_sim_password_type __ofono_sim_puk2pin(
enum ofono_sim_password_type type)
{
switch (type) {
case OFONO_SIM_PASSWORD_SIM_PUK:
@@ -2511,13 +2514,6 @@ static void sim_spn_close(struct ofono_sim *sim)
static void sim_free_main_state(struct ofono_sim *sim)
{
int i;
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
sim->pin_retries[i] = -1;
memset(sim->locked_pins, 0, sizeof(sim->locked_pins));
if (sim->imsi) {
g_free(sim->imsi);
sim->imsi = NULL;
@@ -2607,31 +2603,50 @@ static void sim_set_locked_pin(struct ofono_sim *sim,
g_strfreev(locked_pins);
}
static void sim_query_fac_imsilock_cb(const struct ofono_error *error,
static void sim_query_fac_pinlock_cb(const struct ofono_error *error,
ofono_bool_t status, void *data)
{
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
return;
struct ofono_sim *sim = data;
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_PHSIM_PIN, status);
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
goto done;
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_SIM_PIN, status);
done:
sim_initialize(sim);
}
static void sim_query_fac_networklock_cb(const struct ofono_error *error,
ofono_bool_t status, void *data)
{
struct ofono_sim *sim = data;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
return;
goto done;
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_PHNET_PIN, status);
done:
sim->driver->query_facility_lock(sim,
OFONO_SIM_PASSWORD_SIM_PIN,
sim_query_fac_pinlock_cb, sim);
}
static void sim_query_fac_pinlock_cb(const struct ofono_error *error,
static void sim_query_fac_imsilock_cb(const struct ofono_error *error,
ofono_bool_t status, void *data)
{
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
return;
struct ofono_sim *sim = data;
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_SIM_PIN, status);
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
goto done;
sim_set_locked_pin(data, OFONO_SIM_PASSWORD_PHSIM_PIN, status);
done:
sim->driver->query_facility_lock(sim,
OFONO_SIM_PASSWORD_PHNET_PIN,
sim_query_fac_networklock_cb, sim);
}
void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
@@ -2665,18 +2680,28 @@ void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
OFONO_SIM_PASSWORD_PHSIM_PIN,
sim_query_fac_imsilock_cb, sim);
sim->driver->query_facility_lock(sim,
OFONO_SIM_PASSWORD_PHNET_PIN,
sim_query_fac_networklock_cb, sim);
sim->driver->query_facility_lock(sim,
OFONO_SIM_PASSWORD_SIM_PIN,
sim_query_fac_pinlock_cb, sim);
} else {
sim_initialize(sim);
}
} else {
switch (sim->pin_type) {
case OFONO_SIM_PASSWORD_SIM_PIN:
case OFONO_SIM_PASSWORD_SIM_PUK:
case OFONO_SIM_PASSWORD_SIM_PIN2:
case OFONO_SIM_PASSWORD_SIM_PUK2:
sim->pin_type = OFONO_SIM_PASSWORD_NONE;
break;
default:
break;
}
sim_initialize(sim);
} else {
sim->pin_type = OFONO_SIM_PASSWORD_NONE;
sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] = FALSE;
sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN2] = FALSE;
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PIN] = -1;
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PUK] = -1;
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PIN2] = -1;
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PUK2] = -1;
sim_free_state(sim);
}
@@ -3282,8 +3307,6 @@ ofono_bool_t __ofono_is_valid_sim_pin(const char *pin,
return is_valid_pin(pin, 8, 8);
break;
case OFONO_SIM_PASSWORD_NONE:
return is_valid_pin(pin, 0, 8);
break;
case OFONO_SIM_PASSWORD_INVALID:
break;
}

View File

@@ -226,6 +226,9 @@ void sim_fs_notify_file_watches(struct sim_fs *fs, int id)
struct ofono_sim_context *context = l->data;
GSList *k;
if (context->file_watches == NULL)
continue;
for (k = context->file_watches->items; k; k = k->next) {
struct file_watch *w = k->data;
ofono_sim_file_changed_cb_t notify = w->item.notify;

View File

@@ -2218,6 +2218,7 @@ char *sms_decode_text(GSList *sms_list)
const struct sms *sms;
int guess_size = g_slist_length(sms_list);
char *utf8;
GByteArray *utf16 = 0;
if (guess_size == 1)
guess_size = 160;
@@ -2289,8 +2290,12 @@ char *sms_decode_text(GSList *sms_list)
NULL, NULL, 0,
locking_shift,
single_shift);
if (converted) {
g_string_append(str, converted);
g_free(converted);
}
} else {
const gchar *from = (const gchar *) (ud + taken);
const guint8 *from = ud + taken;
/*
* According to the spec: A UCS2 character shall not be
* split in the middle; if the length of the User Data
@@ -2300,15 +2305,32 @@ char *sms_decode_text(GSList *sms_list)
gssize num_ucs2_chars = (udl_in_bytes - taken) >> 1;
num_ucs2_chars = num_ucs2_chars << 1;
converted = g_convert_with_fallback(from, num_ucs2_chars,
"UTF-8//TRANSLIT", "UTF-16BE",
NULL, NULL, NULL, NULL);
/*
* In theory SMS supports encoding using UCS2 which
* is 16-bit, however in the real world messages
* are encoded in UTF-16 which can be 4 bytes and
* a multiple fragment message can split a 4-byte
* character in the middle. So accumulate the
* entire message before converting to UTF-8.
*/
if (!utf16)
utf16 = g_byte_array_new();
g_byte_array_append(utf16, from, num_ucs2_chars);
}
}
if (utf16) {
char *converted = g_convert_with_fallback((const gchar *)
utf16->data, utf16->len,
"UTF-8//TRANSLIT", "UTF-16BE",
NULL, NULL, NULL, NULL);
if (converted) {
g_string_append(str, converted);
g_free(converted);
}
g_byte_array_free(utf16, TRUE);
}
utf8 = g_string_free(str, FALSE);

View File

@@ -3748,6 +3748,15 @@ int ofono_voicecall_get_next_callid(struct ofono_voicecall *vc)
return __ofono_modem_callid_next(modem);
}
struct ofono_call *ofono_voicecall_find_call(struct ofono_voicecall *vc,
unsigned int id)
{
GSList *l = g_slist_find_custom(vc->call_list, GUINT_TO_POINTER(id),
call_compare_by_id);
return l ? ((struct voicecall *)l->data)->call : NULL;
}
ofono_bool_t __ofono_voicecall_is_busy(struct ofono_voicecall *vc,
enum ofono_voicecall_interaction type)
{

15
ofono/test/cancel-sms Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/python3
import sys
import dbus
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
'org.ofono.Manager')
path = sys.argv[1]
message = dbus.Interface(bus.get_object('org.ofono', path),
'org.ofono.Message')
message.Cancel()

18
ofono/test/disable-throttling Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/python3
import dbus, sys
bus = dbus.SystemBus()
if len(sys.argv) == 2:
path = sys.argv[1]
else:
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
'org.ofono.Manager')
modems = manager.GetModems()
path = modems[0][0]
print("Disabling transmit power throttling of modem %s ..." % path)
thermal_management = dbus.Interface(bus.get_object('org.ofono', path),
'org.ofono.sofia3gr.ThermalManagement')
thermal_management.SetProperty("TransmitPowerThrottling", dbus.Boolean(0), timeout = 30)

18
ofono/test/enable-throttling Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/python3
import dbus, sys
bus = dbus.SystemBus()
if len(sys.argv) == 2:
path = sys.argv[1]
else:
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
'org.ofono.Manager')
modems = manager.GetModems()
path = modems[0][0]
print("Enabling transmit power throttling of modem %s ..." % path)
thermal_management = dbus.Interface(bus.get_object('org.ofono', path),
'org.ofono.sofia3gr.ThermalManagement')
thermal_management.SetProperty("TransmitPowerThrottling", dbus.Boolean(1), timeout = 30)

0
ofono/test/get-serving-cell-info Normal file → Executable file
View File

View File

@@ -0,0 +1,280 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2016 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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 <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <ofono/types.h>
#include <gril.h>
#include "rilmodem-test-engine.h"
#define MAX_REQUEST_SIZE 4096
#define RIL_SERVER_SOCK_PATH "/tmp/unittestril"
static GMainLoop *mainloop;
struct engine_data {
int server_sk;
int connected_sk;
guint connection_watch;
rilmodem_test_engine_cb_t connect_func;
GIOChannel *server_io;
char *sock_name;
struct rilmodem_test_data rtd;
int step_i;
void *user_data;
};
static void send_parcel(struct engine_data *ed)
{
GIOStatus status;
gsize wbytes;
const struct rilmodem_test_step *step = &ed->rtd.steps[ed->step_i];
status = g_io_channel_write_chars(ed->server_io,
step->parcel_data,
step->parcel_size,
&wbytes, NULL);
g_assert(wbytes == step->parcel_size);
g_assert(status == G_IO_STATUS_NORMAL);
status = g_io_channel_flush(ed->server_io, NULL);
g_assert(status == G_IO_STATUS_NORMAL);
rilmodem_test_engine_next_step(ed);
}
static gboolean on_rx_data(GIOChannel *chan, GIOCondition cond, gpointer data)
{
struct engine_data *ed = data;
GIOStatus status;
gsize rbytes;
gchar *buf;
const struct rilmodem_test_step *step;
/* We have closed the socket */
if (cond == G_IO_NVAL)
return FALSE;
buf = g_malloc0(MAX_REQUEST_SIZE);
status = g_io_channel_read_chars(ed->server_io, buf, MAX_REQUEST_SIZE,
&rbytes, NULL);
g_assert(status == G_IO_STATUS_NORMAL);
/* Check this is the expected step */
step = &ed->rtd.steps[ed->step_i];
g_assert(step->type == TST_EVENT_RECEIVE);
g_assert(rbytes == step->parcel_size);
/* validate received parcel */
g_assert(!memcmp(buf, step->parcel_data, rbytes));
rilmodem_test_engine_next_step(ed);
return TRUE;
}
static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
struct engine_data *ed = data;
struct sockaddr saddr;
unsigned int len = sizeof(saddr);
GIOStatus status;
g_assert(cond == G_IO_IN);
ed->connected_sk = accept(ed->server_sk, &saddr, &len);
g_assert(ed->connected_sk != -1);
ed->server_io = g_io_channel_unix_new(ed->connected_sk);
g_assert(ed->server_io != NULL);
status = g_io_channel_set_encoding(ed->server_io, NULL, NULL);
g_assert(status == G_IO_STATUS_NORMAL);
g_io_channel_set_buffered(ed->server_io, FALSE);
g_io_channel_set_close_on_unref(ed->server_io, TRUE);
if (ed->connect_func)
ed->connect_func(ed->user_data);
ed->connection_watch =
g_io_add_watch_full(ed->server_io, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
on_rx_data, ed, NULL);
g_io_channel_unref(ed->server_io);
return FALSE;
}
void rilmodem_test_engine_remove(struct engine_data *ed)
{
if (ed->connection_watch)
g_source_remove(ed->connection_watch);
g_assert(ed->server_sk);
close(ed->server_sk);
remove(ed->sock_name);
g_free(ed->sock_name);
g_free(ed);
}
struct engine_data *rilmodem_test_engine_create(
rilmodem_test_engine_cb_t connect,
const struct rilmodem_test_data *test_data,
void *data)
{
GIOChannel *io;
struct sockaddr_un addr;
int retval;
struct engine_data *ed;
ed = g_new0(struct engine_data, 1);
ed->connect_func = connect;
ed->user_data = data;
ed->rtd = *test_data;
ed->server_sk = socket(AF_UNIX, SOCK_STREAM, 0);
g_assert(ed->server_sk);
ed->sock_name =
g_strdup_printf(RIL_SERVER_SOCK_PATH"%u", (unsigned) getpid());
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, ed->sock_name, sizeof(addr.sun_path) - 1);
/* Unlink any existing socket for this session */
unlink(addr.sun_path);
retval = bind(ed->server_sk, (struct sockaddr *) &addr, sizeof(addr));
g_assert(retval >= 0);
retval = listen(ed->server_sk, 0);
g_assert(retval >= 0);
io = g_io_channel_unix_new(ed->server_sk);
g_assert(io != NULL);
g_io_channel_set_close_on_unref(io, TRUE);
g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
on_socket_connected, ed, NULL);
g_io_channel_unref(io);
return ed;
}
void rilmodem_test_engine_write_socket(struct engine_data *ed,
const unsigned char *buf,
const size_t buf_len)
{
GIOStatus status;
gsize wbytes;
status = g_io_channel_write_chars(ed->server_io,
(const char *) buf,
buf_len,
&wbytes, NULL);
g_assert(status == G_IO_STATUS_NORMAL);
status = g_io_channel_flush(ed->server_io, NULL);
g_assert(status == G_IO_STATUS_NORMAL);
}
const char *rilmodem_test_engine_get_socket_name(struct engine_data *ed)
{
return ed->sock_name;
}
static gboolean action_call(gpointer data)
{
struct engine_data *ed = data;
const struct rilmodem_test_step *step;
step = &ed->rtd.steps[ed->step_i];
step->call_action(ed->user_data);
return FALSE;
}
void rilmodem_test_engine_next_step(struct engine_data *ed)
{
const struct rilmodem_test_step *step;
ed->step_i++;
if (ed->step_i >= ed->rtd.num_steps) {
/* Finish the test */
g_main_loop_quit(mainloop);
return;
}
step = &ed->rtd.steps[ed->step_i];
/* If next step is an action, execute it */
switch (step->type) {
case TST_ACTION_SEND:
send_parcel(ed);
break;
case TST_ACTION_CALL:
g_idle_add(action_call, ed);
break;
case TST_EVENT_RECEIVE:
case TST_EVENT_CALL:
break;
};
}
const struct rilmodem_test_step *rilmodem_test_engine_get_current_step(
struct engine_data *ed)
{
const struct rilmodem_test_step *step = &ed->rtd.steps[ed->step_i];
return step;
}
void rilmodem_test_engine_start(struct engine_data *ed)
{
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
g_main_loop_unref(mainloop);
}

View File

@@ -0,0 +1,74 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2016 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
struct engine_data;
enum test_step_type {
TST_ACTION_SEND,
TST_ACTION_CALL,
TST_EVENT_RECEIVE,
TST_EVENT_CALL,
};
typedef void (*rilmodem_test_engine_cb_t)(void *data);
struct rilmodem_test_step {
enum test_step_type type;
union {
/* For TST_ACTION_CALL */
rilmodem_test_engine_cb_t call_action;
/* For TST_ACTION_SEND or TST_EVENT_RECEIVE */
struct {
const char *parcel_data;
const size_t parcel_size;
};
/* For TST_EVENT_CALL */
struct {
void (*call_func)(void);
void (*check_func)(void);
};
};
};
struct rilmodem_test_data {
const struct rilmodem_test_step *steps;
int num_steps;
};
void rilmodem_test_engine_remove(struct engine_data *ed);
struct engine_data *rilmodem_test_engine_create(
rilmodem_test_engine_cb_t connect,
const struct rilmodem_test_data *test_data,
void *data);
void rilmodem_test_engine_write_socket(struct engine_data *ed,
const unsigned char *buf,
const size_t buf_len);
const char *rilmodem_test_engine_get_socket_name(struct engine_data *ed);
void rilmodem_test_engine_next_step(struct engine_data *ed);
const struct rilmodem_test_step *rilmodem_test_engine_get_current_step(
struct engine_data *ed);
void rilmodem_test_engine_start(struct engine_data *ed);

View File

@@ -0,0 +1,750 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2016 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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 <assert.h>
#include <errno.h>
#include <glib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <ofono/modem.h>
#include <ofono/types.h>
#include <ofono/gprs.h>
#include <gril.h>
#include <drivers/rilmodem/rilutil.h>
#include "common.h"
#include "ril_constants.h"
#include "rilmodem-test-engine.h"
static const struct ofono_gprs_driver *gprs_drv;
/* Declarations && Re-implementations of core functions. */
void ril_gprs_exit(void);
void ril_gprs_init(void);
struct ofono_modem;
struct ofono_gprs {
void *driver_data;
GRil *ril;
struct ofono_modem *modem;
struct engine_data *engined;
};
struct ofono_modem {
struct ofono_gprs *gprs;
};
int ofono_gprs_driver_register(const struct ofono_gprs_driver *d)
{
if (gprs_drv == NULL)
gprs_drv = d;
return 0;
}
void ofono_gprs_driver_unregister(const struct ofono_gprs_driver *d)
{
gprs_drv = NULL;
}
void ofono_gprs_register(struct ofono_gprs *gprs)
{
const struct rilmodem_test_step *step;
step = rilmodem_test_engine_get_current_step(gprs->engined);
g_assert(step->type == TST_EVENT_CALL);
g_assert(step->call_func == (void (*)(void)) ofono_gprs_register);
rilmodem_test_engine_next_step(gprs->engined);
}
void ofono_gprs_set_data(struct ofono_gprs *gprs, void *data)
{
gprs->driver_data = data;
}
void *ofono_gprs_get_data(struct ofono_gprs *gprs)
{
return gprs->driver_data;
}
void ofono_gprs_status_notify(struct ofono_gprs *gprs, int status)
{
const struct rilmodem_test_step *step;
step = rilmodem_test_engine_get_current_step(gprs->engined);
g_assert(step->type == TST_EVENT_CALL);
g_assert(step->call_func == (void (*)(void)) ofono_gprs_status_notify);
if (step->check_func != NULL)
((void (*)(struct ofono_gprs *, int)) step->check_func)(
gprs, status);
rilmodem_test_engine_next_step(gprs->engined);
}
void ofono_gprs_detached_notify(struct ofono_gprs *gprs)
{
const struct rilmodem_test_step *step;
step = rilmodem_test_engine_get_current_step(gprs->engined);
g_assert(step->type == TST_EVENT_CALL);
g_assert(step->call_func ==
(void (*)(void)) ofono_gprs_detached_notify);
rilmodem_test_engine_next_step(gprs->engined);
}
void ofono_gprs_bearer_notify(struct ofono_gprs *gprs, int bearer)
{
const struct rilmodem_test_step *step;
step = rilmodem_test_engine_get_current_step(gprs->engined);
g_assert(step->type == TST_EVENT_CALL);
g_assert(step->call_func == (void (*)(void)) ofono_gprs_bearer_notify);
if (step->check_func != NULL)
((void (*)(struct ofono_gprs *, int)) step->check_func)(
gprs, bearer);
rilmodem_test_engine_next_step(gprs->engined);
}
void ofono_gprs_set_cid_range(struct ofono_gprs *gprs,
unsigned int min, unsigned int max)
{
const struct rilmodem_test_step *step;
step = rilmodem_test_engine_get_current_step(gprs->engined);
g_assert(step->type == TST_EVENT_CALL);
g_assert(step->call_func == (void (*)(void)) ofono_gprs_set_cid_range);
if (step->check_func != NULL)
((void (*)(struct ofono_gprs *, unsigned int, unsigned int))
step->check_func)(gprs, min, max);
rilmodem_test_engine_next_step(gprs->engined);
}
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs)
{
return gprs->modem;
}
int ofono_modem_set_integer(struct ofono_modem *modem,
const char *key, int value)
{
const struct rilmodem_test_step *step;
step = rilmodem_test_engine_get_current_step(modem->gprs->engined);
g_assert(step->type == TST_EVENT_CALL);
g_assert(step->call_func == (void (*)(void)) ofono_modem_set_integer);
if (step->check_func != NULL)
((void (*)(struct ofono_modem *, const char *, int))
step->check_func)(modem, key, value);
rilmodem_test_engine_next_step(modem->gprs->engined);
return 0;
}
void ofono_gprs_remove(struct ofono_gprs *gprs)
{
const struct rilmodem_test_step *step;
step = rilmodem_test_engine_get_current_step(gprs->engined);
g_assert(step->type == TST_EVENT_CALL);
g_assert(step->call_func == (void (*)(void)) ofono_gprs_remove);
rilmodem_test_engine_next_step(gprs->engined);
}
/*
* As all our architectures are little-endian except for
* PowerPC, and the Binder wire-format differs slightly
* depending on endian-ness, the following guards against test
* failures when run on PowerPC.
*/
#if BYTE_ORDER == LITTLE_ENDIAN
/* REQUEST_DATA_CALL_LIST, seq 1 */
static const char parcel_req_data_call_list_1_1[] = {
0x00, 0x00, 0x00, 0x08, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
};
/*
* --- TEST 1 ---
* Step 1: Driver sends REQUEST_DATA_CALL_LIST
*/
static const struct rilmodem_test_step steps_test_1[] = {
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_data_call_list_1_1,
.parcel_size = sizeof(parcel_req_data_call_list_1_1)
}
};
struct rilmodem_test_data test_1 = {
.steps = steps_test_1,
.num_steps = G_N_ELEMENTS(steps_test_1)
};
/* REQUEST_DATA_CALL_LIST, seq 1 */
static const char parcel_req_data_call_list_2_1[] = {
0x00, 0x00, 0x00, 0x08, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
};
/* Response, no errors */
static const char parcel_rsp_data_call_list_2_2[] = {
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* REQUEST_DATA_REGISTRATION_STATE, seq 2 */
static const char parcel_req_data_registration_state_2_3[] = {
0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00
};
/* Responso, no error, {unregistered,0xb08,0x10e1,GPRS,(null),4} */
static const char parcel_rsp_data_registration_state_2_4[] = {
0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x62, 0x00,
0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00,
0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00
};
static void set_cid_range_check_2_5(struct ofono_gprs *gprs,
unsigned int min, unsigned int max)
{
g_assert(min == 1);
g_assert(max == 2);
}
static void gprs_cb_2_8(const struct ofono_error *error, void *data)
{
struct ofono_gprs *gprs = data;
g_assert(error->type == OFONO_ERROR_TYPE_NO_ERROR);
rilmodem_test_engine_next_step(gprs->engined);
}
static void call_set_attached_2_7(gpointer data)
{
struct ofono_gprs *gprs = data;
gprs_drv->set_attached(gprs, 0, gprs_cb_2_8, gprs);
rilmodem_test_engine_next_step(gprs->engined);
}
/*
* --- TEST 2 ---
* Step 1: Driver sends REQUEST_DATA_CALL_LIST
* Step 2: Harness answers with empty data call list
* Step 3: Driver sends REQUEST_DATA_REGISTRATION_STATE
* Step 4: Harness answers with status unregistered
* Step 5: Driver calls ofono_gprs_set_cid_range
* Step 6: Driver calls ofono_gprs_register
* Step 7: Harness calls drv->set_attached(false)
* Step 8: Driver calls the callback specified in step 7
*/
static const struct rilmodem_test_step steps_test_2[] = {
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_data_call_list_2_1,
.parcel_size = sizeof(parcel_req_data_call_list_2_1)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_data_call_list_2_2,
.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
},
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_data_registration_state_2_3,
.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_data_registration_state_2_4,
.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
.check_func = (void (*)(void)) set_cid_range_check_2_5
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_register,
.check_func = NULL
},
{
.type = TST_ACTION_CALL,
.call_action = call_set_attached_2_7,
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) gprs_cb_2_8,
.check_func = NULL
},
};
struct rilmodem_test_data test_2 = {
.steps = steps_test_2,
.num_steps = G_N_ELEMENTS(steps_test_2)
};
static void gprs_cb_3_8(const struct ofono_error *error, void *data)
{
struct ofono_gprs *gprs = data;
g_assert(error->type == OFONO_ERROR_TYPE_NO_ERROR);
rilmodem_test_engine_next_step(gprs->engined);
}
static void call_set_attached_3_7(gpointer data)
{
struct ofono_gprs *gprs = data;
gprs_drv->set_attached(gprs, 1, gprs_cb_3_8, gprs);
rilmodem_test_engine_next_step(gprs->engined);
}
/*
* --- TEST 3 ---
* Steps 1-6: Same as in test 2
* Step 7: Harness calls drv->set_attached(true)
* Step 8: Driver calls the callback specified in step 7
*/
static const struct rilmodem_test_step steps_test_3[] = {
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_data_call_list_2_1,
.parcel_size = sizeof(parcel_req_data_call_list_2_1)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_data_call_list_2_2,
.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
},
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_data_registration_state_2_3,
.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_data_registration_state_2_4,
.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
.check_func = (void (*)(void)) set_cid_range_check_2_5
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_register,
.check_func = NULL
},
{
.type = TST_ACTION_CALL,
.call_action = call_set_attached_3_7,
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) gprs_cb_3_8,
.check_func = NULL
},
};
struct rilmodem_test_data test_3 = {
.steps = steps_test_3,
.num_steps = G_N_ELEMENTS(steps_test_3)
};
/* REQUEST_DATA_REGISTRATION_STATE, seq 3 */
static const char parcel_req_registration_state_4_8[] = {
0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
};
/* Response, no error, {registered,0xb08,0x10e1,GPRS,(null),4} */
static const char parcel_rsp_registration_state_4_9[] = {
0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x62, 0x00,
0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00,
0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00
};
static void reg_state_cb_4_12(const struct ofono_error *error,
int status, void *data)
{
struct ofono_gprs *gprs = data;
const struct rilmodem_test_step *step;
step = rilmodem_test_engine_get_current_step(gprs->engined);
g_assert(step->type == TST_EVENT_CALL);
g_assert(step->call_func == (void (*)(void)) reg_state_cb_4_12);
g_assert(error->type == OFONO_ERROR_TYPE_NO_ERROR);
/*
* Driver returns unregistered even though network state is attached
* because we did not set attach to true in this test case.
*/
g_assert(status == NETWORK_REGISTRATION_STATUS_NOT_REGISTERED);
rilmodem_test_engine_next_step(gprs->engined);
}
static void call_registration_status_4_7(gpointer data)
{
struct ofono_gprs *gprs = data;
gprs_drv->attached_status(gprs, reg_state_cb_4_12, gprs);
rilmodem_test_engine_next_step(gprs->engined);
}
static void set_integer_check_4_10(struct ofono_modem *modem,
const char *key, int value)
{
g_assert_cmpstr(key, ==, "RilDataRadioTechnology");
g_assert(value == RADIO_TECH_GPRS);
}
static void gprs_bearer_check_4_11(struct ofono_gprs *gprs, int bearer)
{
g_assert(bearer == PACKET_BEARER_GPRS);
}
/*
* --- TEST 4 ---
* Steps 1-6: Same as in test 2
* Step 7: Harness calls drv->registration_status
* Step 8: Driver sends REQUEST_DATA_REGISTRATION_STATE
* Step 9: Harness answers saying status is registered
* Step 10: Driver calls ofono_modem_set_integer
* Step 11: Driver calls ofono_gprs_bearer_notify(PACKET_BEARER_GPRS)
* Step 12: Driver calls the callback specified in step 7
*/
static const struct rilmodem_test_step steps_test_4[] = {
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_data_call_list_2_1,
.parcel_size = sizeof(parcel_req_data_call_list_2_1)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_data_call_list_2_2,
.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
},
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_data_registration_state_2_3,
.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_data_registration_state_2_4,
.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
.check_func = (void (*)(void)) set_cid_range_check_2_5
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_register,
.check_func = NULL
},
{
.type = TST_ACTION_CALL,
.call_action = call_registration_status_4_7,
},
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_registration_state_4_8,
.parcel_size = sizeof(parcel_req_registration_state_4_8)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_registration_state_4_9,
.parcel_size = sizeof(parcel_rsp_registration_state_4_9)
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_modem_set_integer,
.check_func = (void (*)(void)) set_integer_check_4_10
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_bearer_notify,
.check_func = (void (*)(void)) gprs_bearer_check_4_11
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) reg_state_cb_4_12,
.check_func = NULL
},
};
struct rilmodem_test_data test_4 = {
.steps = steps_test_4,
.num_steps = G_N_ELEMENTS(steps_test_4)
};
/* UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED */
static const char parcel_ev_network_state_changed_5_9[] = {
0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0xEA, 0x03, 0x00, 0x00
};
/* REQUEST_DATA_REGISTRATION_STATE, seq 3 */
static const char parcel_req_registration_state_5_10[] = {
0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
};
/* Response, no error, {registered,0xb08,0x10e1,GPRS,(null),4} */
static const char parcel_rsp_registration_state_5_11[] = {
0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x62, 0x00,
0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00,
0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00
};
static void gprs_status_check_5_12(struct ofono_gprs *gprs, int status)
{
g_assert(status == NETWORK_REGISTRATION_STATUS_REGISTERED);
}
static void set_integer_check_5_13(struct ofono_modem *modem,
const char *key, int value)
{
g_assert_cmpstr(key, ==, "RilDataRadioTechnology");
g_assert(value == RADIO_TECH_GPRS);
}
static void gprs_bearer_check_5_14(struct ofono_gprs *gprs, int bearer)
{
g_assert(bearer == PACKET_BEARER_GPRS);
}
/*
* --- TEST 5 ---
* Steps 1-8: Same as test 3
* Step 9: Harness sends UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
* Step 10: Driver sends REQUEST_DATA_REGISTRATION_STATE
* Step 11: Harness answers saying status is registered
* Step 12: Driver calls ofono_gprs_status_notify(REGISTERED)
* Step 13: Driver calls ofono_modem_set_integer
* Step 14: Driver calls ofono_gprs_bearer_notify(PACKET_BEARER_GPRS)
*/
static const struct rilmodem_test_step steps_test_5[] = {
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_data_call_list_2_1,
.parcel_size = sizeof(parcel_req_data_call_list_2_1)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_data_call_list_2_2,
.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
},
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_data_registration_state_2_3,
.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_data_registration_state_2_4,
.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
.check_func = (void (*)(void)) set_cid_range_check_2_5
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_register,
.check_func = NULL
},
{
.type = TST_ACTION_CALL,
.call_action = call_set_attached_3_7,
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) gprs_cb_3_8,
.check_func = NULL
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_ev_network_state_changed_5_9,
.parcel_size = sizeof(parcel_ev_network_state_changed_5_9)
},
{
.type = TST_EVENT_RECEIVE,
.parcel_data = parcel_req_registration_state_5_10,
.parcel_size = sizeof(parcel_req_registration_state_5_10)
},
{
.type = TST_ACTION_SEND,
.parcel_data = parcel_rsp_registration_state_5_11,
.parcel_size = sizeof(parcel_rsp_registration_state_5_11)
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_status_notify,
.check_func = (void (*)(void)) gprs_status_check_5_12
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_modem_set_integer,
.check_func = (void (*)(void)) set_integer_check_5_13
},
{
.type = TST_EVENT_CALL,
.call_func = (void (*)(void)) ofono_gprs_bearer_notify,
.check_func = (void (*)(void)) gprs_bearer_check_5_14
},
};
struct rilmodem_test_data test_5 = {
.steps = steps_test_5,
.num_steps = G_N_ELEMENTS(steps_test_5)
};
static void server_connect_cb(gpointer data)
{
struct ofono_gprs *gprs = data;
int retval;
/*
* This triggers the first event from the gprs atom, which is a request
* to retrieve currently active data calls. Test steps must start from
* there.
*/
retval = gprs_drv->probe(gprs, OFONO_RIL_VENDOR_AOSP, gprs->ril);
g_assert(retval == 0);
}
/*
* This unit test:
* - does some test data setup
* - configures a dummy server socket
* - creates a new gril client instance
* - triggers a connect to the dummy
* server socket
* - starts the test engine
*/
static void test_function(gconstpointer data)
{
const struct rilmodem_test_data *test_data = data;
struct ofono_gprs *gprs;
struct ofono_modem *modem;
ril_gprs_init();
gprs = g_malloc0(sizeof(*gprs));
modem = g_malloc0(sizeof(*modem));
modem->gprs = gprs;
gprs->modem = modem;
gprs->engined = rilmodem_test_engine_create(&server_connect_cb,
test_data, gprs);
gprs->ril = g_ril_new(rilmodem_test_engine_get_socket_name(gprs->engined),
OFONO_RIL_VENDOR_AOSP);
g_assert(gprs->ril != NULL);
/* Perform test */
rilmodem_test_engine_start(gprs->engined);
gprs_drv->remove(gprs);
g_ril_unref(gprs->ril);
g_free(modem);
g_free(gprs);
rilmodem_test_engine_remove(gprs->engined);
ril_gprs_exit();
}
#endif
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
/*
* As all our architectures are little-endian except for
* PowerPC, and the Binder wire-format differs slightly
* depending on endian-ness, the following guards against test
* failures when run on PowerPC.
*/
#if BYTE_ORDER == LITTLE_ENDIAN
g_test_add_data_func("/test-rilmodem-gprs/1", &test_1, test_function);
g_test_add_data_func("/test-rilmodem-gprs/2", &test_2, test_function);
g_test_add_data_func("/test-rilmodem-gprs/3", &test_3, test_function);
g_test_add_data_func("/test-rilmodem-gprs/4", &test_4, test_function);
g_test_add_data_func("/test-rilmodem-gprs/5", &test_5, test_function);
#endif
return g_test_run();
}

View File

@@ -1,333 +0,0 @@
* Fri Feb 27 2015 Tommi Kenakkala <tommi.kenakkala@tieto.com> - 1.16
- Update to upstream 1.16
- Rilmodem work
- Some core changes and API extensions
* Thu Jan 09 2014 Martti Piirainen <martti.piirainen@oss.tieto.com> - 1.14
- Update to upstream 1.14.
* Wed Jun 12 2013 Juho Hämäläinen <juho.hamalainen@tieto.com> - 1.12
- Update to upstream 1.12.
- Add phablet patches for ril (version 1.12phablet3).
- Additional ril work and fixes.
* Wed Jan 16 2013 Petri M. Gerdt <petri.gerdt@jollamobile.com> - 1.11
- add patch 0001-Experimental-network-time-plugin.patch which adds
an API for accessing cellular network time.
* Mon Dec 10 2012 Lorn Potter <lorn.potter@jollamobile.com> - 1.11
- upgrade ofono to 1.11
* Fri Aug 24 2012 Jarko Poutiainen <jarko.poutiainen@tieto.com> - 1.10
- upgrade ofono to 1.10
- remove n950 patches
- add patch to disable cbs from n900 plugin
- add patch to fix answering for N9 modem
* Thu Aug 23 2012 Carsten Munk <carsten.munk@jollamobile.com> - 1.8
- Add isimodem-fix-incoming-calls.patch to fix incoming calls on isimodem
* Wed Jul 11 2012 Marko Saukko <marko.saukko@jollamobile.com> - 1.8
- Fixes MER#285: upgrade ofono to recent version
- Fixes MER#422: ofono-test package requires python dbus bindings.
- Rename -test packages to -tests
* Wed Sep 21 2011 Sami Sirkia <sami.sirkia@cybercom.com> - 0.52
- Include patches for N950
* Fri Sep 16 2011 Jouni Peltonen <jouni.peltonen@cybercom.com> - 0.52
- Patch BMC22161-isi-call-id.patch added to correct isi modem answering
BMC #22161.
* Tue Jul 19 2011 Yu <yu.a.wang@intel.com> - 0.52
- upgrade to 0.52
* Wed Jul 13 2011 Yu <yu.a.wang@intel.com> - 0.51
- upgrade to 0.51
* Thu Jun 23 2011 Yu <yu.a.wang@intel.com> - 0.50
- upgrade to 0.50
* Thu Jun 23 2011 Yu <yu.a.wang@intel.com> - 0.49
- Remove requirement for package usb-modeswitch and use-modeswitch-date due to this is not the right way to fix BMC#19097
- Release engineer already added these two packages to package-groups
* Wed Jun 15 2011 Yu <yu.a.wang@intel.com> - 0.49
- Add requirement for package usb-modeswitch and usb-modeswitch-data fix BMC#19097
* Wed Jun 08 2011 Yu <yu.a.wang@intel.com> - 0.49
- upgrade to 0.49
* Wed May 25 2011 Chris Ferron <chris.e.ferron@linux.intel.com> - 0.48
- Updated spec file to change systemctl as a requires to the package systemd
- for each scriplet section. Also added a Requires systemd as systemd is configured
- as a build option for this package exposing systemd features.
* Tue May 03 2011 Chris Ferron <chris.e.ferron@linux.intel.com> - 0.48
- FEA#16109 - [FEA] Implement SystemD as MeeGo init provide
- Updated the ofono package to be usable by systemd as needed
to implement systemd as the init provider of MeeGo. For this
a systemd ofono.service file was added and installed. This will
allow systemd to start stop and track the service.
* Fri Apr 29 2011 Junfeng Dong <junfeng.dong@intel.com> - 0.48
- Fix the error caused by updating libtool.
* Tue Apr 26 2011 Yu <yu.a.wang@intel.com> - 0.48
- upgrade to 0.48 for BMC #14213
- Fix issue with crash due to not stopped PPP timers.
- Fix issue with offline mode handling and Huawei modem.
- Fix issue with missing check for Huawei modem device open.
- Fix issue with USSD and use of non-cloned GAtChat object.
* Sun Apr 17 2011 Yu <yu.a.wang@intel.com> - 0.47
- upgrade to 0.47 for BMC #14213
- Fix issue with entering offline mode prematurely.
- Add support for CPHS CSP network registration handling.
* Wed Apr 13 2011 Yu <yu.a.wang@intel.com> - 0.46
- upgrade to 0.46
- Fix issue with operator name reading and older ISI modems.
- Fix issue with networking registration and older ISI modems.
- Fix issue with missing handling of PIN/SIM states and ISI modems.
- Fix issue with voice call state reporting and ISI modems.
- Fix issue with STK handling of environment variables.
- Fix issue with STK and empty URL for launch browser.
- Fix issue with voice call pause character validation.
- Fix issue with buffer length and long phone numbers.
- Fix issue with SMS sending retries and network timeout.
- Fix issue with missing SMS submit canceled history status.
- Add support for cancellation of SMS submission.
- Add support for handling SIM Toolkit display action commands.
- Add support for handling call forwarding and SIM refresh.
- Add support for handling EFimg and EFiidf changes.
- Add support for handling EFmsisdn and EFsdn changes.
- Add support for handling emergency calls without SIM.
- Add support for handling emergency calls without PIN.
- Add support for handling emergency number updates.
- Add support for assisted satellite navigation interface.
- Add support for IPv6 contexts and ISI modems.
- Add support for dual-stack GPRS contexts.
- Add limited support for CDMA connection manager interface.
* Mon Mar 28 2011 Yu <yu.a.wang@intel.com> - 0.45
- upgrade to 0.45
- remove three already integrated patches
- Fix issue with SIM Toolkit null data object.
- Fix issue with SIM filesystem and modem release.
- Fix issue with disconnect handling and Huawei modems.
- Add support for improved SSN and voicecall handling.
- Add support for SIM Toolkit Refresh handled by the modem.
- Add support for multiple AT channels and STE modems.
- Add support for ISI drivers and wgmodem2.5 handling.
- Add support for optimized ringbuffer operations.
- Add support for optimized PPP buffer management.
* Fri Feb 18 2011 Martin Xu <martin.xu@intel.com> - 0.41
- Add patches:
- 0001_fix_huawei_em770w.patch
- 0002_fix_huawei_em770w.patch
- 0003_fix_huawei_em770w.patch
- to fix BMC #6944 #10018 #9797 #9201
* Wed Feb 09 2011 Martin Xu <martin.xu@intel.com> - 0.41
- upgrade to 0.41 for BMC #12692
- Fix issue with SIM callback handling.
- Fix issue with XTMS handling and IFX modem.
- Add support for alphabets and SMS encoding.
- Add support for generic PIN retries handling.
- Add support for PIN retries and MBM modem.
- Add support for radio settings and MBM modem.
- Add support for cell broadcast and STE modem.
- Add support for handling ECAV status Released.
* Thu Jan 27 2011 Jouni Peltonen <jouni.peltonen@cybercom.com> - 0.39
- Fixes BMC#12559.
- 0001-isimodem-Fix-race-condition-in-SIM-probe.patch upstream commit: 9306837053cd6ce35e0fe02f03c3cd0eba443f6c.
- 0002-n900-Fix-online.patch upstream commit: f6f0f4d12116cbf8787928146b3b97df21acb739
* Fri Jan 21 2011 Martin Xu <martin.xu@intel.com> - 0.39
- upgrade to 0.39 for BMC #12692
- Fix issue with not handling empty EFecc properly.
- Fix issue with string length and DTMF handling.
- Fix issue with missing info for terminal busy result.
- Fix issue with signal strength handling and IFX modem.
- Fix handling of SIM Toolkit enabling and IFX modem.
- Add support for packet switched bearer notifications.
- Add support for handling called line identification.
- Add support for PIN retry counter interface.
- Add support for ST-Ericsson modem init daemon.
- Add support for Cinterion TC65 modem.
- Add support for simple ISI client interface.
* Fri Jan 07 2011 Martin Xu <martin.xu@intel.com> - 0.38
- upgrade to 0.38 for BMC #12501
- Change CalledLine* to ConnectedLine* properties.
- Fix issue with calling presentation property.
- Fix issue with network time and ISI modems.
- Fix issue with timezone reporting and HSO modems.
- Fix issue with SIM ready status and HSO modems.
- Fix issue with hidden caller ID and STE modems.
- Fix issue with handling of STK Setup Menu.
- Fix issue with missing STK text and icon checks.
- Fix issue with missing signal strength query.
* Wed Dec 08 2010 Martin Xu <martin.xu@intel.com> - 0.36
- upgrade to 0.36
- Fix issue with CLIR Invocation and Suppression.
- Fix issue with power/online transition with ZTE devices.
- Fix segmentation fault when removing Nokia Datacard.
- Add support for Nokia CS-17 dongles.
- Add support for Ericsson F5521gw devices.
- Add support for CAIF network interface management.
- Add support for COLR in generic AT modem driver.
- Add support for SMS Point-to-Point download to UICC.
- Add support for checking specific service availability.
- Add support for handling null text field for STK.
* Mon Nov 15 2010 Martin Xu <martin.xu@intel.com> - 0.35
- upgrade to 0.35
* Wed Nov 03 2010 Martin Xu <martin.xu@intel.com> - 0.34
- upgrade to 0.34
* Tue Oct 26 2010 Martin Xu <martin.xu@intel.com> - 0.33
- upgrade to 0.33 to fix IFX-MAL bugs
* Wed Oct 13 2010 Anas Nashif <nashif@linux.intel.com> - 0.31
- Remove requirement on ofono-config
- Remove unused and obsolete patches
* Mon Oct 11 2010 Martin Xu <martin.xu@intel.com> - 0.31
- upgrade to 0.31
- Remove the N900 package patches, waiting for them in upstream
* Tue Sep 21 2010 Marko Saukko <marko.saukko@cybercom.com> - 0.26
- Updated N900 patch
- Added modem.conf back as phonet is autodetected with the new patches.
- This is the final piece of implementing FEA#4134, FEA#4135, FEA#4136
(Dialer - Make call, end call, receive call) on ARM/N900.
- Fixes BMC#5662 (Nokia N900 modem does not turn on in Ofono)
* Fri Sep 3 2010 Carsten Valdemar Munk <carsten@maemo.org> - 0.26
- Include N900 patch
- Seperate modem.conf out into seperate packages providing ofono-config. Reasoning is because there might be other
devices with phonet0, not all n900modem.
* Thu Aug 26 2010 Martin Xu <martin.xu@intel.com> - 0.26
- upgrade to 0.26
* Mon Jul 19 2010 Martin Xu <martin.xu@intel.com> - 0.25
- upgrade to 0.25
* Wed Jul 14 2010 Martin Xu <martin.xu@intel.com> - 0.24
- upgrade to 0.24
* Tue Jun 22 2010 Martin Xu <martin.xu@intel.com> - 0.23
- Upgrade to 0.23
* Fri May 07 2010 Prajwal Mohan <prajwal.karur.mohan@intel.com> - 0.20
- Enabling phonesim for handset images
* Thu Mar 25 2010 Martin Xu <martin.xu@intel.com> - 0.20
- Upgrade to 0.20
* Tue Feb 23 2010 Martin Xu <martin.xu@intel.com> - 0.18
- upgrade to 0.18
- remove 0001-add-netmask-to-hso-gprs-context-driver.patch
* Mon Feb 22 2010 Anas Nashif <anas.nashif@intel.com> - 0.15
- Use spectacle
- Update Group
* Tue Jan 05 2010 Martin Xu <martin.xu@intel.com> - 0.15
- upgrade to 0.15
- add patch 0001-add-netmask-to-hso-gprs-context-driver.patch
* Mon Dec 14 2009 Martin Xu <martin.xu@intel.com> - 0.14
- upgrade to 0.14
* Thu Dec 7 2009 Martin Xu <martin.xu@intel.com> - 0.13
- remove 0001-Allow-builds-to-install-the-test-scripts-for-debuggi.patch
- remove use_AT_CFUN_to_query_powered_state.patch
- patches has been merged in upstream
* Thu Dec 7 2009 Martin Xu <martin.xu@intel.com> - 0.13
- upgrade to 0.13
* Thu Dec 3 2009 Martin Xu <martin.xu@intel.com> - 0.12
- upgrade to 0.12
- clean up spec file
- add test subpackage
* Wed Nov 25 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.11
Update to version 0.11
* Wed Oct 21 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
Additional helper scripts added
* Mon Oct 19 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
Fix install perms on .desktop file
* Mon Oct 19 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
Fixed .ini file and actually added the .desktop file this time
* Mon Oct 19 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
Add .desktop file back in
* Wed Oct 14 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
Fix build
* Wed Oct 14 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
Fix build
* Wed Oct 14 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
Remove service autostart and allow to run as default user
* Tue Oct 06 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
Fix hardcoded modem path in ofono-modem-power script
* Tue Oct 06 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
Update to version 0.7
* Fri Sep 11 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
Obsolete now defunct ofono-extras package
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
Updated ofono-devel.files with man files and header glob
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
Fixed bad ref to modem.conf in ofono.files
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
Created missing bin dir
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
Created missing autostart and dbus dirs
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
Fixed bad sysconfdir reference
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
Update to version 0.4
Added moblin specific configurations and patches
* Fri Jul 31 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.2
- Add new headers to ofono-devel.files list
* Fri Jul 31 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.2
- Update to tip of tree (0.2+)
* Wed Jun 24 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.0
- Tip of tree update (127b56baccc8830eb1), plus my patches
* Tue Jun 23 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.0
- Add new history.h to installed devel file list
* Tue Jun 23 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.0
- Pulling in latest from tip or tree
* Thu May 21 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.0
- Initial import into Moblin, based on upstream ofono.org git,
commit c427cdfdfacbec9b0221e157797e6c9d33113e91

View File

@@ -1,7 +1,7 @@
Name: ofono
Summary: Open Source Telephony
Version: 1.18
Version: 1.19
Release: 1
Group: Communications/Connectivity Adaptation
License: GPLv2
@@ -10,8 +10,8 @@ Source: %{name}-%{version}.tar.bz2
Requires: dbus
Requires: systemd
Requires: ofono-configs
Requires: libgrilio >= 1.0.10
Requires: libglibutil >= 1.0.10
Requires: libgrilio >= 1.0.14
Requires: libglibutil >= 1.0.23
Requires(preun): systemd
Requires(post): systemd
Requires(postun): systemd
@@ -20,8 +20,8 @@ BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(libudev) >= 145
BuildRequires: pkgconfig(mobile-broadband-provider-info)
BuildRequires: pkgconfig(libwspcodec) >= 2.0
BuildRequires: pkgconfig(libgrilio) >= 1.0.10
BuildRequires: pkgconfig(libglibutil) >= 1.0.10
BuildRequires: pkgconfig(libgrilio) >= 1.0.14
BuildRequires: pkgconfig(libglibutil) >= 1.0.23
BuildRequires: pkgconfig(libdbuslogserver-dbus)
BuildRequires: pkgconfig(libmce-glib)
BuildRequires: libtool
@@ -69,11 +69,17 @@ autoreconf --force --install
%configure --disable-static \
--enable-test \
--enable-debuglog \
--enable-jolla-rilmodem \
--enable-sailfish-bt \
--enable-sailfish-debuglog \
--enable-sailfish-provision \
--enable-sailfish-pushforwarder \
--enable-sailfish-rilmodem \
--disable-add-remove-context \
--disable-isimodem \
--disable-qmimodem \
--with-systemdunitdir="/%{_lib}/systemd/system"
make %{?jobs:-j%jobs}
make %{_smp_mflags}
%check