Compare commits

..

113 Commits

Author SHA1 Message Date
Slava Monich
9e6f7721a0 Merge branch 'stray_call' into 'master'
Fix data connection dying after switching radio tech

See merge request mer-core/ofono!198
2018-10-26 15:50:09 +00:00
Slava Monich
9c529dcdcc [ril] Disconnect stray data calls. JB#42752
Sometimes data calls survive change of radio technology and just get
disassociated from ofono context and we may end up trying to activate
another context, thinking that the previous one is gone, even though
it's still alive. This is something that (at least some) operators
don't like, and start start rejecting our data calls.
2018-10-26 13:15:41 +03:00
Slava Monich
41814c6e6a [ril] Don't take LTE caps away from the only SIM 2018-10-25 01:01:05 +03:00
Slava Monich
cf99a5769f Merge branch 'restrict' into 'master'
Respect state restrictions

See merge request mer-core/ofono!197
2018-09-11 21:48:16 +00:00
Slava Monich
076e2f0ef1 [ril] Respect state restrictions. JB#42752
Do not allow mobile data connections if packet data access is blocked
due to restriction.
2018-09-11 17:01:09 +03:00
Slava Monich
fd76cb72ad Merge branch 'mtk2_incoming_call_fix' into 'master'
Fix incoming call indication on mtk2 vendor.

See merge request mer-core/ofono!196
2018-09-10 09:33:12 +00:00
Sergey Chupligin
554e4ab8e5 [ril] Fix incoming call indication on mtk2 vendor. Fixes JB#40790 2018-09-10 12:22:44 +03:00
NeKit
08f3da7577 [ril] Respond to INCOMING_CALL_INDICATION with SET_CALL_INDICATION. Fixes JB#40950
This is needed to make incoming calls to work on Gemini PDA (and noy only)
2018-09-04 12:55:57 +03:00
Slava Monich
2cbd3b6050 Merge branch 'cell_info_dbg' into 'master'
Improved cell info debug log

See merge request mer-core/ofono!194
2018-07-25 15:16:22 +00:00
Slava Monich
78d3d1892d [ril] Improved cell info debug log. JB#42359 2018-07-25 15:22:32 +03:00
Slava Monich
1448bd2320 Merge branch 'transport' into 'master'
Add interface for RIL transport plugins

See merge request mer-core/ofono!193
2018-07-24 08:05:12 +00:00
Slava Monich
ea8dfb48ab plugin: Don't unload external plugins too early
Plugins may reference data structures allocated by each other.
They all need to be deinitialized first, only then it should be
safe to unload the libraries.
2018-07-24 11:00:12 +03:00
Slava Monich
80921e8b7e [ofono] Add interface for RIL transport plugins. JB#42359
Intended to be used for integrating binder support.
2018-07-21 23:39:53 +03:00
Slava Monich
e4cc912719 [ril] Pull phone number type from SUPP_SVC_NOTIFICATION event
It was left uninitialized which wasn't good.
2018-07-21 23:38:41 +03:00
Slava Monich
c5f736d3c3 [ril] Housekeeping 2018-07-21 17:05:12 +03:00
Slava Monich
ddf4cec9b8 [ril] Do not wait for radio power request to complete
... after the power state has changed to the requested one.
There's no guarantee that rild is going to reply at all.
2018-07-21 17:04:02 +03:00
Slava Monich
685d0b34d7 [ril] Do not submit unnecessary radio power requests
Some RILs don't bother to reply to such a request which
blocks the request queue until such request expires.
2018-07-21 17:00:07 +03:00
Slava Monich
896f2f7a71 [ril] Added confirmRadioPowerOn configration entry
Modern RILs don't need and don't like it. The default
remains on for historical reasons.
2018-07-21 16:57:14 +03:00
Slava Monich
e96aacb9e7 [ril] Added radioPowerCycle configration entry.
With modern RILs radio power cycle shouldn't be necessary, it only
slows down the startup.
2018-07-18 23:37:48 +03:00
Slava Monich
91560afeec Merge branch 'fac_lock' into 'master'
Fix broken QUERY_FACILITY_LOCK packets

See merge request mer-core/ofono!192
2018-07-17 20:34:11 +00:00
Slava Monich
09fb8635c9 [ril] Fix broken QUERY_FACILITY_LOCK packets. Fixes JB#42428
I'm surprised that it worked at all - rild was probably ignoring
the broken part.
2018-07-17 16:27:38 +03:00
Slava Monich
1cb80d7d2f Merge branch 'voicecall_filter3' into 'master'
Allow to filter existing calls

See merge request mer-core/ofono!191
2018-07-05 08:54:46 +00:00
Slava Monich
7db5552e79 [ofono] Allow to filter existing calls. JB#41404
Plugins can request it by invoking ofono_voicecall_filter_notify().
Calls that don't pass the filter will be terminated.
2018-07-02 20:16:54 +03:00
Slava Monich
d87e40d0ff modem: Implement ofono_modem_get_voicecall 2018-07-02 20:15:33 +03:00
Slava Monich
35131ff56b include: Add ofono_modem_get_voicecall 2018-07-02 20:15:33 +03:00
Slava Monich
c5cc678b2b Merge branch 'voicecall-filter2' into 'master'
Voicecall filter tweaking

See merge request mer-core/ofono!190
2018-06-29 08:11:36 +00:00
Slava Monich
31be9a099b [ofono] Don't filter emergency calls. JB#41404 2018-06-29 11:09:46 +03:00
Slava Monich
ccaf993977 [ofono] Return AccessDenied if voice call is blocked by the filter. JB#41404 2018-06-28 19:49:01 +03:00
Slava Monich
74d633c58e dbus: Add D-Bus mapping for OFONO_ERROR_TYPE_ERRNO 2018-06-28 19:48:48 +03:00
Slava Monich
f870880cf9 emulator: Handle OFONO_ERROR_TYPE_ERRNO in switch 2018-06-28 19:48:48 +03:00
Slava Monich
50c06afc73 include: Add OFONO_ERROR_TYPE_ERRNO 2018-06-28 19:48:48 +03:00
Slava Monich
e4e0ccd51d [ofono] Housekeeping
Removed unused OFONO_EINVAL and OFONO_NO_ERROR macros
2018-06-28 19:19:25 +03:00
Slava Monich
ee052af454 dbus: Make cme_errors_mapping static const 2018-06-28 19:11:16 +03:00
Slava Monich
296b272274 Merge branch 'voicecall-filter' into 'master'
Voice call filter

See merge request mer-core/ofono!189
2018-06-28 09:35:33 +00:00
Slava Monich
9b9e5159f5 [ofono] Hooked up voicecall-filter. JB#41404 2018-06-27 16:45:22 +03:00
Slava Monich
fa8002200c [ofono] Added voicecall-filter. JB#41404 2018-06-27 16:45:06 +03:00
Slava Monich
4cc71c78ec [ril] Implement hangup_active in voicecall driver 2018-06-27 16:43:13 +03:00
Slava Monich
27b31e65bb [ril] set_udub should be implemented as RIL_REQUEST_UDUB 2018-06-26 11:50:07 +03:00
Slava Monich
e26d365a94 voicecall: Implement ofono_voicecall_get_modem 2018-06-26 11:49:04 +03:00
Slava Monich
63f06cd11c include: Add ofono_voicecall_get_modem 2018-06-26 11:49:03 +03:00
Slava Monich
96ca3aa907 [gprs-filter] Removed unnecessary forward declaration 2018-06-21 11:55:34 +03:00
Slava Monich
11a84853fe Merge branch 'jb41925' into 'master'
Make sure that USSD cancel callback is invoked

See merge request mer-core/ofono!188
2018-05-24 15:28:47 +00:00
Slava Monich
a393cf0b11 [ril] Make sure that USSD cancel callback is invoked. JB#41925
Some RILs don't bother to reply. But if we don't invoke the callback
provided by ofono core, its USSD machinery gets stuck in active state.
2018-05-24 15:17:30 +03:00
Slava Monich
6f263ee8d5 ussd: Cancel pending requests when unregistering
And reset state to idle before unregistering the D-Bus interface.
This may occur e.g. when we receive REFRESH from STK.
2018-05-23 20:48:27 +03:00
Slava Monich
92a4760f46 Merge branch 'nettime' into 'master'
Handle NITZ string without DST part

See merge request mer-core/ofono!187
2018-05-16 08:20:05 +00:00
Slava Monich
c43d41829f [ril] Handle NITZ string without DST part. Fixes JB#41890 2018-05-16 00:09:13 +03:00
Slava Monich
25638a30c0 [ril] netreg: Housekeeping 2018-05-15 23:55:36 +03:00
Slava Monich
ed669bf66c Merge branch 'jb41508' into 'master'
Don't wait for SIM state change after enabling/disabling pin

See merge request mer-core/ofono!186
2018-05-14 15:46:46 +00:00
Slava Monich
e01dbd2b21 [ril] Don't wait for SIM state change after enabling/disabling pin. JB#41508
There's no real need for that, but most importantly no SIM state change
event is generated by MTK RIL in such cases.
2018-05-14 16:10:37 +03:00
Slava Monich
a8f0f26df8 Merge branch 'mdm_deactivate' into 'master'
Add filter_check to ofono_gprs_filter

See merge request mer-core/ofono!185
2018-05-04 13:26:55 +00:00
Slava Monich
56c84395ba [ofono] Added filter_check to ofono_gprs_filter. JB#41665
It checks if ofono_gprs_filter allows mobile data in general,
not just for the particular context.
2018-05-03 19:35:04 +03:00
Slava Monich
3bf2b1df5c [ofono] Expose gprs_attached_update() to plugins. JB#41665
ofono_gprs_filter plugins implementing API version 1 or later
should call this function when their configuration changes and
mobile data may have become disallowed for the current SIM.
2018-05-03 19:14:28 +03:00
Slava Monich
75041ccc37 modem: Implement ofono_modem_get_gprs 2018-05-03 19:14:28 +03:00
Slava Monich
e91ef8a701 include: Add ofono_modem_get_gprs 2018-05-03 19:14:28 +03:00
Slava Monich
620a20abdc [coverage] Remove *.gcda and *.gcno files on clean 2018-05-03 19:13:57 +03:00
Slava Monich
d85fa8a64d Merge branch 'mtk_caps' into 'master'
Capability switch issues

See merge request mer-core/ofono!183
2018-04-25 13:02:30 +00:00
Slava Monich
d33b20889b [ril] Made SET_PREFERRED_NETWORK_TYPE timeout configurable. JB#41570 2018-04-25 15:55:18 +03:00
Slava Monich
cb8801752c [ril] Destroying ril_radio_caps cancels its pending requests. JB#41570
Mediatek rild restarts in the middle of the caps switch transaction,
destroying ril_radio_caps in the process. That should terminate the
transaction.
2018-04-25 12:29:00 +03:00
Slava Monich
a0722f8538 [ril] Don't retry SET_PREFERRED_NETWORK_TYPE too often. JB#41570
That has a disastrous effect with some RILs, slowing things down
to almost a complete stop.
2018-04-25 12:29:00 +03:00
Slava Monich
e016281b86 Merge branch 'lte_mode' into 'master'
Make LTE mode configurable

See merge request mer-core/ofono!184
2018-04-25 09:23:45 +00:00
Sergey Chupligin
781a528625 [rild] make lte mode configurable 2018-04-25 12:02:21 +03:00
Slava Monich
5b1ab91b77 ussd: Don't ignore data from TERMINATED response
Typically responses to USSD requests are coming with status
zero (NOTIFY) but some are coming with status 2 (TERMINATED).
If those contain data, the data should be presented to the user.

[ussd] Don't ignore data from TERMINATED response. Fixes JB#41734
2018-04-23 22:05:03 +03:00
Slava Monich
9604d9ef0a Merge branch 'sim_caps_fix' into 'master'
Fix a few issues with caps switch

See merge request mer-core/ofono!181
2018-04-20 13:05:28 +00:00
Slava Monich
598acaa1a8 [ril] Some events triggering caps switch, were missed. Fixes JB#41583
As a result, the data slot could be left with GSM caps and the other
slot (possibly empty) would keep enjoying LTE caps which it doesn't
really need.
2018-04-19 12:00:08 +03:00
Slava Monich
60193032f5 [ril] Make sure cancelled I/O doesn't remain marked as active. JB#41583
Otherwise capability switch may never start after a rild crash
waiting forever for SIM I/O to calm down.
2018-04-18 15:57:53 +03:00
Slava Monich
9faf27ec28 Merge branch 'initial_apn' into 'master'
Fix SET_INITIAL_ATTACH_APN crash on some MTK devices

See merge request mer-core/ofono!180
2018-04-11 15:20:17 +00:00
Slava Monich
32c26c5a35 [ril] Fix SET_INITIAL_ATTACH_APN crash on some MTK devices. Fixes JB#41587
This may break some other devices but let's give it a try.
2018-04-11 17:43:30 +03:00
Slava Monich
79fb591342 Merge branch 'query_available_band_mode' into 'master'
Don't use QUERY_AVAILABLE_BAND_MODE with MTK RILs

See merge request mer-core/ofono!179
2018-04-03 15:29:26 +00:00
Slava Monich
f6e46f78e3 [ril] Don't use QUERY_AVAILABLE_BAND_MODE with MTK RILs. Fixes JB#41506
Most MTK RIL implementations don't support this request and don't even
bother to reply which slows things down because we wait for this request
to complete at startup.
2018-04-03 16:11:10 +03:00
Slava Monich
7c587772d1 [ofono] Return AccessDenied if filter disallows a data call. JB#41405 2018-03-29 20:51:54 +03:00
Slava Monich
0d0728593b Housekeeping 2018-03-27 13:10:35 +03:00
Slava Monich
fd3916b2c7 Merge branch 'jb41496' into 'master'
Deduce signal strength from RSRP

See merge request mer-core/ofono!178
2018-03-27 10:05:29 +00:00
Slava Monich
c35557c2ed [ril] Deduce signal strength from RSRP. Fixes JB#41497
Some RILs report zero signal strength AND a valid LTE RSRP value in
RIL_UNSOL_SIGNAL_STRENGTH. In that case, calculate signal strength
from RSRP.
2018-03-26 20:48:12 +03:00
Slava Monich
bb07543dd6 Merge branch 'jb41474' into 'master'
Fixed parsing of data call list

See merge request mer-core/ofono!177
2018-03-26 14:07:16 +00:00
Slava Monich
d346f1289c [ril] Fixed parsing of data call list. Fixes JB#41474
The code was incorrectly assuming that each data call block has the
same size. This is an absolutely wrong assumption. It's especially
wrong if one data call has IPv6 addresses assigned and the other one
doesn't - in this case one block may be several times bigger than
the other.

The regression was introduced by commit 8c9e3704
2018-03-26 13:09:57 +03:00
Slava Monich
e170b6df4c [unit] Added test-dbus-queue. JB#38932
Lines:     112/112  100.0%
    Functions:   17/17  100.0%
    Branches:    56/56  100.0%
2018-03-23 17:19:05 +02:00
Slava Monich
761cd320bb [ofono] Fixed a few corner cases in D-Bus queue 2018-03-23 17:16:37 +02:00
Slava Monich
60bc47aea2 Merge branch 'gprs-filter' into 'master'
Add support for mobile data filter plugins

See merge request !176
2018-03-23 15:12:59 +00:00
Slava Monich
183e4dab4b [unit] Added test-gprs-filter
Tests gprs-filter.c

Lines:     128/128  100.0%
Functions:   17/17  100.0%
Branches:    61/64   95.3%
2018-03-23 12:41:30 +02:00
Slava Monich
d6cdfc92ad [ofono] Added support for gprs filter plugins. JB#41405
Such plugins can selectively disallow mobile data connections
or modify the actual access point settings sent to the driver
2018-03-22 13:53:06 +02:00
Slava Monich
b68752640c voicecall: Use dbus_validate_path
Instead of __ofono_dbus_valid_object_path which is no more
2018-03-21 15:05:02 +02:00
Slava Monich
a53fc6ea7e dbus: Use dbus_validate_path
Instead of __ofono_dbus_valid_object_path
2018-03-21 11:17:54 +02:00
Slava Monich
63fe971077 Merge branch 'config_merge' into 'master'
Allow multiple RIL config files

See merge request !175
2018-03-13 14:01:04 +00:00
Slava Monich
011f3b74d1 [ril] Allow multiple RIL config files. Fixes JB#41276
In addition to the usual /etc/ofono/ril_subscription.conf config file,
additional *.conf files from /etc/ofono/ril_subscription.d directory
will be merged in.
2018-03-13 16:59:52 +03:00
Slava Monich
4d2e314ad6 [ril] Unit test for ril_config.c 2018-03-13 12:10:33 +03:00
Slava Monich
d846618057 [ril] Added ril_config_merge_files utility 2018-03-13 11:53:13 +03:00
Slava Monich
38115199f7 [ril] Allow comments in int array config values 2018-03-13 11:52:50 +03:00
Slava Monich
f88c7ce919 [ril] Explicitely include <glib-object.h> where it's needed. MER#1437
Don't rely on gutil_types.h to pull it in
2018-02-25 16:48:39 +02:00
Slava Monich
9d6b3ec124 Merge branch 'mtk' into 'master'
Detect MTK variant based on events codes

See merge request !174
2018-02-23 08:55:58 +00:00
Slava Monich
6dcf5cebc1 [ril] Detect MTK variant based on events codes. JB#40397
The same (or very similar) kinds of hardware may be (and are!)
running different MTK adaptation software, totally incompatible
with each other. The new approach is an attempt to figure it out
based on the unsolicited events we are receiving from rild.

It's still possible to exlicitely choose the variant (e.g. mtk2)
2018-02-22 22:59:54 +02:00
Slava Monich
0e87392c90 phonebook: Fixed double deletion of merge_list 2018-02-22 22:58:32 +02:00
Slava Monich
dab76692db Merge branch 'uuid_sub' into 'master'
Fix UICC subscription

See merge request !173
2018-02-22 12:32:20 +00:00
Slava Monich
21bc90f638 [ril] Fix UICC subscription. JB#41130
The previous commit slightly broke it. Under certain circumstances
UICC subscription was never attempted.
2018-02-21 16:18:50 +02:00
Slava Monich
d8707d52be Merge branch 'uicc_sub_stop' into 'master'
Support for dual-IMSI SIMs

When subscription gets switched via STK, rild generates SIM_REFRESH
event and we need  to reinitialize the SIM, i.e. re-read all the
EFs, at least under GSM/Telecom DF. Currently, reinitialization
is performed by simulating a SIM swap. That, however, has an
unpleasant side effect - the phones which don't support hot-swap
ask the user to reboot the phone (in this case, unnecessarily).

A better way of reinitializing the SIM should be implemented,
which wouldn't generate this misleading warning, but in the
meantime let's merge this one because it at least appears to work.

See merge request !172
2018-02-20 13:33:00 +00:00
Slava Monich
fa0abf892d [ril] Give SIM card 10 seconds to activate USIM app. JB#41130
And only then poke rild with SET_UICC_SUBSCRIPTION request.
2018-02-20 13:25:45 +02:00
Slava Monich
8a28d4eea8 [ril] A better way to reset the SIM state
It's better to simulate SIM card removal at RilSimCard level.
That way the presence of the SIM card won't be reported until
we fetch the actual SIM status (which may require a few retries
if the reset was initiated by STK).
2018-02-15 18:05:33 +02:00
Slava Monich
4f0be99683 [gprs] Disable special treatment of LTE
In Sailfish OS the Attached flag is used by connman to check whether
context activation is possible. There won't be any context activation
if Attached stays false.
2018-02-15 18:03:42 +02:00
Slava Monich
95933beb2d [ril] Handle RIL_UNSOL_SIM_REFRESH 2018-02-15 12:33:55 +02:00
Slava Monich
018a712e29 [ril] Make sure that SET_UICC_SUBSCRIPTION is not repeated forever. 2018-02-12 16:52:08 +03:00
Slava Monich
e6777f1ecc Merge branch 'cbs' into 'master'
Make CBS support configurable

See merge request !171
2018-02-09 13:49:40 +00:00
Slava Monich
a58e1a5e9b [ril] Make CBS support configurable. Fixes MER#1873
By default it's enabled. To disable CBS, set enableCellBroadcast=false
in /etc/ofono/ril_subscription.conf
2018-02-09 01:20:24 +03:00
Slava Monich
61be41240f Merge branch 'mtk_call' into 'master'
Handle INCOMING_CALL_INDICATION event

See merge request !170
2018-01-30 10:46:03 +00:00
Slava Monich
dbb40560c6 [mtk] Handle INCOMING_CALL_INDICATION event. JB#40950
MTK RILs (at least some of them) are not bothering to submit
the standard CALL_STATE_CHANGED event when a new incoming call
is received. Let's do it for them.

Even if they suddenly change their mind and start sending
CALL_STATE_CHANGED events, there's no harm in receiving
multiple events - we will handle that just fine.
2018-01-29 18:41:09 +02:00
Slava Monich
9bf50bb3e3 Merge branch 'mtk_4g' into 'master'
Make 4G work on MTK tablet

See merge request !169
2018-01-29 15:08:06 +00:00
Slava Monich
d2353c46a8 [ril] Make 4G work on MTK tablet. Fixes JB#40923
It seems to require initial attach APN to be set before it can
register with a 4G network.
2018-01-29 16:56:28 +02:00
Slava Monich
6701b53737 Merge branch 'mtk_reg' into 'master'
Poll registration state on PS_NETWORK_STATE_CHANGED

See merge request !168
2018-01-26 09:45:20 +00:00
Slava Monich
6612bfa1da [ril] Poll registration state on PS_NETWORK_STATE_CHANGED. Fixes JB#40937
MTK rild appears to send this event (with 3 integers as the payload),
whenever data registration state changes. That's a good time to poll
the current state.
2018-01-26 01:21:07 +02:00
Slava Monich
c732d5192d [unit] Added test-sailfish_watch
Tests sailfish_watch.c

  Lines:     336/336 100.0 %
  Functions:   52/52 100.0 %
  Branches:  142/180  78.9 %
2018-01-24 23:20:39 +02:00
Slava Monich
6815772b17 [ofono] sailfish_watch should reset online flag when modem is removed 2018-01-24 23:17:22 +02:00
Slava Monich
e4766ef2c4 [rpm] Made dbus unit tests work with older versions of dbus (e.g. 1.6) 2018-01-24 15:57:15 +02:00
Slava Monich
7aa396636b Merge branch 'cid' into 'master'
Use the right cid to signal context settings change

See merge request !167
2018-01-24 09:08:31 +00:00
Slava Monich
096cd04044 [ril] Use the right cid to signal context settings change. Fixes JB#40845 2018-01-23 18:19:35 +02:00
Slava Monich
5eabe96602 [ril] INT_MAX -> SAILFISH_CELL_INVALID_VALUE where appropriate
They are numerically equivalent but the latter has a clearer semantics.
2018-01-23 17:51:56 +02:00
73 changed files with 9163 additions and 1245 deletions

61
.gitignore vendored
View File

@@ -1,61 +0,0 @@
*.o
*.lo
*.la
.deps
.libs
.dirstamp
Makefile
Makefile.in
aclocal.m4
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
depcomp
compile
install-sh
libtool
ltmain.sh
missing
stamp-h1
autom4te.cache
test-driver
test-suite.log
ofono.pc
include/ofono
include/version.h
src/builtin.h
src/ofonod
src/ofono.service
dundee/dundee
dundee/dundee.service
unit/test-common
unit/test-util
unit/test-idmap
unit/test-sms
unit/test-sms-root
unit/test-simutil
unit/test-mux
unit/test-caif
unit/test-stkutil
unit/test-cdmasms
unit/test-*.log
unit/test-*.trs
tools/huawei-audio
tools/auto-enable
tools/get-location
tools/lookup-apn
tools/lookup-provider-name
tools/tty-redirector
tools/qmi
tools/stktest
gatchat/gsmdial
gatchat/test-server
gatchat/test-qcdm

View File

@@ -1,7 +0,0 @@
Luiz Augusto von Dentz <luiz.dentz-von@nokia.com> <luiz.dentz-von@nokia.com>
Zhenhua Zhang <zhenhua.zhang@intel.com> <zhenhua.zhang@intel.com>
Pekka Pessi <pekka.pessi@nokia.com> <Pekka.Pessi@nokia.com>
Pekka Pessi <pekka.pessi@nokia.com> <ppessi@hamsa.research.nokia.com>
Lasse Kunnasluoto <lasse.kunnasluoto@tieto.com> <Lasse.Kunnasluoto@tieto.com>
Syam Sidhardhan <s.syam@samsung.com> <syamsidhardh@gmail.com>
Michael Dietrich <mdt@emdete.de> <mdt@emdete.de>

8
ofono/.gitignore vendored
View File

@@ -32,6 +32,8 @@ src/ofono.service
dundee/dundee
dundee/dundee.service
test-driver
test-suite.log
unit/test-common
unit/test-util
unit/test-idmap
@@ -42,7 +44,11 @@ unit/test-mux
unit/test-caif
unit/test-stkutil
unit/test-cdmasms
unit/test-dbus-queue
unit/test-gprs-filter
unit/test-ril_config
unit/test-ril_util
unit/test-ril-transport
unit/test-rilmodem-cb
unit/test-rilmodem-cs
unit/test-rilmodem-gprs
@@ -52,7 +58,9 @@ unit/test-sailfish_cell_info_dbus
unit/test-sailfish_manager
unit/test-sailfish_sim_info
unit/test-sailfish_sim_info_dbus
unit/test-sailfish_watch
unit/test-sms-filter
unit/test-voicecall-filter
unit/test-*.log
unit/test-*.trs

View File

@@ -23,7 +23,9 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
include/cdma-provision.h include/handsfree.h \
include/sim-mnclength.h \
include/handsfree-audio.h include/siri.h \
include/sms-filter.h \
include/sms-filter.h include/gprs-filter.h \
include/voicecall-filter.h \
include/ril-constants.h include/ril-transport.h \
include/netmon.h include/lte.h \
include/storage.h \
gdbus/gdbus.h
@@ -736,7 +738,8 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/cdma-provision.c src/handsfree.c \
src/handsfree-audio.c src/bluetooth.h \
src/sim-mnclength.c src/voicecallagent.c \
src/sms-filter.c src/dbus-queue.c \
src/sms-filter.c src/gprs-filter.c src/dbus-queue.c \
src/voicecall-filter.c src/ril-transport.c \
src/hfp.h src/siri.c \
src/netmon.c src/lte.c \
src/netmonagent.c src/netmonagent.h
@@ -749,7 +752,8 @@ src_ofonod_LDFLAGS = -Wl,--export-dynamic \
BUILT_SOURCES = $(local_headers) src/builtin.h
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA)
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA) \
$(shell find . -name "*.gcda") $(shell find . -name "*.gcno")
plugindir = $(pkglibdir)/plugins
@@ -919,8 +923,7 @@ unit_objects =
unit_tests = unit/test-common unit/test-util unit/test-idmap \
unit/test-simutil unit/test-stkutil \
unit/test-sms unit/test-cdmasms \
unit/test-provision unit/test-sms-filter
unit/test-sms unit/test-cdmasms
if SAILFISH_MANAGER
@@ -980,11 +983,27 @@ unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
unit_tests += unit/test-sailfish_manager
unit_test_sailfish_watch_SOURCES = unit/test-sailfish_watch.c \
plugins/sailfish_manager/sailfish_watch.c \
src/log.c src/watch.c
unit_test_sailfish_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
unit_test_sailfish_watch_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_watch_OBJECTS)
unit_tests += unit/test-sailfish_watch
endif
if RILMODEM
if SAILFISH_RILMODEM
unit_test_ril_config_SOURCES = unit/test-ril_config.c drivers/ril/ril_util.c \
drivers/ril/ril_config.c src/log.c
unit_test_ril_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_config_OBJECTS)
unit_tests += unit/test-ril_config
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
src/log.c
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
@@ -1061,6 +1080,14 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_caif_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_caif_OBJECTS)
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
src/dbus-queue.c gdbus/object.c \
src/dbus.c src/log.c
unit_test_dbus_queue_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_dbus_queue_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_dbus_queue_OBJECTS)
unit_tests += unit/test-dbus-queue
unit_test_provision_SOURCES = unit/test-provision.c \
plugins/provision.h plugins/mbpi.c \
plugins/sailfish_provision.c \
@@ -1068,12 +1095,36 @@ unit_test_provision_SOURCES = unit/test-provision.c \
unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_provision_OBJECTS)
unit_tests += unit/test-provision
unit_test_ril_transport_SOURCES = unit/test-ril-transport.c \
src/ril-transport.c src/log.c
unit_test_ril_transport_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_transport_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_transport_OBJECTS)
unit_tests += unit/test-ril-transport
unit_test_sms_filter_SOURCES = unit/test-sms-filter.c \
src/sms-filter.c src/log.c
unit_test_sms_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_sms_filter_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sms_filter_OBJECTS)
unit_tests += unit/test-sms-filter
unit_test_gprs_filter_SOURCES = unit/test-gprs-filter.c \
src/gprs-filter.c src/log.c
unit_test_gprs_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_gprs_filter_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_gprs_filter_OBJECTS)
unit_tests += unit/test-gprs-filter
unit_test_voicecall_filter_SOURCES = unit/test-voicecall-filter.c \
src/voicecall-filter.c src/log.c \
src/common.c src/util.c
unit_test_voicecall_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_voicecall_filter_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_voicecall_filter_OBJECTS)
unit_tests += unit/test-voicecall-filter
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
gatchat/ringbuffer.h gatchat/ringbuffer.c \

View File

@@ -184,10 +184,10 @@ AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
if (test "${enable_sailfish_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.20, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.20 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.25, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.25 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.30, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.30 is required))
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
AC_MSG_ERROR(libmce-glib >= 1.0.5 is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"

View File

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

View File

@@ -23,6 +23,7 @@
#include <grilio_request.h>
#include <grilio_parser.h>
#include <gutil_idlepool.h>
#include <gutil_misc.h>
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
@@ -75,6 +76,20 @@ static void ril_cell_free1(gpointer cell)
ril_cell_free(cell);
}
static const char *ril_cell_info_int_format(int value, const char *format)
{
if (value == SAILFISH_CELL_INVALID_VALUE) {
return "";
} else {
static GUtilIdlePool *ril_cell_info_pool = NULL;
GUtilIdlePool *pool = gutil_idle_pool_get(&ril_cell_info_pool);
char *str = g_strdup_printf(format, value);
gutil_idle_pool_add(pool, str, g_free);
return str;
}
}
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
{
while (l1 && l2) {
@@ -106,10 +121,10 @@ static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
/* Optional RIL_CellIdentityGsm_v12 part */
gsm->arfcn = INT_MAX;
gsm->bsic = INT_MAX;
gsm->arfcn = SAILFISH_CELL_INVALID_VALUE;
gsm->bsic = SAILFISH_CELL_INVALID_VALUE;
/* Optional RIL_GSM_SignalStrength_v12 part */
gsm->timingAdvance = INT_MAX;
gsm->timingAdvance = SAILFISH_CELL_INVALID_VALUE;
/* RIL_CellIdentityGsm */
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
grilio_parser_get_int32(rilp, &gsm->mnc) &&
@@ -123,11 +138,17 @@ static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
grilio_parser_get_int32(rilp, &gsm->bitErrorRate) &&
(version < 12 || /* RIL_GSM_SignalStrength_v12 part */
grilio_parser_get_int32(rilp, &gsm->timingAdvance))) {
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,arfcn=%d,"
"bsic=%d,strength=%d,err=%d,t=%d", registered,
gsm->mcc, gsm->mnc, gsm->lac, gsm->cid, gsm->arfcn,
gsm->bsic, gsm->signalStrength, gsm->bitErrorRate,
gsm->timingAdvance);
DBG("[gsm] reg=%d%s%s%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(gsm->mcc, ",mcc=%d"),
ril_cell_info_int_format(gsm->mnc, ",mnc=%d"),
ril_cell_info_int_format(gsm->lac, ",lac=%d"),
ril_cell_info_int_format(gsm->cid, ",cid=%d"),
ril_cell_info_int_format(gsm->arfcn, ",arfcn=%d"),
ril_cell_info_int_format(gsm->bsic, ",bsic=%d"),
ril_cell_info_int_format(gsm->signalStrength,
",strength=%d"),
ril_cell_info_int_format(gsm->bitErrorRate, ",err=%d"),
ril_cell_info_int_format(gsm->timingAdvance, ",t=%d"));
cell->type = SAILFISH_CELL_TYPE_GSM;
cell->registered = registered;
return cell;
@@ -145,7 +166,7 @@ static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
/* Optional RIL_CellIdentityWcdma_v12 part */
wcdma->uarfcn = INT_MAX;
wcdma->uarfcn = SAILFISH_CELL_INVALID_VALUE;
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
grilio_parser_get_int32(rilp, &wcdma->lac) &&
@@ -155,10 +176,16 @@ static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
grilio_parser_get_int32(rilp, &wcdma->uarfcn)) &&
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
DBG("[wcdma] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,psc=%d,"
"strength=%d,err=%d", registered, wcdma->mcc,
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
wcdma->signalStrength, wcdma->bitErrorRate);
DBG("[wcdma] reg=%d%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(wcdma->mcc, ",mcc=%d"),
ril_cell_info_int_format(wcdma->mnc, ",mnc=%d"),
ril_cell_info_int_format(wcdma->lac, ",lac=%d"),
ril_cell_info_int_format(wcdma->cid, ",cid=%d"),
ril_cell_info_int_format(wcdma->psc, ",psc=%d"),
ril_cell_info_int_format(wcdma->signalStrength,
",strength=%d"),
ril_cell_info_int_format(wcdma->bitErrorRate,
",err=%d"));
cell->type = SAILFISH_CELL_TYPE_WCDMA;
cell->registered = registered;
return cell;
@@ -176,7 +203,7 @@ static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
struct sailfish_cell_info_lte *lte = &cell->info.lte;
/* Optional RIL_CellIdentityLte_v12 part */
lte->earfcn = INT_MAX;
lte->earfcn = SAILFISH_CELL_INVALID_VALUE;
if (grilio_parser_get_int32(rilp, &lte->mcc) &&
grilio_parser_get_int32(rilp, &lte->mnc) &&
grilio_parser_get_int32(rilp, &lte->ci) &&
@@ -190,11 +217,19 @@ static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
grilio_parser_get_int32(rilp, &lte->rssnr) &&
grilio_parser_get_int32(rilp, &lte->cqi) &&
grilio_parser_get_int32(rilp, &lte->timingAdvance)) {
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
"strength=%d,rsrp=%d,rsrq=%d,rssnr=%d,cqi=%d,"
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
DBG("[lte] reg=%d%s%s%s%s%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(lte->mcc, ",mcc=%d"),
ril_cell_info_int_format(lte->mnc, ",mnc=%d"),
ril_cell_info_int_format(lte->ci, ",ci=%d"),
ril_cell_info_int_format(lte->pci, ",pci=%d"),
ril_cell_info_int_format(lte->tac, ",tac=%d"),
ril_cell_info_int_format(lte->signalStrength,
",strength=%d"),
ril_cell_info_int_format(lte->rsrp, ",rsrp=%d"),
ril_cell_info_int_format(lte->rsrq, ",rsrq=%d"),
ril_cell_info_int_format(lte->rssnr, ",rssnr=%d"),
ril_cell_info_int_format(lte->cqi, ",cqi=%d"),
ril_cell_info_int_format(lte->timingAdvance, ",t=%d"));
cell->type = SAILFISH_CELL_TYPE_LTE;
cell->registered = registered;
return cell;

View File

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

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,6 +22,8 @@
#define RILCONF_SETTINGS_GROUP "Settings"
void ril_config_merge_files(GKeyFile *conf, const char *file);
char *ril_config_get_string(GKeyFile *file, const char *group,
const char *key);
char **ril_config_get_strings(GKeyFile *file, const char *group,

View File

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

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -76,6 +76,12 @@ enum ril_data_priv_flags {
typedef GObjectClass RilDataClass;
typedef struct ril_data RilData;
enum ril_data_io_event_id {
IO_EVENT_DATA_CALL_LIST_CHANGED,
IO_EVENT_RESTRICTED_STATE_CHANGED,
IO_EVENT_COUNT
};
enum ril_data_settings_event_id {
SETTINGS_EVENT_IMSI_CHANGED,
SETTINGS_EVENT_PREF_MODE,
@@ -94,9 +100,11 @@ struct ril_data_priv {
struct ril_radio *radio;
struct ril_network *network;
struct ril_data_manager *dm;
enum ril_data_priv_flags flags;
struct ril_vendor_hook *vendor_hook;
enum ril_data_priv_flags flags;
enum ril_restricted_state restricted_state;
struct ril_data_request *req_queue;
struct ril_data_request *pending_req;
@@ -104,8 +112,9 @@ struct ril_data_priv {
guint slot;
char *log_prefix;
guint query_id;
gulong io_event_id;
gulong io_event_id[IO_EVENT_COUNT];
gulong settings_event_id[SETTINGS_EVENT_COUNT];
GHashTable* grab;
};
enum ril_data_signal {
@@ -177,7 +186,7 @@ struct ril_data_request_allow_data {
static void ril_data_manager_check_data(struct ril_data_manager *dm);
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
static void ril_data_call_deact_cid(struct ril_data *data, int cid);
static void ril_data_power_update(struct ril_data *self);
static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
{
@@ -360,7 +369,8 @@ static struct ril_data_call *ril_data_call_parse(struct ril_vendor_hook *hook,
/* Try the default parser */
ril_data_call_destroy(call);
memset(call, 0, sizeof(*call));
parsed = ril_data_call_parse_default(call, version, &copy);
*parser = copy;
parsed = ril_data_call_parse_default(call, version, parser);
}
if (parsed) {
@@ -386,7 +396,7 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
guint len, struct ril_vendor_hook *hook,
enum ril_data_call_format format)
{
guint32 version, n;
guint32 version, n, i;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
@@ -403,22 +413,14 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
list->version = format;
}
if (n > 0) {
guint i, clen = grilio_parser_bytes_remaining(&rilp)/n;
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
struct ril_data_call *call = ril_data_call_parse(hook,
list->version, &rilp);
for (i = 0; i < n; i++) {
GRilIoParser callp;
struct ril_data_call *call;
grilio_parser_get_data(&rilp, &callp, clen);
call = ril_data_call_parse(hook, list->version,
&callp);
if (call) {
list->num++;
list->calls = g_slist_insert_sorted
(list->calls, call,
ril_data_call_compare);
}
if (call) {
list->num++;
list->calls = g_slist_insert_sorted(list->calls,
call, ril_data_call_compare);
}
}
@@ -544,6 +546,10 @@ struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
static void ril_data_set_calls(struct ril_data *self,
struct ril_data_call_list *list)
{
struct ril_data_priv *priv = self->priv;
GHashTableIter it;
gpointer key;
if (!ril_data_call_list_equal(self->data_calls, list)) {
DBG("data calls changed");
ril_data_call_list_free(self->data_calls);
@@ -552,6 +558,63 @@ static void ril_data_set_calls(struct ril_data *self,
} else {
ril_data_call_list_free(list);
}
/* Clean up the grab table */
g_hash_table_iter_init(&it, priv->grab);
while (g_hash_table_iter_next(&it, &key, NULL)) {
const int cid = GPOINTER_TO_INT(key);
if (!ril_data_call_find(self->data_calls, cid)) {
g_hash_table_iter_remove(&it);
}
}
if (self->data_calls) {
GSList *l;
/* Disconnect stray calls (one at a time) */
for (l = self->data_calls->calls; l; l = l->next) {
struct ril_data_call *dc = l->data;
key = GINT_TO_POINTER(dc->cid);
if (!g_hash_table_contains(priv->grab, key)) {
DBG_(self, "stray call %u", dc->cid);
ril_data_call_deact_cid(self, dc->cid);
break;
}
}
}
}
static void ril_data_check_allowed(struct ril_data *self, gboolean was_allowed)
{
if (ril_data_allowed(self) != was_allowed) {
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
}
}
static void ril_data_restricted_state_changed_cb(GRilIoChannel *io, guint event,
const void *data, guint len, void *user_data)
{
struct ril_data *self = RIL_DATA(user_data);
GRilIoParser rilp;
guint32 count, state;
GASSERT(event == RIL_UNSOL_RESTRICTED_STATE_CHANGED);
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &count) && count == 1 &&
grilio_parser_get_uint32(&rilp, &state) &&
grilio_parser_at_end(&rilp)) {
struct ril_data_priv *priv = self->priv;
if (priv->restricted_state != state) {
const gboolean was_allowed = ril_data_allowed(self);
DBG_(self, "restricted state 0x%02x", state);
priv->restricted_state = state;
ril_data_check_allowed(self, was_allowed);
}
}
}
static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
@@ -1051,6 +1114,11 @@ static struct ril_data_request *ril_data_call_deact_new(struct ril_data *data,
return req;
}
static void ril_data_call_deact_cid(struct ril_data *data, int cid)
{
ril_data_request_queue(ril_data_call_deact_new(data, cid, NULL, NULL));
}
/*==========================================================================*
* ril_data_allow_request
*==========================================================================*/
@@ -1077,9 +1145,7 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
DBG_(data, "data off");
}
if (ril_data_allowed(data) != was_allowed) {
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
}
ril_data_check_allowed(data, was_allowed);
}
ril_data_request_finish(req);
@@ -1195,9 +1261,15 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
priv->radio = ril_radio_ref(radio);
priv->network = ril_network_ref(network);
priv->vendor_hook = ril_vendor_hook_ref(vendor_hook);
priv->io_event_id = grilio_channel_add_unsol_event_handler(io,
priv->io_event_id[IO_EVENT_DATA_CALL_LIST_CHANGED] =
grilio_channel_add_unsol_event_handler(io,
ril_data_call_list_changed_cb,
RIL_UNSOL_DATA_CALL_LIST_CHANGED, self);
priv->io_event_id[IO_EVENT_RESTRICTED_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(io,
ril_data_restricted_state_changed_cb,
RIL_UNSOL_RESTRICTED_STATE_CHANGED, self);
priv->settings_event_id[SETTINGS_EVENT_IMSI_CHANGED] =
ril_sim_settings_add_imsi_changed_handler(settings,
@@ -1271,6 +1343,8 @@ void ril_data_unref(struct ril_data *self)
gboolean ril_data_allowed(struct ril_data *self)
{
return G_LIKELY(self) &&
(self->priv->restricted_state &
RIL_RESTRICTED_STATE_PS_ALL) == 0 &&
(self->priv->flags &
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON)) ==
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
@@ -1285,9 +1359,7 @@ static void ril_data_deactivate_all(struct ril_data *self)
struct ril_data_call *call = l->data;
if (call->status == PDP_FAIL_NONE) {
DBG_(self, "deactivating call %u", call->cid);
ril_data_request_queue(
ril_data_call_deact_new(self,
call->cid, NULL, NULL));
ril_data_call_deact_cid(self, call->cid);
}
}
}
@@ -1355,9 +1427,7 @@ static void ril_data_disallow(struct ril_data *self)
ril_data_power_update(self);
}
if (ril_data_allowed(self) != was_allowed) {
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
}
ril_data_check_allowed(self, was_allowed);
}
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
@@ -1456,12 +1526,39 @@ struct ril_data_request *ril_data_call_deactivate(struct ril_data *self,
return req;
}
gboolean ril_data_call_grab(struct ril_data *self, int cid, void *cookie)
{
if (self && cookie && ril_data_call_find(self->data_calls, cid)) {
struct ril_data_priv *priv = self->priv;
gpointer key = GINT_TO_POINTER(cid);
void *prev = g_hash_table_lookup(priv->grab, key);
if (!prev) {
g_hash_table_insert(priv->grab, key, cookie);
return TRUE;
} else {
return (prev == cookie);
}
}
return FALSE;
}
void ril_data_call_release(struct ril_data *self, int cid, void *cookie)
{
if (self && cookie) {
struct ril_data_priv *priv = self->priv;
g_hash_table_remove(priv->grab, GUINT_TO_POINTER(cid));
}
}
static void ril_data_init(struct ril_data *self)
{
struct ril_data_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_DATA_TYPE, struct ril_data_priv);
self->priv = priv;
priv->grab = g_hash_table_new(g_direct_hash, g_direct_equal);
}
static void ril_data_dispose(GObject *object)
@@ -1475,7 +1572,7 @@ static void ril_data_dispose(GObject *object)
ril_sim_settings_remove_handlers(settings, priv->settings_event_id,
G_N_ELEMENTS(priv->settings_event_id));
grilio_channel_remove_handlers(priv->io, &priv->io_event_id, 1);
grilio_channel_remove_all_handlers(priv->io, priv->io_event_id);
grilio_queue_cancel_all(priv->q, FALSE);
priv->query_id = 0;
@@ -1489,6 +1586,7 @@ static void ril_data_dispose(GObject *object)
dm->data_list = g_slist_remove(dm->data_list, self);
ril_data_manager_check_data(dm);
g_hash_table_destroy(priv->grab);
G_OBJECT_CLASS(ril_data_parent_class)->dispose(object);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,8 +17,11 @@
#define RIL_DATA_H
#include "ril_types.h"
#include <ofono/gprs-context.h>
#include <glib-object.h>
enum ril_data_call_active {
RIL_DATA_CALL_INACTIVE = 0,
RIL_DATA_CALL_LINK_DOWN = 1,
@@ -120,6 +123,9 @@ struct ril_data_request *ril_data_call_deactivate(struct ril_data *data,
void ril_data_request_detach(struct ril_data_request *req);
void ril_data_request_cancel(struct ril_data_request *req);
gboolean ril_data_call_grab(struct ril_data *data, int cid, void *cookie);
void ril_data_call_release(struct ril_data *data, int cid, void *cookie);
void ril_data_call_free(struct ril_data_call *call);
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,8 @@
#include "ril_types.h"
#include <glib-object.h>
struct ril_ecclist_priv;
struct ril_ecclist {

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -88,6 +88,7 @@ static int ril_gprs_context_address_family(const char *addr)
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
{
if (gcd->active_call) {
ril_data_call_release(gcd->data, gcd->active_call->cid, gcd);
ril_data_call_free(gcd->active_call);
gcd->active_call = NULL;
}
@@ -111,6 +112,7 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
}
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
ril_data_call_grab(gcd->data, call->cid, gcd);
} else {
ril_gprs_context_free_active_call(gcd);
}
@@ -378,7 +380,7 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
ril_gprs_context_set_dns_servers(gc, call);
}
ofono_gprs_context_signal_change(gc, call->cid);
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
ril_data_call_free(prev_call);
}
@@ -396,6 +398,8 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
if (ril_status != RIL_E_SUCCESS) {
ofono_error("GPRS context: Reply failure: %s",
ril_error_to_string(ril_status));
} else if (!call) {
ofono_error("Unexpected data call failure");
} else if (call->status != PDP_FAIL_NONE) {
ofono_error("Unexpected data call status %d", call->status);
error.type = OFONO_ERROR_TYPE_CMS;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -285,8 +285,10 @@ 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));
if (md->modem.config.enable_cbs) {
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
}
}
static void ril_modem_post_online(struct ofono_modem *modem)
@@ -452,8 +454,10 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
ofono_modem_set_data(ofono, md);
err = ofono_modem_register(ofono);
if (!err) {
ril_radio_power_cycle(modem->radio);
GASSERT(io->connected);
if (config->radio_power_cycle) {
ril_radio_power_cycle(modem->radio);
}
/*
* ofono_modem_reset sets Powered to TRUE without
@@ -466,11 +470,12 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
/*
* With some RIL implementations, querying available
* band modes causes some magic Android properties to
* appear. Otherwise this request is pretty harmless
* and useless.
* appear.
*/
grilio_queue_send_request(md->q, NULL,
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
if (config->query_available_band_mode) {
grilio_queue_send_request(md->q, NULL,
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
}
ril_modem_update_radio_settings(md);
return modem;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -61,6 +61,8 @@ struct ril_netreg_cbd {
#define ril_netreg_cbd_free g_free
#define DBG_(nd,fmt,args...) DBG("%s" fmt, (nd)->log_prefix, ##args)
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
{
return ofono ? ofono_netreg_get_data(ofono) : NULL;
@@ -109,7 +111,7 @@ static gboolean ril_netreg_status_notify_cb(gpointer user_data)
struct ril_netreg *nd = user_data;
const struct ril_registration_state *reg = &nd->network->voice;
DBG("%s", nd->log_prefix);
DBG_(nd, "");
GASSERT(nd->notify_id);
nd->notify_id = 0;
ofono_netreg_status_notify(nd->netreg,
@@ -124,9 +126,9 @@ static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
/* Coalesce multiple notifications into one */
if (nd->notify_id) {
DBG("%snotification aready queued", nd->log_prefix);
DBG_(nd, "notification aready queued");
} else {
DBG("%squeuing notification", nd->log_prefix);
DBG_(nd, "queuing notification");
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
}
}
@@ -138,7 +140,7 @@ static void ril_netreg_registration_status(struct ofono_netreg *netreg,
const struct ril_registration_state *reg = &nd->network->voice;
struct ofono_error error;
DBG("%s", nd->log_prefix);
DBG_(nd, "");
cb(ril_error_ok(&error),
ril_netreg_check_status(nd, reg->status),
reg->lac, reg->ci, reg->access_tech, data);
@@ -151,7 +153,7 @@ static gboolean ril_netreg_current_operator_cb(void *user_data)
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
struct ofono_error error;
DBG("%s", nd->log_prefix);
DBG_(nd, "");
GASSERT(nd->current_operator_id);
nd->current_operator_id = 0;
@@ -322,6 +324,7 @@ static int ril_netreg_get_signal_strength(const void *data, guint len)
{
GRilIoParser rilp;
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
int rsrp = 0;
grilio_parser_init(&rilp, data, len);
@@ -341,23 +344,41 @@ static int ril_netreg_get_signal_strength(const void *data, guint len)
/* LTE_SignalStrength */
grilio_parser_get_int32(&rilp, &lte_signal);
grilio_parser_get_int32(&rilp, NULL); /* rsrp */
grilio_parser_get_int32(&rilp, NULL); /* rsrq */
grilio_parser_get_int32(&rilp, NULL); /* rssnr */
grilio_parser_get_int32(&rilp, NULL); /* cqi */
grilio_parser_get_int32(&rilp, &rsrp);
/* The rest is ignored */
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal, cdma_dbm,
evdo_dbm, lte_signal);
if (rsrp == INT_MAX) {
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal,
cdma_dbm, evdo_dbm, lte_signal);
} else {
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d", gw_signal,
cdma_dbm, evdo_dbm, lte_signal, rsrp);
}
/* Return the first valid one */
if (gw_signal != 99 && gw_signal != -1) {
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
* RSRP value. If we've got zero, don't report it just yet. */
if (gw_signal >= 1 && gw_signal <= 31) {
/* Valid values are (0-31, 99) as defined in TS 27.007 */
return (gw_signal * 100) / 31;
}
if (lte_signal != 99 && lte_signal != -1) {
/* Valid values are (0-31, 99) as defined in TS 27.007 */
if (lte_signal >= 0 && lte_signal <= 31) {
return (lte_signal * 100) / 31;
}
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
return 140 - rsrp;
}
/* If we've got zero strength and no valid RSRP, then so be it */
if (gw_signal == 0) {
return 0;
}
/* In case of dbm, return the value directly */
if (cdma_dbm != -1) {
return MIN(cdma_dbm, 100);
@@ -378,7 +399,7 @@ static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
strength = ril_netreg_get_signal_strength(data, len);
DBG("%d", strength);
DBG_(nd, "%d", strength);
ofono_netreg_strength_notify(nd->netreg, strength);
}
@@ -417,9 +438,8 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
{
struct ril_netreg *nd = user_data;
GRilIoParser rilp;
struct ofono_network_time time;
int year, mon, mday, hour, min, sec, dst, tzi;
char tzs, tz[4];
int year, mon, mday, hour, min, sec, tzi, dst = 0;
char tzs;
gchar *nitz;
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
@@ -427,21 +447,33 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
grilio_parser_init(&rilp, data, len);
nitz = grilio_parser_get_utf8(&rilp);
DBG("%s", nitz);
sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u", &year, &mon, &mday,
&hour, &min, &sec, &tzs, &tzi, &dst);
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
DBG_(nd, "%s", nitz);
time.utcoff = atoi(tz) * 15 * 60;
time.dst = dst;
time.sec = sec;
time.min = min;
time.hour = hour;
time.mday = mday;
time.mon = mon;
time.year = 2000 + year;
/*
* Format: yy/mm/dd,hh:mm:ss(+/-)tz[,ds]
* The ds part is considered optional, initialized to zero.
*/
if (nitz && sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u",
&year, &mon, &mday, &hour, &min, &sec, &tzs, &tzi,
&dst) >= 8 && (tzs == '+' || tzs == '-')) {
struct ofono_network_time time;
char tz[4];
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
time.utcoff = atoi(tz) * 15 * 60;
time.dst = dst;
time.sec = sec;
time.min = min;
time.hour = hour;
time.mday = mday;
time.mon = mon;
time.year = 2000 + year;
ofono_netreg_time_notify(nd->netreg, &time);
} else {
ofono_warn("Failed to parse NITZ string \"%s\"", nitz);
}
ofono_netreg_time_notify(nd->netreg, &time);
g_free(nitz);
}
@@ -482,10 +514,11 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
{
struct ril_modem *modem = data;
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
guint slot = ril_modem_slot(modem);
DBG("[%u] %p", slot, netreg);
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
nd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
DBG_(nd, "%p", netreg);
nd->io = grilio_channel_ref(ril_modem_io(modem));
nd->q = grilio_queue_new(nd->io);
nd->network = ril_network_ref(modem->network);
@@ -499,9 +532,8 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
static void ril_netreg_remove(struct ofono_netreg *netreg)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
unsigned int i;
DBG("%p", netreg);
DBG_(nd, "%p", netreg);
grilio_queue_cancel_all(nd->q, FALSE);
ofono_netreg_set_data(netreg, NULL);
@@ -517,14 +549,10 @@ static void ril_netreg_remove(struct ofono_netreg *netreg)
g_source_remove(nd->current_operator_id);
}
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
}
ril_network_remove_all_handlers(nd->network, nd->network_event_id);
ril_network_unref(nd->network);
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
G_N_ELEMENTS(nd->ril_event_id));
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
grilio_channel_unref(nd->io);
grilio_queue_unref(nd->q);
g_free(nd->log_prefix);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -47,6 +47,12 @@ enum ril_network_radio_event {
RADIO_EVENT_COUNT
};
enum ril_network_sim_events {
SIM_EVENT_STATUS_CHANGED,
SIM_EVENT_IO_ACTIVE_CHANGED,
SIM_EVENT_COUNT
};
enum ril_network_unsol_event {
UNSOL_EVENT_NETWORK_STATE,
UNSOL_EVENT_RADIO_CAPABILITY,
@@ -57,8 +63,10 @@ struct ril_network_priv {
GRilIoChannel *io;
GRilIoQueue *q;
struct ril_radio *radio;
struct ril_sim_card *sim_card;
struct ril_sim_card *simcard;
int rat;
int lte_network_mode;
int network_mode_timeout;
char *log_prefix;
guint operator_poll_id;
guint voice_poll_id;
@@ -68,8 +76,8 @@ struct ril_network_priv {
gulong set_rat_id;
gulong unsol_event_id[UNSOL_EVENT_COUNT];
gulong settings_event_id;
gulong sim_status_event_id;
gulong radio_event_id[RADIO_EVENT_COUNT];
gulong simcard_event_id[SIM_EVENT_COUNT];
struct ofono_network_operator operator;
gboolean assert_rat;
};
@@ -111,7 +119,8 @@ G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_UMTS > OFONO_RADIO_ACCESS_MODE_GSM);
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_LTE > OFONO_RADIO_ACCESS_MODE_UMTS);
static void ril_network_query_pref_mode(struct ril_network *self);
static void ril_network_set_pref_mode(struct ril_network *self, int rat);
static void ril_network_check_pref_mode(struct ril_network *self,
gboolean immediate);
static void ril_network_emit(struct ril_network *self,
enum ril_network_signal sig)
@@ -208,11 +217,11 @@ static gboolean ril_network_parse_response(struct ril_network *self,
reg->max_calls = 2;
}
if (!ril_parse_int(slac, 16, &reg->lac)) {
if (!gutil_parse_int(slac, 16, &reg->lac)) {
reg->lac = -1;
}
if (!ril_parse_int(sci, 16, &reg->ci)) {
if (!gutil_parse_int(sci, 16, &reg->ci)) {
reg->ci = -1;
}
@@ -400,12 +409,25 @@ static void ril_network_poll_state(struct ril_network *self)
priv->operator_poll_id = ril_network_poll_and_retry(self,
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
ril_network_poll_operator_cb);
priv->voice_poll_id = ril_network_poll_and_retry(self,
priv->voice_poll_id, RIL_REQUEST_VOICE_REGISTRATION_STATE,
ril_network_poll_voice_state_cb);
priv->data_poll_id = ril_network_poll_and_retry(self,
priv->data_poll_id, RIL_REQUEST_DATA_REGISTRATION_STATE,
ril_network_poll_data_state_cb);
ril_network_query_registration_state(self);
}
void ril_network_query_registration_state(struct ril_network *self)
{
if (self) {
struct ril_network_priv *priv = self->priv;
DBG_(self, "");
priv->voice_poll_id = ril_network_poll_and_retry(self,
priv->voice_poll_id,
RIL_REQUEST_VOICE_REGISTRATION_STATE,
ril_network_poll_voice_state_cb);
priv->data_poll_id = ril_network_poll_and_retry(self,
priv->data_poll_id,
RIL_REQUEST_DATA_REGISTRATION_STATE,
ril_network_poll_data_state_cb);
}
}
static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
@@ -435,7 +457,7 @@ static int ril_network_mode_to_rat(struct ril_network *self,
case OFONO_RADIO_ACCESS_MODE_ANY:
case OFONO_RADIO_ACCESS_MODE_LTE:
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
return PREF_NET_TYPE_LTE_GSM_WCDMA;
return self->priv->lte_network_mode;
}
/* no break */
default:
@@ -484,37 +506,28 @@ static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
return priv->radio->online && ril_sim_card_ready(priv->sim_card);
/*
* With some modems an attempt to set rat significantly slows
* down SIM I/O, let's avoid that.
*/
return priv->radio->online && ril_sim_card_ready(priv->simcard) &&
!priv->simcard->sim_io_active &&
!priv->timer[TIMER_SET_RAT_HOLDOFF] ;
}
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
const int rat = ril_network_pref_mode_expected(self);
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
GASSERT(priv->timer[TIMER_SET_RAT_HOLDOFF]);
priv->timer[TIMER_SET_RAT_HOLDOFF] = 0;
/*
* Don't retry the request if modem is offline or SIM card isn't
* ready, to avoid spamming system log with error messages. Radio
* and SIM card state change callbacks will schedule a new check
* when it's appropriate.
*/
if (priv->rat != rat || priv->assert_rat) {
if (ril_network_can_set_pref_mode(self)) {
ril_network_set_pref_mode(self, rat);
} else {
DBG_(self, "giving up");
}
}
ril_network_check_pref_mode(self, FALSE);
return G_SOURCE_REMOVE;
}
static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
static void ril_network_set_rat_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
@@ -529,33 +542,53 @@ static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
ril_network_query_pref_mode(self);
}
static void ril_network_set_rat(struct ril_network *self, int rat)
{
struct ril_network_priv *priv = self->priv;
if (!priv->set_rat_id && priv->radio->online &&
ril_sim_card_ready(priv->simcard) &&
/*
* With some modems an attempt to set rat significantly
* slows down SIM I/O, let's avoid that.
*/
!priv->simcard->sim_io_active &&
!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
GRilIoRequest *req = grilio_request_sized_new(8);
DBG_(self, "setting rat mode %d", rat);
grilio_request_append_int32(req, 1); /* count */
grilio_request_append_int32(req, rat);
grilio_request_set_timeout(req, priv->network_mode_timeout);
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
ril_network_set_rat_cb, NULL, self);
grilio_request_unref(req);
/* We have submitted the request, clear the assertion flag */
priv->assert_rat = FALSE;
/* And don't do it too often */
priv->timer[TIMER_SET_RAT_HOLDOFF] =
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
ril_network_set_rat_holdoff_cb, self);
} else {
DBG_(self, "need to set rat mode %d", rat);
}
}
static void ril_network_set_pref_mode(struct ril_network *self, int rat)
{
struct ril_network_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(8);
DBG_(self, "setting rat mode %d", rat);
grilio_request_append_int32(req, 1); /* Number of params */
grilio_request_append_int32(req, rat);
grilio_queue_cancel_request(priv->q, priv->set_rat_id, FALSE);
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
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] =
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
ril_network_set_rat_holdoff_cb, self);
if (priv->rat != rat || priv->assert_rat) {
ril_network_set_rat(self, rat);
}
}
static void ril_network_check_pref_mode(struct ril_network *self,
gboolean force)
gboolean immediate)
{
struct ril_network_priv *priv = self->priv;
const int rat = ril_network_pref_mode_expected(self);
@@ -567,10 +600,14 @@ static void ril_network_check_pref_mode(struct ril_network *self,
* ril_network_pref_mode_changed_cb and is meant
* to force radio tech check right now.
*/
force = TRUE;
immediate = TRUE;
}
if (priv->rat == rat || force) {
if (priv->rat != rat) {
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
}
if (immediate) {
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
}
@@ -813,8 +850,9 @@ static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card,
struct ril_sim_settings *settings)
struct ril_sim_card *simcard,
struct ril_sim_settings *settings,
const struct ril_slot_config *config)
{
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
struct ril_network_priv *priv = self->priv;
@@ -823,10 +861,16 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
priv->io = grilio_channel_ref(io);
priv->q = grilio_queue_new(priv->io);
priv->radio = ril_radio_ref(radio);
priv->sim_card = ril_sim_card_ref(sim_card);
priv->simcard = ril_sim_card_ref(simcard);
priv->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
DBG_(self, "");
/* Copy relevant config values */
priv->lte_network_mode = config->lte_network_mode;
priv->network_mode_timeout = config->network_mode_timeout;
/* Register listeners */
priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
grilio_channel_add_unsol_event_handler(priv->io,
ril_network_state_changed_cb,
@@ -841,12 +885,15 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
ril_radio_add_online_changed_handler(priv->radio,
ril_network_radio_online_cb, self);
priv->simcard_event_id[SIM_EVENT_STATUS_CHANGED] =
ril_sim_card_add_status_changed_handler(priv->simcard,
ril_network_sim_status_changed_cb, self);
priv->simcard_event_id[SIM_EVENT_IO_ACTIVE_CHANGED] =
ril_sim_card_add_sim_io_active_changed_handler(priv->simcard,
ril_network_sim_status_changed_cb, self);
priv->settings_event_id =
ril_sim_settings_add_pref_mode_changed_handler(settings,
ril_network_pref_mode_changed_cb, self);
priv->sim_status_event_id =
ril_sim_card_add_status_changed_handler(priv->sim_card,
ril_network_sim_status_changed_cb, self);
/*
* Query the initial state. Querying network state before the radio
@@ -903,16 +950,13 @@ static void ril_network_finalize(GObject *object)
}
grilio_queue_cancel_all(priv->q, FALSE);
grilio_channel_remove_handlers(priv->io, priv->unsol_event_id,
G_N_ELEMENTS(priv->unsol_event_id));
grilio_channel_remove_all_handlers(priv->io, priv->unsol_event_id);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
ril_radio_unref(priv->radio);
ril_sim_card_remove_handler(priv->sim_card,
priv->sim_status_event_id);
ril_sim_card_unref(priv->sim_card);
ril_sim_card_remove_all_handlers(priv->simcard, priv->simcard_event_id);
ril_sim_card_unref(priv->simcard);
ril_sim_settings_remove_handler(self->settings,
priv->settings_event_id);
ril_sim_settings_unref(self->settings);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,8 @@
#include "ril_types.h"
#include <glib-object.h>
struct ofono_network_operator;
struct ril_registration_state {
@@ -46,7 +48,8 @@ typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card,
struct ril_sim_settings *settings);
struct ril_sim_settings *settings,
const struct ril_slot_config *ril_slot_config);
struct ril_network *ril_network_ref(struct ril_network *net);
void ril_network_unref(struct ril_network *net);
@@ -54,6 +57,7 @@ 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);
void ril_network_query_registration_state(struct ril_network *net);
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
@@ -67,6 +71,9 @@ gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
void ril_network_remove_handler(struct ril_network *net, gulong id);
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
#define ril_network_remove_all_handlers(net, ids) \
ril_network_remove_handlers(net, ids, G_N_ELEMENTS(ids))
#endif /* RIL_NETWORK_H */
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -30,8 +30,11 @@
#include <sailfish_manager.h>
#include <sailfish_watch.h>
#include <grilio_transport.h>
#include <gutil_ints.h>
#include <gutil_macros.h>
#include <gutil_misc.h>
#include <mce_display.h>
#include <mce_log.h>
@@ -48,6 +51,7 @@
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include <ofono/storage.h>
#include <ofono/ril-transport.h>
#define OFONO_RADIO_ACCESS_MODE_ALL (OFONO_RADIO_ACCESS_MODE_GSM |\
OFONO_RADIO_ACCESS_MODE_UMTS |\
@@ -63,7 +67,10 @@
#define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2"
#define RILMODEM_DEFAULT_SUB "SUB1"
#define RILMODEM_DEFAULT_TECHS OFONO_RADIO_ACCESS_MODE_ALL
#define RILMODEM_DEFAULT_LTE_MODE PREF_NET_TYPE_LTE_GSM_WCDMA
#define RILMODEM_DEFAULT_NETWORK_MODE_TIMEOUT (20*1000) /* ms */
#define RILMODEM_DEFAULT_ENABLE_VOICECALL TRUE
#define RILMODEM_DEFAULT_ENABLE_CBS TRUE
#define RILMODEM_DEFAULT_SLOT 0xffffffff
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
@@ -74,7 +81,15 @@
#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 RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE TRUE /* Qualcomm */
#define RILMODEM_DEFAULT_LEGACY_IMEI_QUERY FALSE
#define RILMODEM_DEFAULT_RADIO_POWER_CYCLE TRUE
#define RILMODEM_DEFAULT_CONFIRM_RADIO_POWER_ON TRUE
/* RIL socket transport name and parameters */
#define RIL_TRANSPORT_SOCKET "socket"
#define RIL_TRANSPORT_SOCKET_PATH "path"
#define RIL_TRANSPORT_SOCKET_SUB "sub"
/*
* The convention is that the keys which can only appear in the [Settings]
@@ -82,37 +97,43 @@
* modem section (OR in the [Settings] if they apply to all modems) start
* with lower case.
*/
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
#define RILCONF_SETTINGS_IDENTITY "Identity"
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
#define RILCONF_SETTINGS_IDENTITY "Identity"
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
#define RILCONF_DEV_PREFIX "ril_"
#define RILCONF_PATH_PREFIX "/" RILCONF_DEV_PREFIX
#define RILCONF_NAME "name"
#define RILCONF_SOCKET "socket"
#define RILCONF_SLOT "slot"
#define RILCONF_SUB "sub"
#define RILCONF_START_TIMEOUT "startTimeout"
#define RILCONF_TIMEOUT "timeout"
#define RILCONF_4G "enable4G" /* Deprecated */
#define RILCONF_ENABLE_VOICECALL "enableVoicecall"
#define RILCONF_TECHNOLOGIES "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_VENDOR_DRIVER "vendorDriver"
#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 RILCONF_DEFAULT_LEGACY_IMEI_QUERY "legacyImeiQuery"
#define RILCONF_MODEM_PREFIX "ril_"
#define RILCONF_PATH_PREFIX "/" RILCONF_MODEM_PREFIX
#define RILCONF_TRANSPORT "transport"
#define RILCONF_NAME "name"
#define RILCONF_SOCKET "socket"
#define RILCONF_SLOT "slot"
#define RILCONF_SUB "sub"
#define RILCONF_START_TIMEOUT "startTimeout"
#define RILCONF_TIMEOUT "timeout"
#define RILCONF_4G "enable4G" /* Deprecated */
#define RILCONF_ENABLE_VOICECALL "enableVoicecall"
#define RILCONF_ENABLE_CBS "enableCellBroadcast"
#define RILCONF_TECHNOLOGIES "technologies"
#define RILCONF_LTE_MODE "lteNetworkMode"
#define RILCONF_NETWORK_MODE_TIMEOUT "networkModeTimeout"
#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_VENDOR_DRIVER "vendorDriver"
#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 RILCONF_LEGACY_IMEI_QUERY "legacyImeiQuery"
#define RILCONF_RADIO_POWER_CYCLE "radioPowerCycle"
#define RILCONF_CONFIRM_RADIO_POWER_ON "confirmRadioPowerOn"
/* Modem error ids */
#define RIL_ERROR_ID_RILD_RESTART "rild-restart"
#define RIL_ERROR_ID_CAPS_SWITCH_ABORTED "ril-caps-switch-aborted"
#define RIL_ERROR_ID_RILD_RESTART "rild-restart"
#define RIL_ERROR_ID_CAPS_SWITCH_ABORTED "ril-caps-switch-aborted"
enum ril_plugin_io_events {
IO_EVENT_CONNECTED,
@@ -171,8 +192,8 @@ typedef struct sailfish_slot_impl {
char *imei;
char *imeisv;
char *name;
char *sockpath;
char *sub;
char *transport_name;
GHashTable *transport_params;
char *ecclist_file;
int timeout; /* RIL timeout, in milliseconds */
int index;
@@ -957,18 +978,16 @@ static void ril_plugin_slot_connected(ril_slot *slot)
*/
ril_plugin_start_imei_query(slot, TRUE, -1);
GASSERT(!slot->vendor_hook);
slot->vendor_hook = ril_vendor_create_hook(slot->vendor, slot->io,
slot->path, &slot->config);
GASSERT(!slot->radio);
slot->radio = ril_radio_new(slot->io);
GASSERT(!slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED]);
slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(slot->io,
if (slot->config.confirm_radio_power_on) {
slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(slot->io,
ril_plugin_radio_state_changed,
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, slot);
}
GASSERT(!slot->sim_card);
slot->sim_card = ril_sim_card_new(slot->io, slot->config.slot,
@@ -982,7 +1001,12 @@ static void ril_plugin_slot_connected(ril_slot *slot)
GASSERT(!slot->network);
slot->network = ril_network_new(slot->path, slot->io, log_prefix,
slot->radio, slot->sim_card, slot->sim_settings);
slot->radio, slot->sim_card, slot->sim_settings,
&slot->config);
GASSERT(!slot->vendor_hook);
slot->vendor_hook = ril_vendor_create_hook(slot->vendor, slot->io,
slot->path, &slot->config, slot->network);
GASSERT(!slot->data);
slot->data = ril_data_new(plugin->data_manager, log_prefix,
@@ -1040,8 +1064,8 @@ static void ril_plugin_slot_connected_cb(GRilIoChannel *io, void *user_data)
static void ril_plugin_init_io(ril_slot *slot)
{
if (!slot->io) {
DBG("%s %s", slot->sockpath, slot->sub);
slot->io = grilio_channel_new_socket(slot->sockpath, slot->sub);
slot->io = grilio_channel_new(ofono_ril_transport_connect
(slot->transport_name, slot->transport_params));
if (slot->io) {
ril_debug_trace_update(slot);
ril_debug_dump_update(slot);
@@ -1097,7 +1121,7 @@ static void ril_plugin_retry_init_io(ril_slot *slot)
g_source_remove(slot->retry_id);
}
DBG("%s %s", slot->sockpath, slot->sub);
DBG("%s", slot->path);
slot->retry_id = g_timeout_add_seconds(RIL_RETRY_SECS,
ril_plugin_retry_init_io_cb, slot);
}
@@ -1125,7 +1149,7 @@ static void ril_slot_free(ril_slot *slot)
{
ril_plugin* plugin = slot->plugin;
DBG("%s", slot->sockpath);
DBG("%s", slot->path);
ril_plugin_shutdown_slot(slot, TRUE);
plugin->slots = g_slist_remove(plugin->slots, slot);
mce_display_remove_all_handlers(slot->display, slot->display_event_id);
@@ -1139,8 +1163,8 @@ static void ril_slot_free(ril_slot *slot)
g_free(slot->imei);
g_free(slot->imeisv);
g_free(slot->name);
g_free(slot->sockpath);
g_free(slot->sub);
g_free(slot->transport_name);
g_hash_table_destroy(slot->transport_params);
g_free(slot->ecclist_file);
g_free(slot);
}
@@ -1150,7 +1174,7 @@ static gboolean ril_plugin_slot_start_timeout(gpointer user_data)
ril_slot *slot = user_data;
ril_plugin* plugin = slot->plugin;
DBG("%s", slot->sockpath);
DBG("%s", slot->path);
plugin->slots = g_slist_remove(plugin->slots, slot);
slot->start_timeout_id = 0;
ril_slot_free(slot);
@@ -1158,18 +1182,28 @@ static gboolean ril_plugin_slot_start_timeout(gpointer user_data)
return G_SOURCE_REMOVE;
}
static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *path,
char *name, guint slot_index)
static ril_slot *ril_plugin_slot_new_take(char *transport,
GHashTable *transport_params, char *dbus_path,
char *name, guint slot_index)
{
ril_slot *slot = g_new0(ril_slot, 1);
struct ril_slot_config *config = &slot->config;
slot->sockpath = sockpath;
slot->path = path;
slot->transport_name = transport;
slot->transport_params = transport_params;
slot->path = dbus_path;
slot->name = name;
slot->config.slot = slot_index;
slot->config.techs = RILMODEM_DEFAULT_TECHS;
slot->config.empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
slot->config.enable_voicecall = RILMODEM_DEFAULT_ENABLE_VOICECALL;
config->slot = slot_index;
config->techs = RILMODEM_DEFAULT_TECHS;
config->lte_network_mode = RILMODEM_DEFAULT_LTE_MODE;
config->empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
config->radio_power_cycle = RILMODEM_DEFAULT_RADIO_POWER_CYCLE;
config->confirm_radio_power_on =
RILMODEM_DEFAULT_CONFIRM_RADIO_POWER_ON;
config->enable_voicecall = RILMODEM_DEFAULT_ENABLE_VOICECALL;
config->enable_cbs = RILMODEM_DEFAULT_ENABLE_CBS;
config->query_available_band_mode =
RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE;
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
slot->legacy_imei_query = RILMODEM_DEFAULT_LEGACY_IMEI_QUERY;
@@ -1190,7 +1224,7 @@ static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *path,
mce_display_add_state_changed_handler(slot->display,
ril_plugin_display_cb, slot);
slot->watch = sailfish_watch_new(path);
slot->watch = sailfish_watch_new(dbus_path);
slot->watch_event_id[WATCH_EVENT_MODEM] =
sailfish_watch_add_modem_changed_handler(slot->watch,
ril_plugin_slot_modem_changed, slot);
@@ -1205,20 +1239,38 @@ static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
/* Let the vendor extension to adjust (some) defaults */
memset(&defaults, 0, sizeof(defaults));
defaults.empty_pin_query = config->empty_pin_query;
defaults.legacy_imei_query = slot->legacy_imei_query;
defaults.enable_cbs = config->enable_cbs;
defaults.empty_pin_query = config->empty_pin_query;
defaults.query_available_band_mode =
config->query_available_band_mode;
ril_vendor_get_defaults(slot->vendor, &defaults);
config->empty_pin_query = defaults.empty_pin_query;
slot->legacy_imei_query = defaults.legacy_imei_query;
config->enable_cbs = defaults.enable_cbs;
config->empty_pin_query = defaults.empty_pin_query;
config->query_available_band_mode =
defaults.query_available_band_mode;
}
}
static ril_slot *ril_plugin_slot_new(const char *sockpath, const char *path,
static ril_slot *ril_plugin_slot_new_socket(const char *sockpath,
const char *sub, const char *dbus_path,
const char *name, guint slot_index)
{
return ril_plugin_slot_new_take(g_strdup(sockpath), g_strdup(path),
g_strdup(name), slot_index);
/* RIL socket configuration */
GHashTable *params = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
g_hash_table_insert(params, g_strdup(RIL_TRANSPORT_SOCKET_PATH),
g_strdup(sockpath));
if (sub) {
g_hash_table_insert(params, g_strdup(RIL_TRANSPORT_SOCKET_SUB),
g_strdup(sub));
}
return ril_plugin_slot_new_take(g_strdup(RIL_TRANSPORT_SOCKET), params,
g_strdup(dbus_path), g_strdup(name), slot_index);
}
static GSList *ril_plugin_create_default_config()
@@ -1227,24 +1279,75 @@ static GSList *ril_plugin_create_default_config()
if (g_file_test(RILMODEM_DEFAULT_SOCK2, G_FILE_TEST_EXISTS)) {
DBG("Falling back to default dual SIM config");
list = g_slist_append(list,
ril_plugin_slot_new(RILMODEM_DEFAULT_SOCK,
list = g_slist_append(list, ril_plugin_slot_new_socket
(RILMODEM_DEFAULT_SOCK, NULL,
RILCONF_PATH_PREFIX "0", "RIL1", 0));
list = g_slist_append(list,
ril_plugin_slot_new(RILMODEM_DEFAULT_SOCK2,
list = g_slist_append(list, ril_plugin_slot_new_socket
(RILMODEM_DEFAULT_SOCK2, NULL,
RILCONF_PATH_PREFIX "1", "RIL2", 1));
} else {
ril_slot *slot = ril_plugin_slot_new(RILMODEM_DEFAULT_SOCK,
RILCONF_PATH_PREFIX "0", "RIL", 0);
DBG("Falling back to default single SIM config");
slot->sub = g_strdup(RILMODEM_DEFAULT_SUB);
list = g_slist_append(list, slot);
list = g_slist_append(list, ril_plugin_slot_new_socket
(RILMODEM_DEFAULT_SOCK, RILMODEM_DEFAULT_SUB,
RILCONF_PATH_PREFIX "0", "RIL", 0));
}
return list;
}
/*
* Parse the spec according to the following grammar:
*
* spec: transport | transport ':' parameters
* params: param | params ';' param
* param: name '=' value
* transport: STRING
* name: STRING
* value: STRING
*
* For example, a RIL socket spec may look like this:
*
* socket:path=/dev/socket/rild;sub=SUB1
*/
static char *ril_plugin_parse_transport_spec(const char *spec,
GHashTable *params)
{
char *transport = NULL;
char *sep = strchr(spec, ':');
if (sep) {
transport = g_strstrip(g_strndup(spec, sep - spec));
if (transport[0]) {
char **list = g_strsplit(sep + 1, ";", 0);
char **ptr;
for (ptr = list; *ptr; ptr++) {
const char *p = *ptr;
sep = strchr(p, '=');
if (sep) {
char *name = g_strndup(p, sep - p);
char* value = g_strdup(sep + 1);
g_hash_table_insert(params,
g_strstrip(name),
g_strstrip(value));
}
}
g_strfreev(list);
return transport;
}
} else {
/* Use default transport attributes */
transport = g_strstrip(g_strdup(spec));
if (transport[0]) {
return transport;
}
}
g_free(transport);
return NULL;
}
static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
const char *group)
{
@@ -1253,29 +1356,57 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
int ival;
char *sval;
char **strv;
char *sock = g_key_file_get_string(file, group, RILCONF_SOCKET, NULL);
GHashTable *transport_params = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, g_free);
char *transport = NULL;
char *transport_spec = g_key_file_get_string(file, group,
RILCONF_TRANSPORT, NULL);
if (!sock) {
ofono_warn("no socket path for %s", group);
if (transport_spec) {
transport = ril_plugin_parse_transport_spec(transport_spec,
transport_params);
if (transport) {
DBG("%s: %s:%s", group, transport,
strchr(transport_spec, ':') + 1);
}
g_free(transport_spec);
} else {
/* Fall back to socket transport */
char *sockpath = g_key_file_get_string(file, group,
RILCONF_SOCKET, NULL);
if (sockpath) {
char *sub = g_key_file_get_string(file, group,
RILCONF_SUB, NULL);
transport = g_strdup(RIL_TRANSPORT_SOCKET);
g_hash_table_insert(transport_params,
g_strdup(RIL_TRANSPORT_SOCKET_PATH),
sockpath);
if (sub && strlen(sub) == RIL_SUB_SIZE) {
DBG("%s: %s:%s", group, sockpath, sub);
g_hash_table_insert(transport_params,
g_strdup(RIL_TRANSPORT_SOCKET_SUB),
sub);
} else {
DBG("%s: %s", group, sockpath);
g_free(sub);
}
}
}
if (!transport) {
ofono_warn("No usable RIL transport defined for %s", group);
g_hash_table_destroy(transport_params);
return NULL;
}
slot = ril_plugin_slot_new_take(sock,
slot = ril_plugin_slot_new_take(transport, transport_params,
g_strconcat("/", group, NULL),
ril_config_get_string(file, group, RILCONF_NAME),
RILMODEM_DEFAULT_SLOT);
config = &slot->config;
/* sub */
sval = ril_config_get_string(file, group, RILCONF_SUB);
if (sval && strlen(sval) == RIL_SUB_SIZE) {
DBG("%s: %s:%s", group, sock, sval);
slot->sub = sval;
} else {
DBG("%s: %s", group, sock);
g_free(sval);
}
/* slot */
if (ril_config_get_integer(file, group, RILCONF_SLOT, &ival) &&
ival >= 0) {
@@ -1322,6 +1453,13 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
config->enable_voicecall ? "yes" : "no");
}
/* enableCellBroadcast */
if (ril_config_get_boolean(file, group, RILCONF_ENABLE_CBS,
&config->enable_cbs)) {
DBG("%s: " RILCONF_ENABLE_CBS " %s", group,
config->enable_cbs ? "yes" : "no");
}
/* technologies */
strv = ril_config_get_strings(file, group, RILCONF_TECHNOLOGIES, ',');
if (strv) {
@@ -1357,6 +1495,20 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
}
g_strfreev(strv);
}
/* lteNetworkMode */
if (ril_config_get_integer(file, group, RILCONF_LTE_MODE,
&config->lte_network_mode)) {
DBG("%s: " RILCONF_LTE_MODE " %d", group,
config->lte_network_mode);
}
/* networkModeTimeout */
if (ril_config_get_integer(file, group, RILCONF_NETWORK_MODE_TIMEOUT,
&config->network_mode_timeout)) {
DBG("%s: " RILCONF_NETWORK_MODE_TIMEOUT " %d", group,
config->network_mode_timeout);
}
/* enable4G (deprecated but still supported) */
ival = config->techs;
@@ -1374,6 +1526,20 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
config->empty_pin_query ? "on" : "off");
}
/* radioPowerCycle */
if (ril_config_get_boolean(file, group, RILCONF_RADIO_POWER_CYCLE,
&config->radio_power_cycle)) {
DBG("%s: " RILCONF_RADIO_POWER_CYCLE " %s", group,
config->radio_power_cycle ? "on" : "off");
}
/* confirmRadioPowerOn */
if (ril_config_get_boolean(file, group, RILCONF_CONFIRM_RADIO_POWER_ON,
&config->confirm_radio_power_on)) {
DBG("%s: " RILCONF_CONFIRM_RADIO_POWER_ON " %s", group,
config->confirm_radio_power_on ? "on" : "off");
}
/* uiccWorkaround */
if (ril_config_get_flag(file, group, RILCONF_UICC_WORKAROUND,
RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND,
@@ -1454,10 +1620,9 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
}
/* legacyImeiQuery */
if (ril_config_get_boolean(file, group,
RILCONF_DEFAULT_LEGACY_IMEI_QUERY,
if (ril_config_get_boolean(file, group, RILCONF_LEGACY_IMEI_QUERY,
&slot->legacy_imei_query)) {
DBG("%s: " RILCONF_DEFAULT_LEGACY_IMEI_QUERY " %s", group,
DBG("%s: " RILCONF_LEGACY_IMEI_QUERY " %s", group,
slot->legacy_imei_query ? "on" : "off");
}
@@ -1535,7 +1700,7 @@ static void ril_plugin_parse_identity(struct ril_plugin_identity *identity,
int n;
/* Try numeric */
if (ril_parse_int(group, 0, &n)) {
if (gutil_parse_int(group, 0, &n)) {
gr = getgrgid(n);
}
}
@@ -1547,7 +1712,7 @@ static void ril_plugin_parse_identity(struct ril_plugin_identity *identity,
int n;
/* Try numeric */
if (ril_parse_int(user, 0, &n)) {
if (gutil_parse_int(user, 0, &n)) {
pw = getpwuid(n);
}
}
@@ -1578,7 +1743,7 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
for (i=0; i<n; i++) {
const char *group = groups[i];
if (g_str_has_prefix(group, RILCONF_DEV_PREFIX)) {
if (g_str_has_prefix(group, RILCONF_MODEM_PREFIX)) {
/* Modem configuration */
ril_slot *slot = ril_plugin_parse_config_group(file,
group);
@@ -1632,22 +1797,16 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
static GSList *ril_plugin_load_config(const char *path,
struct ril_plugin_settings *ps)
{
GError *err = NULL;
GSList *l, *list = NULL;
GKeyFile *file = g_key_file_new();
gboolean empty = FALSE;
if (g_key_file_load_from_file(file, path, 0, &err)) {
DBG("Loading %s", path);
if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP,
ril_config_merge_files(file, path);
if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP,
RILCONF_SETTINGS_EMPTY, &empty) && empty) {
DBG("Empty config");
} else {
list = ril_plugin_parse_config_file(file, ps);
}
DBG("Empty config");
} else {
DBG("conf load error: %s", err->message);
g_error_free(err);
list = ril_plugin_parse_config_file(file, ps);
}
if (!list && !empty) {
@@ -1908,10 +2067,31 @@ static void ril_slot_enabled_changed(struct sailfish_slot_impl *s)
}
}
/**
* RIL socket transport factory
*/
static struct grilio_transport *ril_socket_transport_connect(GHashTable *args)
{
const char* path = g_hash_table_lookup(args, RIL_TRANSPORT_SOCKET_PATH);
const char* sub = g_hash_table_lookup(args, RIL_TRANSPORT_SOCKET_SUB);
GASSERT(path);
if (path) {
DBG("%s %s", path, sub);
return grilio_transport_socket_new_path(path, sub);
}
return NULL;
}
/* Global part (that requires access to global variables) */
static struct sailfish_slot_driver_reg *ril_driver = NULL;
static guint ril_driver_init_id = 0;
static const struct ofono_ril_transport ril_socket_transport = {
.name = RIL_TRANSPORT_SOCKET,
.api_version = OFONO_RIL_TRANSPORT_API_VERSION,
.connect = ril_socket_transport_connect
};
static void ril_debug_trace_notify(struct ofono_debug_desc *desc)
{
@@ -1957,6 +2137,9 @@ static gboolean ril_plugin_start(gpointer user_data)
DBG("");
ril_driver_init_id = 0;
/* Socket transport can be registered right away */
ofono_ril_transport_register(&ril_socket_transport);
/* Register the driver */
ril_driver = sailfish_slot_driver_register(&ril_slot_driver);
return G_SOURCE_REMOVE;
@@ -1992,6 +2175,7 @@ static void ril_plugin_exit(void)
DBG("");
GASSERT(ril_driver);
ofono_ril_transport_unregister(&ril_socket_transport);
ofono_modem_driver_unregister(&ril_modem_driver);
ofono_sim_driver_unregister(&ril_sim_driver);
ofono_sms_driver_unregister(&ril_sms_driver);

View File

@@ -71,14 +71,16 @@ G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
#define RIL_RADIO_TYPE (ril_radio_get_type())
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
return self->online && !priv->power_cycle &&
g_hash_table_size(priv->req_table) > 0;
return (self->online || g_hash_table_size(priv->req_table) > 0) &&
!priv->power_cycle;
}
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
@@ -102,7 +104,7 @@ static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
struct ril_radio *self = RIL_RADIO(user_data);
struct ril_radio_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
DBG_(self, "");
GASSERT(priv->retry_id);
priv->retry_id = 0;
ril_radio_submit_power_request(self,
@@ -116,7 +118,7 @@ static void ril_radio_cancel_retry(struct ril_radio *self)
struct ril_radio_priv *priv = self->priv;
if (priv->retry_id) {
DBG("%sretry cancelled", priv->log_prefix);
DBG_(self, "retry cancelled");
g_source_remove(priv->retry_id);
priv->retry_id = 0;
}
@@ -129,8 +131,8 @@ static void ril_radio_check_state(struct ril_radio *self)
if (!priv->pending_id) {
gboolean should_be_on = ril_radio_power_should_be_on(self);
if (ril_radio_state_on(self->priv->last_known_state) ==
should_be_on) {
if (ril_radio_state_on(priv->last_known_state) ==
should_be_on) {
/* All is good, cancel pending retry if there is one */
ril_radio_cancel_retry(self);
} else if (priv->state_changed_while_request_pending) {
@@ -138,7 +140,7 @@ static void ril_radio_check_state(struct ril_radio *self)
ril_radio_submit_power_request(self, should_be_on);
} else if (!priv->retry_id) {
/* There has been no reaction so far, wait a bit */
DBG("%sretry scheduled", priv->log_prefix);
DBG_(self, "retry scheduled");
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
ril_radio_power_request_retry_cb, self);
}
@@ -147,33 +149,38 @@ static void ril_radio_check_state(struct ril_radio *self)
/* Don't update public state while something is pending */
if (!priv->pending_id && !priv->retry_id &&
self->state != priv->last_known_state) {
DBG("%s%s -> %s", priv->log_prefix,
ril_radio_state_to_string(self->state),
DBG_(self, "%s -> %s", ril_radio_state_to_string(self->state),
ril_radio_state_to_string(priv->last_known_state));
self->state = priv->last_known_state;
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
}
}
static void ril_radio_power_request_done(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
GASSERT(priv->pending_id);
priv->pending_id = 0;
if (priv->next_state_valid) {
ril_radio_submit_power_request(self, priv->next_state);
} else {
ril_radio_check_state(self);
}
}
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_radio *self = RIL_RADIO(user_data);
struct ril_radio_priv *priv = self->priv;
GASSERT(priv->pending_id);
priv->pending_id = 0;
if (ril_status != RIL_E_SUCCESS) {
ofono_error("Power request failed: %s",
ril_error_to_string(ril_status));
}
if (priv->next_state_valid) {
ril_radio_submit_power_request(self, priv->next_state);
} else {
ril_radio_check_state(self);
}
ril_radio_power_request_done(self);
}
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
@@ -214,13 +221,18 @@ static void ril_radio_power_request(struct ril_radio *self, gboolean on,
/* Wait for the pending request to complete */
priv->next_state_valid = TRUE;
priv->next_state = on;
DBG("%s%s (queued)", priv->log_prefix, on_off);
DBG_(self, "%s (queued)", on_off);
} else {
DBG("%s%s (ignored)", priv->log_prefix, on_off);
DBG_(self, "%s (ignored)", on_off);
}
} else {
DBG("%s%s", priv->log_prefix, on_off);
ril_radio_submit_power_request(self, on);
if (ril_radio_state_on(priv->last_known_state) == on) {
DBG_(self, "%s (already)", on_off);
ril_radio_check_state(self);
} else {
DBG_(self, "%s", on_off);
ril_radio_submit_power_request(self, on);
}
}
}
@@ -237,12 +249,12 @@ void ril_radio_power_cycle(struct ril_radio *self)
struct ril_radio_priv *priv = self->priv;
if (ril_radio_state_off(priv->last_known_state)) {
DBG("%spower is already off", priv->log_prefix);
DBG_(self, "power is already off");
GASSERT(!priv->power_cycle);
} else if (priv->power_cycle) {
DBG("%salready in progress", priv->log_prefix);
DBG_(self, "already in progress");
} else {
DBG("%sinitiated", priv->log_prefix);
DBG_(self, "initiated");
priv->power_cycle = TRUE;
if (!priv->pending_id) {
ril_radio_submit_power_request(self, FALSE);
@@ -259,7 +271,7 @@ void ril_radio_power_on(struct ril_radio *self, gpointer tag)
if (!g_hash_table_contains(priv->req_table, tag)) {
gboolean was_on = ril_radio_power_should_be_on(self);
DBG("%s%p", priv->log_prefix, tag);
DBG_(self, "%p", tag);
g_hash_table_insert(priv->req_table, tag, tag);
if (!was_on && ril_radio_power_should_be_on(self)) {
ril_radio_power_request(self, TRUE, FALSE);
@@ -274,7 +286,7 @@ void ril_radio_power_off(struct ril_radio *self, gpointer tag)
struct ril_radio_priv *priv = self->priv;
if (g_hash_table_remove(priv->req_table, tag)) {
DBG("%s%p", priv->log_prefix, tag);
DBG_(self, "%p", tag);
if (!ril_radio_power_should_be_on(self)) {
/* The last one turns the lights off */
ril_radio_power_request(self, FALSE, FALSE);
@@ -346,20 +358,41 @@ static void ril_radio_state_changed(GRilIoChannel *io, guint code,
if (radio_state != RADIO_STATE_UNAVAILABLE) {
struct ril_radio_priv *priv = self->priv;
DBG("%s%s", priv->log_prefix,
ril_radio_state_to_string(radio_state));
DBG_(self, "%s", ril_radio_state_to_string(radio_state));
GASSERT(!priv->pending_id || !priv->retry_id);
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
DBG("%sswitched off for power cycle", priv->log_prefix);
DBG_(self, "switched off for power cycle");
priv->power_cycle = FALSE;
}
priv->last_known_state = radio_state;
if (priv->pending_id) {
priv->state_changed_while_request_pending++;
if (ril_radio_state_on(radio_state) ==
ril_radio_power_should_be_on(self)) {
DBG_(self, "dropping pending request");
/*
* All right, the modem has switched to the
* desired state, drop the request.
*/
grilio_queue_cancel_request(priv->q,
priv->pending_id, FALSE);
/*
* This will zero pending_id and call
* ril_radio_check_state() if necesary:
*/
ril_radio_power_request_done(self);
/* We are done */
return;
} else {
/* Something weird is going on */
priv->state_changed_while_request_pending++;
}
}
priv->last_known_state = radio_state;
ril_radio_check_state(self);
}
}
@@ -374,7 +407,7 @@ struct ril_radio *ril_radio_new(GRilIoChannel *io)
priv->log_prefix =
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
g_strconcat(io->name, " ", NULL) : g_strdup("");
DBG("%s", priv->log_prefix);
DBG_(self, "");
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_radio_state_changed,
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
@@ -431,7 +464,7 @@ static void ril_radio_finalize(GObject *object)
struct ril_radio *self = RIL_RADIO(object);
struct ril_radio_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
DBG_(self, "");
g_free(priv->log_prefix);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,8 @@
#include "ril_types.h"
#include <glib-object.h>
struct ril_radio {
GObject object;
struct ril_radio_priv *priv;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2017 Jolla Ltd.
* Copyright (C) 2017-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -71,6 +71,7 @@ struct ril_radio_caps {
gulong max_pref_mode_event_id;
gulong radio_event_id;
int tx_id;
int tx_pending;
struct ril_data *data;
struct ril_radio *radio;
struct ril_network *network;
@@ -85,7 +86,6 @@ typedef struct ril_radio_caps_manager {
GObject object;
GPtrArray *caps_list;
guint check_id;
int tx_pending;
int tx_id;
int tx_phase_index;
gboolean tx_failed;
@@ -453,7 +453,7 @@ struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
struct ril_radio_caps *self =
g_slice_new0(struct ril_radio_caps);
self->ref_count = 1;
g_atomic_int_set(&self->ref_count, 1);
self->slot = config->slot;
self->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
@@ -471,13 +471,16 @@ struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
self->simcard_event_id[SIM_EVENT_STATE_CHANGED] =
ril_sim_card_add_state_changed_handler(sim,
ril_radio_caps_simcard_event, self);
self->simcard_event_id[SIM_EVENT_IO_ACTIVE_CHANGED] =
ril_sim_card_add_sim_io_active_changed_handler(sim,
ril_radio_caps_simcard_event, self);
self->network = ril_network_ref(net);
self->settings_event_id[SETTINGS_EVENT_PREF_MODE] =
ril_sim_settings_add_pref_mode_changed_handler(
settings, ril_radio_caps_settings_event, self);
self->settings_event_id[SETTINGS_EVENT_IMSI] =
ril_sim_settings_add_pref_mode_changed_handler(
ril_sim_settings_add_imsi_changed_handler(
settings, ril_radio_caps_settings_event, self);
self->max_pref_mode_event_id =
@@ -560,6 +563,24 @@ static void ril_radio_caps_manager_foreach_tx
}
}
static gboolean ril_radio_caps_manager_tx_pending
(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];
/* Ignore the modems not associated with this transaction */
if (caps->tx_id == self->tx_id && caps->tx_pending > 0) {
return TRUE;
}
}
return FALSE;
}
/**
* Checks that all radio caps have been initialized (i.e. all the initial
* GET_RADIO_CAPABILITY requests have completed) and there's no transaction
@@ -568,7 +589,7 @@ static void ril_radio_caps_manager_foreach_tx
static gboolean ril_radio_caps_manager_can_check
(struct ril_radio_caps_manager *self)
{
if (self->caps_list && !self->tx_pending) {
if (self->caps_list && !ril_radio_caps_manager_tx_pending(self)) {
const GPtrArray *list = self->caps_list;
const struct ril_radio_caps *prev_caps = NULL;
gboolean all_modes_equal = TRUE;
@@ -753,6 +774,10 @@ static void ril_radio_caps_manager_issue_requests
phase->send_new_cap ? &caps->new_cap :
&caps->old_cap;
/* Count it */
caps->tx_pending++;
DBG_(caps, "tx_pending=%d", caps->tx_pending);
/* Encode and send the request */
grilio_request_append_int32(req,
RIL_RADIO_CAPABILITY_VERSION);
@@ -766,9 +791,6 @@ static void ril_radio_caps_manager_issue_requests
RIL_REQUEST_SET_RADIO_CAPABILITY,
handler, NULL, caps);
grilio_request_unref(req);
/* Count it */
self->tx_pending++;
}
}
}
@@ -791,7 +813,6 @@ static void ril_radio_caps_manager_next_transaction
{
ril_radio_caps_manager_foreach(self,
ril_radio_caps_manager_next_transaction_cb);
self->tx_pending = 0;
self->tx_failed = FALSE;
self->tx_phase_index = -1;
self->tx_id++;
@@ -829,8 +850,10 @@ static void ril_radio_caps_manager_abort_cb(GRilIoChannel *io,
struct ril_radio_caps *caps = user_data;
struct ril_radio_caps_manager *self = caps->mgr;
GASSERT(self->tx_pending > 0);
if (!(--self->tx_pending)) {
GASSERT(caps->tx_pending > 0);
caps->tx_pending--;
DBG_(caps, "tx_pending=%d", caps->tx_pending);
if (!ril_radio_caps_manager_tx_pending(self)) {
DBG("transaction aborted");
ril_radio_caps_manager_transaction_done(self);
}
@@ -875,7 +898,7 @@ static void ril_radio_caps_manager_next_phase_cb(GRilIoChannel *io,
struct ril_radio_caps_manager *self = caps->mgr;
gboolean ok = FALSE;
GASSERT(self->tx_pending > 0);
GASSERT(caps->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) &&
@@ -892,7 +915,9 @@ static void ril_radio_caps_manager_next_phase_cb(GRilIoChannel *io,
}
}
if (!(--self->tx_pending)) {
caps->tx_pending--;
DBG_(caps, "tx_pending=%d", caps->tx_pending);
if (!ril_radio_caps_manager_tx_pending(self)) {
if (self->tx_failed) {
ril_radio_caps_manager_abort_transaction(self);
} else {
@@ -907,7 +932,7 @@ static void ril_radio_caps_manager_next_phase
/* 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);
GASSERT(!ril_radio_caps_manager_tx_pending(self));
if (self->tx_phase_index >= max_index) {
DBG("transaction %d is done", self->tx_id);
ril_radio_caps_manager_transaction_done(self);
@@ -924,14 +949,16 @@ static void ril_radio_caps_manager_next_phase
static void ril_radio_caps_manager_data_off_done(GRilIoChannel *io,
int status, const void *req_data, guint len, void *user_data)
{
struct ril_radio_caps_manager *self = RADIO_CAPS_MANAGER(user_data);
struct ril_radio_caps *caps = user_data;
struct ril_radio_caps_manager *self = caps->mgr;
DBG("%d", self->tx_pending);
GASSERT(self->tx_pending > 0);
GASSERT(caps->tx_pending > 0);
if (status != GRILIO_STATUS_OK) {
self->tx_failed = TRUE;
}
if (!(--self->tx_pending)) {
caps->tx_pending--;
DBG_(caps, "tx_pending=%d", caps->tx_pending);
if (!ril_radio_caps_manager_tx_pending(self)) {
if (self->tx_failed) {
DBG("failed to start the transaction");
ril_data_manager_assert_data_on(self->data_manager);
@@ -951,13 +978,13 @@ static void ril_radio_caps_manager_data_off
{
GRilIoRequest *req = ril_request_allow_data_new(FALSE);
self->tx_pending++;
DBG_(caps, "disallowing data");
caps->tx_pending++;
DBG_(caps, "tx_pending=%d", caps->tx_pending);
grilio_request_set_timeout(req, DATA_OFF_TIMEOUT_MS);
grilio_queue_send_request_full(caps->q, req,
RIL_REQUEST_ALLOW_DATA,
ril_radio_caps_manager_data_off_done,
NULL, self);
NULL, caps);
grilio_request_unref(req);
}
@@ -967,14 +994,16 @@ static void ril_radio_caps_manager_deactivate_data_call_done(GRilIoChannel *io,
struct ril_radio_caps *caps = user_data;
struct ril_radio_caps_manager *self = caps->mgr;
GASSERT(self->tx_pending > 0);
GASSERT(caps->tx_pending > 0);
if (status != GRILIO_STATUS_OK) {
self->tx_failed = TRUE;
/* Something seems to be slightly broken, try requesting the
* current state (later, after we release the transaction). */
ril_data_poll_call_state(caps->data);
}
if (!(--self->tx_pending)) {
caps->tx_pending--;
DBG_(caps, "tx_pending=%d", caps->tx_pending);
if (!ril_radio_caps_manager_tx_pending(self)) {
if (self->tx_failed) {
DBG("failed to start the transaction");
ril_radio_caps_manager_recheck_later(self);
@@ -992,8 +1021,8 @@ static void ril_radio_caps_deactivate_data_call(struct ril_radio_caps *caps,
{
GRilIoRequest *req = ril_request_deactivate_data_call_new(cid);
caps->mgr->tx_pending++;
DBG_(caps, "deactivating call %u", cid);
caps->tx_pending++;
DBG_(caps, "cid=%u, tx_pending=%d", cid, caps->tx_pending);
grilio_request_set_blocking(req, TRUE);
grilio_request_set_timeout(req, DEACTIVATE_TIMEOUT_MS);
grilio_queue_send_request_full(caps->q, req,
@@ -1028,11 +1057,11 @@ static void ril_radio_caps_manager_deactivate_all
{
ril_radio_caps_manager_foreach_tx(self,
ril_radio_caps_manager_deactivate_all_cb);
if (!self->tx_pending) {
if (!ril_radio_caps_manager_tx_pending(self)) {
/* No data calls, submit ALLOW_DATA requests right away */
ril_radio_caps_manager_foreach_tx(self,
ril_radio_caps_manager_data_off);
GASSERT(self->tx_pending);
GASSERT(ril_radio_caps_manager_tx_pending(self));
}
}
@@ -1255,6 +1284,24 @@ static GSList *ril_radio_caps_manager_empty_slots
return found;
}
static guint ril_radio_caps_manager_sim_count
(struct ril_radio_caps_manager *self)
{
const GPtrArray *list = self->caps_list;
guint i, count = 0;
for (i = 0; i < list->len; i++) {
const struct ril_radio_caps *caps = list->pdata[i];
if (caps->simcard->status->card_state ==
RIL_CARDSTATE_PRESENT) {
count++;
}
}
return count;
}
/**
* There could be no capability mismatch but LTE could be enabled for
* the slot that has no SIM card in it. That's a waste, fix it.
@@ -1298,7 +1345,7 @@ static void ril_radio_caps_manager_check(struct ril_radio_caps_manager *self)
if (ril_radio_caps_manager_can_check(self)) {
const int first = ril_radio_caps_manager_first_mismatch(self);
if (first >= 0) {
if (first >= 0 && ril_radio_caps_manager_sim_count(self) > 1) {
if (ril_radio_caps_manager_update_caps(self, first)) {
ril_radio_caps_manager_start_transaction(self);
}
@@ -1321,7 +1368,7 @@ static gboolean ril_radio_caps_manager_check_cb(gpointer data)
static void ril_radio_caps_manager_recheck_later
(struct ril_radio_caps_manager *self)
{
if (!self->tx_pending) {
if (!ril_radio_caps_manager_tx_pending(self)) {
if (self->check_id) {
g_source_remove(self->check_id);
self->check_id = 0;
@@ -1334,7 +1381,7 @@ static void ril_radio_caps_manager_recheck_later
static void ril_radio_caps_manager_schedule_check
(struct ril_radio_caps_manager *self)
{
if (!self->check_id && !self->tx_pending) {
if (!self->check_id && !ril_radio_caps_manager_tx_pending(self)) {
self->check_id = g_idle_add(ril_radio_caps_manager_check_cb,
self);
}

View File

@@ -69,6 +69,11 @@ enum ril_sim_card_event {
SIM_CARD_EVENT_COUNT
};
enum ril_sim_io_event {
IO_EVENT_SIM_REFRESH,
IO_EVENT_COUNT
};
struct ril_sim {
GRilIoChannel *io;
GRilIoQueue *q;
@@ -81,6 +86,7 @@ struct ril_sim {
gboolean inserted;
guint idle_id; /* Used by register and SIM reset callbacks */
gulong card_event_id[SIM_CARD_EVENT_COUNT];
gulong io_event_id[IO_EVENT_COUNT];
guint query_pin_retries_id;
const char *log_prefix;
@@ -102,8 +108,9 @@ struct ril_sim_io_response {
guint data_len;
};
struct ril_sim_cbd {
struct ril_sim_cbd_io {
struct ril_sim *sd;
struct ril_sim_card *card;
union _ofono_sim_cb {
ofono_sim_file_info_cb_t file_info;
ofono_sim_read_cb_t read;
@@ -173,24 +180,43 @@ static const struct ril_sim_retry_query ril_sim_retry_query_types[] = {
#define DBG_(sd,fmt,args...) DBG("%s" fmt, (sd)->log_prefix, ##args)
#define ril_sim_cbd_free g_free
static inline struct ril_sim *ril_sim_get_data(struct ofono_sim *sim)
{
return ofono_sim_get_data(sim);
}
static struct ril_sim_cbd *ril_sim_cbd_new(struct ril_sim *sd, void *cb,
static struct ril_sim_cbd_io *ril_sim_cbd_io_new(struct ril_sim *sd, void *cb,
void *data)
{
struct ril_sim_cbd *cbd = g_new0(struct ril_sim_cbd, 1);
struct ril_sim_cbd_io *cbd = g_new0(struct ril_sim_cbd_io, 1);
cbd->sd = sd;
cbd->cb.ptr = cb;
cbd->data = data;
cbd->card = ril_sim_card_ref(sd->card);
return cbd;
}
static void ril_sim_cbd_io_free(void *data)
{
struct ril_sim_cbd_io *cbd = data;
ril_sim_card_sim_io_finished(cbd->card, cbd->req_id);
ril_sim_card_unref(cbd->card);
g_free(cbd);
}
static void ril_sim_cbd_io_start(struct ril_sim_cbd_io *cbd, GRilIoRequest* req,
guint code, GRilIoChannelResponseFunc cb)
{
struct ril_sim *sd = cbd->sd;
cbd->req_id = grilio_queue_send_request_full(sd->q, req, code,
cb, ril_sim_cbd_io_free, cbd);
ril_sim_card_sim_io_started(cbd->card, cbd->req_id);
}
static void ril_sim_pin_cbd_state_event_count_cb(struct ril_sim_card *sc,
void *user_data)
{
@@ -249,11 +275,6 @@ static void ril_sim_pin_req_done(gpointer ptr)
}
}
static const char *ril_sim_app_id(struct ril_sim *sd)
{
return sd->card->app ? sd->card->app->aid : NULL;
}
int ril_sim_app_type(struct ofono_sim *sim)
{
struct ril_sim *sd = ril_sim_get_data(sim);
@@ -423,14 +444,13 @@ static void ril_sim_io_response_free(struct ril_sim_io_response *res)
static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd *cbd = user_data;
struct ril_sim_cbd_io *cbd = user_data;
ofono_sim_file_info_cb_t cb = cbd->cb.file_info;
struct ril_sim *sd = cbd->sd;
struct ril_sim_io_response *res = NULL;
struct ofono_error error;
DBG_(sd, "");
ril_sim_card_sim_io_finished(sd->card, cbd->req_id);
ril_error_init_failure(&error);
res = ril_sim_parse_io_response(data, len);
@@ -474,12 +494,13 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
guint p1, guint p2, guint p3, const char *hex_data,
const guchar *path, guint path_len,
GRilIoChannelResponseFunc cb, struct ril_sim_cbd *cbd)
GRilIoChannelResponseFunc cb, struct ril_sim_cbd_io *cbd)
{
GRilIoRequest *req = grilio_request_new();
DBG_(sd, "cmd=0x%.2X,efid=0x%.4X,%d,%d,%d,%s,pin2=(null),aid=%s",
cmd, fileid, p1, p2, p3, hex_data, ril_sim_app_id(sd));
cmd, fileid, p1, p2, p3, hex_data,
ril_sim_card_app_aid(sd->card));
grilio_request_append_int32(req, cmd);
grilio_request_append_int32(req, fileid);
@@ -489,13 +510,11 @@ static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
grilio_request_append_int32(req, p3); /* P3 */
grilio_request_append_utf8(req, hex_data); /* data; only for writes */
grilio_request_append_utf8(req, NULL); /* pin2; only for writes */
grilio_request_append_utf8(req, ril_sim_app_id(sd));
grilio_request_append_utf8(req, ril_sim_card_app_aid(sd->card));
grilio_request_set_blocking(req, TRUE);
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SIM_IO, cb, ril_sim_cbd_free, cbd);
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_IO, cb);
grilio_request_unref(req);
}
@@ -505,19 +524,19 @@ static void ril_sim_ofono_read_file_info(struct ofono_sim *sim, int fileid,
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_request_io(sd, CMD_GET_RESPONSE, fileid, 0, 0, 15, NULL,
path, len, ril_sim_file_info_cb, ril_sim_cbd_new(sd, cb, data));
path, len, ril_sim_file_info_cb,
ril_sim_cbd_io_new(sd, cb, data));
}
static void ril_sim_read_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd *cbd = user_data;
struct ril_sim_cbd_io *cbd = user_data;
ofono_sim_read_cb_t cb = cbd->cb.read;
struct ril_sim_io_response *res;
struct ofono_error err;
DBG_(cbd->sd, "");
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
res = ril_sim_parse_io_response(data, len);
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
@@ -536,7 +555,7 @@ static void ril_sim_read(struct ofono_sim *sim, guint cmd, int fileid,
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_request_io(sd, cmd, fileid, p1, p2, p3, NULL, path, path_len,
ril_sim_read_cb, ril_sim_cbd_new(sd, cb, data));
ril_sim_read_cb, ril_sim_cbd_io_new(sd, cb, data));
}
static void ril_sim_ofono_read_file_transparent(struct ofono_sim *sim,
@@ -566,13 +585,12 @@ static void ril_sim_ofono_read_file_cyclic(struct ofono_sim *sim, int fileid,
static void ril_sim_write_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd *cbd = user_data;
struct ril_sim_cbd_io *cbd = user_data;
ofono_sim_write_cb_t cb = cbd->cb.write;
struct ril_sim_io_response *res;
struct ofono_error err;
DBG_(cbd->sd, "");
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
res = ril_sim_parse_io_response(data, len);
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
@@ -593,7 +611,7 @@ static void ril_sim_write(struct ofono_sim *sim, guint cmd, int fileid,
struct ril_sim *sd = ril_sim_get_data(sim);
char *hex_data = encode_hex(value, length, 0);
ril_sim_request_io(sd, cmd, fileid, p1, p2, length, hex_data, path,
path_len, ril_sim_write_cb, ril_sim_cbd_new(sd, cb, data));
path_len, ril_sim_write_cb, ril_sim_cbd_io_new(sd, cb, data));
g_free(hex_data);
}
@@ -630,12 +648,10 @@ static void ril_sim_write_file_cyclic(struct ofono_sim *sim, int fileid,
static void ril_sim_get_imsi_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd *cbd = user_data;
struct ril_sim_cbd_io *cbd = user_data;
ofono_sim_imsi_cb_t cb = cbd->cb.imsi;
struct ofono_error error;
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
if (status == RIL_E_SUCCESS) {
gchar *imsi;
GRilIoParser rilp;
@@ -660,8 +676,8 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
const char *app_id = ril_sim_app_id(sd);
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
const char *app_id = ril_sim_card_app_aid(sd->card);
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
GRilIoRequest *req = grilio_request_array_utf8_new(1, app_id);
DBG_(sd, "%s", app_id);
@@ -673,10 +689,8 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
*/
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_request_set_blocking(req, TRUE);
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_GET_IMSI, ril_sim_get_imsi_cb,
ril_sim_cbd_free, cbd);
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_GET_IMSI,
ril_sim_get_imsi_cb);
grilio_request_unref(req);
}
@@ -858,31 +872,15 @@ static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
}
}
static gboolean ril_sim_reinsert_cb(gpointer data)
{
struct ril_sim *sd = data;
const enum ofono_sim_state state = ofono_sim_get_state(sd->watch->sim);
GASSERT(sd->idle_id);
sd->idle_id = 0;
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted) {
DBG_(sd, "reinserting SIM");
ofono_sim_inserted_notify(sd->sim, TRUE);
}
return G_SOURCE_REMOVE;
}
static void ril_sim_state_changed_cb(struct sailfish_watch *watch, void *data)
{
struct ril_sim *sd = data;
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
DBG_(sd, "%d %d", state, sd->inserted);
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted &&
!sd->idle_id) {
sd->idle_id = g_idle_add(ril_sim_reinsert_cb, sd);
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted) {
/* That will simulate SIM card removal: */
ril_sim_card_reset(sd->card);
}
}
@@ -900,25 +898,22 @@ static int ril_sim_parse_retry_count(const void *data, guint len)
static GRilIoRequest *ril_sim_enter_sim_pin_req(struct ril_sim *sd,
const char *pin)
{
if (sd->card->app) {
/*
* If there's no AID then so be it... Some
* adaptations (namely, MTK) don't provide it
* but don't seem to require it either.
*/
GRilIoRequest *req = grilio_request_array_utf8_new(2,
pin, sd->card->app->aid);
/*
* If there's no AID then so be it... Some
* adaptations (namely, MTK) don't provide it
* but don't seem to require it either.
*/
GRilIoRequest *req = grilio_request_array_utf8_new(2, pin,
ril_sim_card_app_aid(sd->card));
grilio_request_set_blocking(req, TRUE);
return req;
}
return NULL;
grilio_request_set_blocking(req, TRUE);
return req;
}
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);
const char *app_id = ril_sim_card_app_aid(sd->card);
if (app_id) {
GRilIoRequest *req = grilio_request_array_utf8_new(3,
puk, pin, app_id);
@@ -1220,7 +1215,7 @@ static void ril_sim_pin_send(struct ofono_sim *sim, const char *passwd,
GRilIoRequest *req = ril_sim_enter_sim_pin_req(sd, passwd);
if (req) {
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
DBG_(sd, "%s,aid=%s", passwd, ril_sim_card_app_aid(sd->card));
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,
@@ -1247,10 +1242,7 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
case OFONO_SIM_PASSWORD_PHNET_PIN:
if (!enable) {
code = RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION;
req = grilio_request_sized_new(12);
grilio_request_append_int32(req,
RIL_PERSOSUBSTATE_SIM_NETWORK);
grilio_request_append_utf8(req, passwd);
req = grilio_request_array_utf8_new(1, passwd);
} else {
DBG_(sd, "Not supported, enable=%d", enable);
}
@@ -1263,7 +1255,7 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
if (req) {
id = grilio_queue_send_request_full(sd->q, req, code,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
grilio_request_unref(req);
}
@@ -1299,7 +1291,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
const char *passwd, ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
const char *app_id = ril_sim_app_id(sd);
const char *app_id = ril_sim_card_app_aid(sd->card);
const char *type_str = ril_sim_facility_code(passwd_type);
struct ofono_error error;
guint id = 0;
@@ -1319,7 +1311,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SET_FACILITY_LOCK,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
grilio_request_unref(req);
}
@@ -1337,7 +1329,7 @@ static void ril_sim_pin_send_puk(struct ofono_sim *sim,
if (req) {
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd,
ril_sim_app_id(sd));
ril_sim_card_app_aid(sd->card));
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PUK, ril_sim_pin_change_state_cb,
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
@@ -1357,7 +1349,7 @@ static void ril_sim_change_passwd(struct ofono_sim *sim,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
const char *app_id = ril_sim_app_id(sd);
const char *app_id = ril_sim_card_app_aid(sd->card);
GRilIoRequest *req = grilio_request_array_utf8_new(3,
old_passwd, new_passwd, app_id);
@@ -1375,11 +1367,9 @@ static void ril_sim_query_facility_lock_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_sim_cbd *cbd = user_data;
struct ril_sim_cbd_io *cbd = user_data;
ofono_query_facility_lock_cb_t cb = cbd->cb.query_facility_lock;
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
if (status == RIL_E_SUCCESS) {
int locked = 0;
GRilIoParser rilp;
@@ -1409,9 +1399,9 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
{
struct ril_sim *sd = ril_sim_get_data(sim);
const char *type_str = ril_sim_facility_code(type);
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
GRilIoRequest *req = grilio_request_array_utf8_new(4,
type_str, "", "0" /* class */, ril_sim_app_id(sd));
type_str, "", "0" /* class */, ril_sim_card_app_aid(sd->card));
/* Make sure that this request gets completed sooner or later */
grilio_request_set_timeout(req, FAC_LOCK_QUERY_TIMEOUT_SECS * 1000);
@@ -1419,13 +1409,24 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
grilio_request_set_retry_func(req, ril_sim_query_facility_lock_retry);
DBG_(sd, "%s", type_str);
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_QUERY_FACILITY_LOCK, ril_sim_query_facility_lock_cb,
ril_sim_cbd_free, cbd);
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_QUERY_FACILITY_LOCK,
ril_sim_query_facility_lock_cb);
grilio_request_unref(req);
}
static void ril_sim_refresh_cb(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_sim *sd = user_data;
/*
* RIL_UNSOL_SIM_REFRESH may contain the EFID of the updated file,
* so we could be more descrete here. However I have't actually
* seen that in real life, let's just refresh everything for now.
*/
__ofono_sim_refresh(sd->sim, NULL, TRUE, TRUE);
}
static gboolean ril_sim_register(gpointer user)
{
struct ril_sim *sd = user;
@@ -1447,6 +1448,11 @@ static gboolean ril_sim_register(gpointer user)
sailfish_watch_add_sim_state_changed_handler(sd->watch,
ril_sim_state_changed_cb, sd);
/* And RIL events */
sd->io_event_id[IO_EVENT_SIM_REFRESH] =
grilio_channel_add_unsol_event_handler(sd->io,
ril_sim_refresh_cb, RIL_UNSOL_SIM_REFRESH, sd);
/* Check the current state */
ril_sim_status_changed_cb(sd->card, sd);
return FALSE;
@@ -1485,6 +1491,7 @@ static void ril_sim_remove(struct ofono_sim *sim)
DBG_(sd, "");
g_list_free_full(sd->pin_cbd_list, ril_sim_pin_cbd_list_free_cb);
grilio_channel_remove_all_handlers(sd->io, sd->io_event_id);
grilio_queue_cancel_all(sd->q, FALSE);
ofono_sim_set_data(sim, NULL);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,17 @@
#include <gutil_misc.h>
/*
* First we wait for USIM app to get activated by itself. If that
* doesn't happen within UICC_SUBSCRIPTION_START_MS we poke the SIM
* with SET_UICC_SUBSCRIPTION request, resubmitting it if it times out.
* If nothing happens within UICC_SUBSCRIPTION_TIMEOUT_MS we give up.
*
* Submitting SET_UICC_SUBSCRIPTION request when rild doesn't expect
* it sometimes breaks pretty much everything. Unfortunately, there no
* reliable way to find out when rild expects it and when it doesn't :/
*/
#define UICC_SUBSCRIPTION_START_MS (5000)
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
/* SIM I/O idle timeout is measured in the number of idle loops.
@@ -48,6 +59,7 @@ struct ril_sim_card_priv {
int flags;
guint status_req_id;
guint sub_req_id;
guint sub_start_timer;
gulong event_id[EVENT_COUNT];
guint sim_io_idle_id;
guint sim_io_idle_count;
@@ -157,10 +169,55 @@ static void ril_sim_card_status_free(struct ril_sim_card_status *status)
}
}
static void ril_sim_card_tx_start(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
GRILIO_TRANSACTION_STATE tx_state =
grilio_queue_transaction_state(priv->q);
if (tx_state == GRILIO_TRANSACTION_NONE) {
tx_state = grilio_queue_transaction_start(priv->q);
DBG("status tx for slot %u %s", self->slot,
(tx_state == GRILIO_TRANSACTION_STARTED) ?
"started" : "starting");
}
}
static void ril_sim_card_tx_check(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
if (grilio_queue_transaction_state(priv->q) !=
GRILIO_TRANSACTION_NONE) {
const struct ril_sim_card_status *status = self->status;
if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
/* Transaction (if there is any) is finished when
* both GET_SIM_STATUS and SET_UICC_SUBSCRIPTION
* complete or get dropped */
if (!priv->status_req_id && !priv->sub_req_id &&
status->gsm_umts_index >= 0 &&
status->gsm_umts_index < status->num_apps) {
DBG("status tx for slot %u finished",
self->slot);
grilio_queue_transaction_finish(priv->q);
}
} else {
DBG("status tx for slot %u cancelled", self->slot);
grilio_queue_transaction_finish(priv->q);
}
}
}
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
if (priv->sub_start_timer) {
/* Don't need this timer anymore */
g_source_remove(priv->sub_start_timer);
priv->sub_start_timer = 0;
}
if (priv->sub_req_id) {
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
* so we better drop rather than cancel it (so that it gets
@@ -168,7 +225,7 @@ static void ril_sim_card_subscription_done(struct ril_sim_card *self)
grilio_channel_drop_request(priv->io, priv->sub_req_id);
priv->sub_req_id = 0;
}
grilio_queue_transaction_finish(priv->q);
ril_sim_card_tx_check(self);
}
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
@@ -184,19 +241,18 @@ static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
ril_sim_card_subscription_done(self);
}
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
enum ril_uicc_subscription_action sub_action)
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index)
{
struct ril_sim_card_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(16);
const guint sub_id = self->slot;
guint code;
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_action);
DBG("%u,%d,%u", self->slot, app_index, sub_id);
grilio_request_append_int32(req, self->slot);
grilio_request_append_int32(req, app_index);
grilio_request_append_int32(req, sub_id);
grilio_request_append_int32(req, sub_action);
grilio_request_append_int32(req, RIL_UICC_SUBSCRIPTION_ACTIVATE);
grilio_request_set_retry(req, 0, -1);
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
@@ -213,7 +269,7 @@ static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
/* Don't allow any requests other that GET_SIM_STATUS until
* we are done with the subscription */
grilio_queue_transaction_start(priv->q);
ril_sim_card_tx_start(self);
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
req, code, ril_sim_card_subscribe_cb, NULL, self);
grilio_request_unref(req);
@@ -250,9 +306,8 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
ril_sim_card_subscription_done(self);
} else {
app_index = ril_sim_card_select_app(status);
if (app_index >= 0) {
ril_sim_card_subscribe(self, app_index,
RIL_UICC_SUBSCRIPTION_ACTIVATE);
if (app_index >= 0 && !self->priv->sub_start_timer) {
ril_sim_card_subscribe(self, app_index);
}
}
} else {
@@ -273,6 +328,18 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
}
}
static gboolean ril_sim_card_sub_start_timeout(gpointer user_data)
{
struct ril_sim_card *self = RIL_SIMCARD(user_data);
struct ril_sim_card_priv *priv = self->priv;
DBG("%u", self->slot);
GASSERT(priv->sub_start_timer);
priv->sub_start_timer = 0;
ril_sim_card_update_app(self);
return G_SOURCE_REMOVE;
}
static void ril_sim_card_update_status(struct ril_sim_card *self,
struct ril_sim_card_status *status)
{
@@ -282,6 +349,23 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
struct ril_sim_card_status *old_status = self->status;
self->status = status;
if (diff & RIL_SIMCARD_STATE_CHANGED &&
status->card_state == RIL_CARDSTATE_PRESENT) {
struct ril_sim_card_priv *priv = self->priv;
/*
* SIM card has just appeared, give it some time to
* activate the USIM app
*/
if (priv->sub_start_timer) {
g_source_remove(priv->sub_start_timer);
}
DBG("started subscription timeout for slot %u",
self->slot);
priv->sub_start_timer =
g_timeout_add(UICC_SUBSCRIPTION_START_MS,
ril_sim_card_sub_start_timeout, self);
}
ril_sim_card_update_app(self);
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_STATUS_RECEIVED], 0);
@@ -297,6 +381,7 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
}
ril_sim_card_status_free(old_status);
} else {
ril_sim_card_update_app(self);
ril_sim_card_status_free(status);
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_STATUS_RECEIVED], 0);
@@ -430,6 +515,24 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
ril_sim_card_update_status(self, status);
}
}
ril_sim_card_tx_check(self);
}
void ril_sim_card_reset(struct ril_sim_card *self)
{
if (G_LIKELY(self)) {
struct ril_sim_card_status *status =
g_new0(struct ril_sim_card_status, 1);
/* Simulate removal and re-submit the SIM status query */
status->card_state = RIL_CARDSTATE_ABSENT;
status->gsm_umts_index = -1;
status->cdma_index = -1;
status->ims_index = -1;
ril_sim_card_update_status(self, status);
ril_sim_card_request_status(self);
}
}
void ril_sim_card_request_status(struct ril_sim_card *self)
@@ -445,6 +548,9 @@ void ril_sim_card_request_status(struct ril_sim_card *self)
} else {
GRilIoRequest* req = grilio_request_new();
/* Start the transaction to not allow any other
* requests to interfere with SIM status query */
ril_sim_card_tx_start(self);
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
priv->status_req_id =
grilio_queue_send_request_full(priv->q,
@@ -664,6 +770,9 @@ static void ril_sim_card_finalize(GObject *object)
if (priv->sim_io_idle_id) {
g_source_remove(priv->sim_io_idle_id);
}
if (priv->sub_start_timer) {
g_source_remove(priv->sub_start_timer);
}
g_hash_table_destroy(priv->sim_io_pending);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,8 @@
#include "ril_types.h"
#include <glib-object.h>
struct ril_sim_card_app {
enum ril_app_type app_type;
enum ril_app_state app_state;
@@ -56,6 +58,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_reset(struct ril_sim_card *sc);
void ril_sim_card_request_status(struct ril_sim_card *sc);
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
@@ -74,9 +77,13 @@ void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
/* Inline wrappers */
static inline enum ril_app_type
ril_sim_card_app_type(struct ril_sim_card *sc)
static inline enum ril_app_type ril_sim_card_app_type(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
static inline const char *ril_sim_card_app_aid(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->aid : NULL; }
#define ril_sim_card_remove_all_handlers(net, ids) \
ril_sim_card_remove_handlers(net, ids, G_N_ELEMENTS(ids))
#endif /* RIL_SIM_CARD_H */

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,8 @@
#include "ril_types.h"
#include <glib-object.h>
struct ril_sim_settings_priv;
struct ril_sim_settings {

View File

@@ -184,6 +184,13 @@ socket=/dev/socket/rild
#
#enableVoicecall=true
# Support for Cell Broadcast System (CBS). By default, its enabled but if
# your rild and/or modem is not happy about it, you can turn it off.
#
# Default true
#
#enableCellBroadcast=true
# Timeout for the modem to show up, in milliseconds. Those that don't
# show up before this timeout expires, will be dropped (ignored).
#
@@ -202,3 +209,34 @@ socket=/dev/socket/rild
# Default is false (use RIL_REQUEST_DEVICE_IDENTITY)
#
#legacyImeiQuery=false
# Some devices don't support LTE RAT mode PREF_NET_TYPE_LTE_GSM_WCDMA.
# This option allows to set a custom LTE mode.
#
# The default is 9 (PREF_NET_TYPE_LTE_GSM_WCDMA)
#
#lteNetworkMode=9
# Timeout for RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, in milliseconds.
#
# The default is 20000 (20 seconds)
#
#networkModeTimeout=20000
# Cycle radio power at startup.
#
# The default is true (cycle the power)
#
#radioPowerCycle=true
# With some RILs it seems to be necessary to kick (RIL_REQUEST_RADIO_POWER)
# the modems with power on after one of the modems has been powered off.
# Otherwise bad things may happen (like the modem never registering
# on the network).
#
# On the other hand, with some RILs it's causing some trouble (like this
# extra RIL_REQUEST_RADIO_POWER getting stuck indefinitely).
#
# The default is true for historical reasons
#
#confirmRadioPowerOn=true

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -51,8 +51,14 @@ struct ril_vendor_hook;
struct ril_slot_config {
guint slot;
enum ofono_radio_access_mode techs;
int lte_network_mode;
int network_mode_timeout;
gboolean query_available_band_mode;
gboolean empty_pin_query;
gboolean radio_power_cycle;
gboolean confirm_radio_power_on;
gboolean enable_voicecall;
gboolean enable_cbs;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
};

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,6 +20,8 @@
#include "smsutil.h"
#include "util.h"
#define USSD_CANCEL_TIMEOUT_SEC (20)
struct ril_ussd {
struct ofono_ussd *ussd;
GRilIoChannel *io;
@@ -114,11 +116,14 @@ static void ril_ussd_cancel(struct ofono_ussd *ussd,
ofono_ussd_cb_t cb, void *data)
{
struct ril_ussd *ud = ril_ussd_get_data(ussd);
GRilIoRequest *req = grilio_request_new();
ofono_info("send ussd cancel");
grilio_queue_send_request_full(ud->q, NULL, RIL_REQUEST_CANCEL_USSD,
grilio_request_set_timeout(req, USSD_CANCEL_TIMEOUT_SEC * 1000);
grilio_queue_send_request_full(ud->q, req, RIL_REQUEST_CANCEL_USSD,
ril_ussd_cancel_cb, ril_ussd_cbd_free,
ril_ussd_cbd_new(cb, data));
grilio_request_unref(req);
}
static void ril_ussd_notify(GRilIoChannel *io, guint code,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,10 +18,10 @@
#include <grilio_channel.h>
#include <gutil_misc.h>
#include <sys/socket.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include "common.h"
#include "netreg.h"
@@ -326,7 +326,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
{
int access_tech = -1;
int tech = -1;
if (ril_parse_int(stech, 0, &tech)) {
if (gutil_parse_int(stech, 0, &tech)) {
switch (tech) {
case RADIO_TECH_GPRS:
case RADIO_TECH_GSM:
@@ -411,26 +411,6 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
return FALSE;
}
gboolean ril_parse_int(const char *str, int base, int *value)
{
gboolean ok = FALSE;
if (str && str[0]) {
char *str2 = g_strstrip(g_strdup(str));
char *end = str2;
long l;
errno = 0;
l = strtol(str2, &end, base);
ok = !*end && errno != ERANGE && l >= INT_MIN && l <= INT_MAX;
if (ok && value) {
*value = (int)l;
}
g_free(str2);
}
return ok;
}
/*
* Local Variables:
* mode: C

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,7 +26,6 @@ const char *ril_unsol_event_to_string(guint event);
const char *ril_radio_state_to_string(int radio_state);
int ril_parse_tech(const char *stech, int *ril_tech);
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
gboolean ril_parse_int(const char *str, int base, int *value);
#define ril_error_init_ok(err) \
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,7 +18,8 @@
struct ril_vendor_hook *ril_vendor_create_hook
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
const char *path, const struct ril_slot_config *config)
const char *path, const struct ril_slot_config *config,
struct ril_network *network)
{
if (vendor) {
const void *data = vendor->driver_data;
@@ -31,16 +32,19 @@ struct ril_vendor_hook *ril_vendor_create_hook
vendor = vendor->base;
}
if (vendor->create_hook) {
return vendor->create_hook(data, io, path, config);
return vendor->create_hook(data, io, path, config,
network);
}
}
return NULL;
}
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *self,
const struct ril_vendor_hook_proc *proc)
const struct ril_vendor_hook_proc *proc,
ril_vendor_hook_free_proc free)
{
self->proc = proc;
self->free = free;
g_atomic_int_set(&self->ref_count, 1);
return self;
}
@@ -56,13 +60,8 @@ struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *self)
static void ril_vendor_hook_free(struct ril_vendor_hook *self)
{
const struct ril_vendor_hook_proc *proc = self->proc;
while (!proc->free && proc->base) {
proc = proc->base;
}
if (proc->free) {
proc->free(self);
if (self->free) {
self->free(self);
}
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,6 +21,8 @@
struct ril_vendor_defaults {
gboolean empty_pin_query;
gboolean legacy_imei_query;
gboolean enable_cbs;
gboolean query_available_band_mode;
};
struct ril_vendor_driver {
@@ -30,12 +32,12 @@ struct ril_vendor_driver {
void (*get_defaults)(struct ril_vendor_defaults *defaults);
struct ril_vendor_hook *(*create_hook)(const void *driver_data,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *cfg);
const struct ril_slot_config *cfg,
struct ril_network *network);
};
struct ril_vendor_hook_proc {
const struct ril_vendor_hook_proc *base;
void (*free)(struct ril_vendor_hook *hook);
const char *(*request_to_string)(struct ril_vendor_hook *hook,
guint request);
const char *(*event_to_string)(struct ril_vendor_hook *hook,
@@ -49,19 +51,23 @@ struct ril_vendor_hook_proc {
GRilIoParser *rilp);
};
typedef void (*ril_vendor_hook_free_proc)(struct ril_vendor_hook *hook);
struct ril_vendor_hook {
const struct ril_vendor_hook_proc *proc;
ril_vendor_hook_free_proc free;
gint ref_count;
};
struct ril_vendor_hook *ril_vendor_create_hook
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
const char *path, const struct ril_slot_config *cfg);
const char *path, const struct ril_slot_config *cfg,
struct ril_network *network);
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
struct ril_vendor_defaults *defaults);
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *hook,
const struct ril_vendor_hook_proc *proc);
const struct ril_vendor_hook_proc *proc,
ril_vendor_hook_free_proc free);
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *hook);
void ril_vendor_hook_unref(struct ril_vendor_hook *hook);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,7 @@
#include "ril_plugin.h"
#include "ril_vendor.h"
#include "ril_network.h"
#include "ril_data.h"
#include "ril_log.h"
@@ -26,17 +27,27 @@
#include <grilio_queue.h>
#include <gutil_macros.h>
#include <gutil_misc.h>
#include "ofono.h"
#define SET_INITIAL_ATTACH_APN_TIMEOUT (20*1000)
enum ril_mtk_watch_events {
WATCH_EVENT_SIM_CHANGED,
WATCH_EVENT_IMSI_CHANGED,
WATCH_EVENT_COUNT
};
enum ril_mtk_network_events {
NETWORK_EVENT_PREF_MODE_CHANGED,
NETWORK_EVENT_COUNT
};
enum ril_mtk_events {
MTK_EVENT_REGISTRATION_SUSPENDED,
MTK_EVENT_SET_ATTACH_APN,
MTK_EVENT_PS_NETWORK_STATE_CHANGED,
MTK_EVENT_INCOMING_CALL_INDICATION,
MTK_EVENT_COUNT
};
@@ -45,7 +56,12 @@ struct ril_vendor_hook_mtk {
const struct ril_mtk_msg *msg;
GRilIoQueue *q;
GRilIoChannel *io;
struct ril_network *network;
struct sailfish_watch *watch;
guint set_initial_attach_apn_id;
gboolean initial_attach_apn_ok;
gulong network_event_id[NETWORK_EVENT_COUNT];
gulong watch_event_id[WATCH_EVENT_COUNT];
gulong ril_event_id[MTK_EVENT_COUNT];
guint slot;
};
@@ -57,39 +73,47 @@ struct ril_vendor_mtk_driver_data {
const struct ril_vendor_hook_proc *proc;
};
/* Hook with auto-detection */
struct ril_vendor_hook_mtk_auto {
struct ril_vendor_hook_mtk mtk;
const struct ril_vendor_mtk_driver_data *type;
gulong detect_id;
};
/* MTK specific RIL messages (actual codes differ from model to model!) */
struct ril_mtk_msg {
gboolean attach_apn_has_roaming_protocol;
guint request_resume_registration;
guint unsol_network_info;
guint request_set_call_indication;
/* See ril_vendor_mtk_auto_detect_event */
#define unsol_msgs unsol_ps_network_state_changed
#define MTK_UNSOL_MSGS (4)
guint unsol_ps_network_state_changed;
guint unsol_registration_suspended;
guint unsol_ims_registration_info;
guint unsol_volte_eps_network_feature_support;
guint unsol_emergency_bearer_support_notify;
guint unsol_incoming_call_indication;
guint unsol_set_attach_apn;
};
/* Fly FS522 Cirrus 14 */
static const struct ril_mtk_msg mtk_msg_mt6737 = {
static const struct ril_mtk_msg msg_mtk1 = {
.attach_apn_has_roaming_protocol = TRUE,
.request_resume_registration = 2050,
.unsol_network_info = 3001,
.request_set_call_indication = 2065,
.unsol_ps_network_state_changed = 3012,
.unsol_registration_suspended = 3021,
.unsol_ims_registration_info = 3029,
.unsol_volte_eps_network_feature_support = 3042,
.unsol_emergency_bearer_support_notify = 3052,
.unsol_incoming_call_indication = 3037,
.unsol_set_attach_apn = 3065
};
/* MT8735 Tablet */
static const struct ril_mtk_msg mtk_msg_mt8735 = {
static const struct ril_mtk_msg msg_mtk2 = {
.attach_apn_has_roaming_protocol = FALSE,
.request_resume_registration = 2065,
.unsol_network_info = 3001,
.request_set_call_indication = 2086,
.unsol_ps_network_state_changed = 3015,
.unsol_ims_registration_info = 3033,
.unsol_volte_eps_network_feature_support = 3048,
.unsol_emergency_bearer_support_notify = 3059,
.unsol_registration_suspended = 3024
.unsol_registration_suspended = 3024,
.unsol_incoming_call_indication = 3042,
.unsol_set_attach_apn = 3073
};
static inline struct ril_vendor_hook_mtk *ril_vendor_hook_mtk_cast
@@ -98,6 +122,12 @@ static inline struct ril_vendor_hook_mtk *ril_vendor_hook_mtk_cast
return G_CAST(hook, struct ril_vendor_hook_mtk, hook);
}
static inline struct ril_vendor_hook_mtk_auto *ril_vendor_hook_mtk_auto_cast
(struct ril_vendor_hook *hook)
{
return G_CAST(hook, struct ril_vendor_hook_mtk_auto, mtk.hook);
}
static const char *ril_vendor_mtk_request_to_string
(struct ril_vendor_hook *hook, guint request)
{
@@ -106,6 +136,24 @@ static const char *ril_vendor_mtk_request_to_string
if (request == msg->request_resume_registration) {
return "MTK_RESUME_REGISTRATION";
} else if (request == msg->request_set_call_indication) {
return "MTK_SET_CALL_INDICATION";
} else {
return NULL;
}
}
static const char *ril_vendor_mtk_unsol_msg_name(const struct ril_mtk_msg *msg,
guint event)
{
if (event == msg->unsol_ps_network_state_changed) {
return "MTK_PS_NETWORK_STATE_CHANGED";
} else if (event == msg->unsol_registration_suspended) {
return "MTK_REGISTRATION_SUSPENDED";
} else if (event == msg->unsol_set_attach_apn) {
return "MTK_SET_ATTACH_APN";
} else if (event == msg->unsol_incoming_call_indication) {
return "MTK_INCOMING_CALL_INDICATION";
} else {
return NULL;
}
@@ -115,25 +163,8 @@ static const char *ril_vendor_mtk_event_to_string(struct ril_vendor_hook *hook,
guint event)
{
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
const struct ril_mtk_msg *msg = self->msg;
if (event == msg->unsol_network_info) {
return "MTK_NETWORK_INFO";
} else if (event == msg->unsol_ps_network_state_changed) {
return "MTK_PS_NETWORK_STATE_CHANGED";
} else if (event == msg->unsol_registration_suspended) {
return "MTK_REGISTRATION_SUSPENDED";
} else if (event == msg->unsol_ims_registration_info) {
return "MTK_IMS_REGISTRATION_INFO";
} else if (event == msg->unsol_volte_eps_network_feature_support) {
return "MTK_VOLTE_EPS_NETWORK_FEATURE_SUPPORT";
} else if (event == msg->unsol_emergency_bearer_support_notify) {
return "MTK_EMERGENCY_BEARER_SUPPORT_NOTIFY";
} else if (event == msg->unsol_set_attach_apn) {
return "MTK_SET_ATTACH_APN";
} else {
return NULL;
}
return ril_vendor_mtk_unsol_msg_name(self->msg, event);
}
static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
@@ -148,7 +179,7 @@ static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, NULL) &&
grilio_parser_get_int32(&rilp, &session_id)) {
GRilIoRequest* req = grilio_request_new();
GRilIoRequest *req = grilio_request_new();
DBG("slot=%u,session_id=%d", self->slot, session_id);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, session_id);
@@ -158,70 +189,215 @@ static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
}
}
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
static GRilIoRequest *ril_vendor_mtk_build_set_attach_apn_req
(const struct ofono_gprs_primary_context *pc,
gboolean roamingProtocol)
{
GRilIoRequest *req = grilio_request_new();
const char *proto = ril_data_ofono_protocol_to_ril(pc->proto);
DBG("%s %d", pc->apn, roamingProtocol);
grilio_request_append_utf8(req, pc->apn); /* apn */
grilio_request_append_utf8(req, proto); /* protocol */
if (roamingProtocol) {
grilio_request_append_utf8(req, proto); /* roamingProtocol */
}
if (pc->username[0]) {
int auth;
switch (pc->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
auth = RIL_AUTH_BOTH;
break;
case OFONO_GPRS_AUTH_METHOD_NONE:
auth = RIL_AUTH_NONE;
break;
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = RIL_AUTH_CHAP;
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = RIL_AUTH_PAP;
break;
default:
auth = RIL_AUTH_NONE;
break;
}
grilio_request_append_int32(req, auth);
grilio_request_append_utf8(req, pc->username);
grilio_request_append_utf8(req, pc->password);
} else {
grilio_request_append_int32(req, RIL_AUTH_NONE);
grilio_request_append_utf8(req, "");
grilio_request_append_utf8(req, "");
}
grilio_request_append_utf8(req, ""); /* operatorNumeric */
grilio_request_append_int32(req, FALSE); /* canHandleIms */
grilio_request_append_int32(req, -1); /* dualApnPlmnList */
return req;
}
static const struct ofono_gprs_primary_context *ril_vendor_mtk_internet_context
(struct ril_vendor_hook_mtk *self)
{
struct sailfish_watch *watch = self->watch;
if (watch->imsi) {
struct ofono_atom *atom = __ofono_modem_find_atom(watch->modem,
OFONO_ATOM_TYPE_GPRS);
if (atom) {
return __ofono_gprs_context_settings_by_type
(__ofono_atom_get_data(atom),
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
}
}
return NULL;
}
static void ril_vendor_mtk_initial_attach_apn_resp(GRilIoChannel *io,
int ril_status, const void *data, guint len, void *user_data)
{
struct ril_vendor_hook_mtk *self = user_data;
struct sailfish_watch *watch = self->watch;
struct ofono_atom * gprs_atom = __ofono_modem_find_atom(watch->modem,
OFONO_ATOM_TYPE_GPRS);
struct ofono_gprs *gprs = gprs_atom ?
__ofono_atom_get_data(gprs_atom) : NULL;
const struct ofono_gprs_primary_context *pc =
(gprs && watch->imsi) ?
__ofono_gprs_context_settings_by_type(gprs,
OFONO_GPRS_CONTEXT_TYPE_INTERNET) : NULL;
/* authtype, username, password */
if (pc) {
GRilIoRequest *req = grilio_request_new();
const char *proto = ril_data_ofono_protocol_to_ril(pc->proto);
DBG("%s",pc->apn);
grilio_request_append_utf8(req, pc->apn); /* apn */
grilio_request_append_utf8(req, proto); /* protocol */
grilio_request_append_utf8(req, proto); /* roamingProtocol */
if (pc->username[0]) {
int auth;
switch (pc->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
auth = RIL_AUTH_BOTH;
break;
case OFONO_GPRS_AUTH_METHOD_NONE:
auth = RIL_AUTH_NONE;
break;
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = RIL_AUTH_CHAP;
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = RIL_AUTH_PAP;
break;
default:
auth = RIL_AUTH_NONE;
break;
}
grilio_request_append_int32(req, auth);
grilio_request_append_utf8(req, pc->username);
grilio_request_append_utf8(req, pc->password);
} else {
grilio_request_append_int32(req, RIL_AUTH_NONE);
grilio_request_append_utf8(req, "");
grilio_request_append_utf8(req, "");
}
grilio_request_append_utf8(req, ""); /* operatorNumeric */
grilio_request_append_int32(req, FALSE); /* canHandleIms */
grilio_request_append_int32(req, 0); /* Some sort of count */
grilio_queue_send_request(self->q, req,
RIL_REQUEST_SET_INITIAL_ATTACH_APN);
grilio_request_unref(req);
GASSERT(self->set_initial_attach_apn_id);
self->set_initial_attach_apn_id = 0;
if (ril_status == RIL_E_SUCCESS) {
DBG("ok");
self->initial_attach_apn_ok = TRUE;
}
}
static GRilIoRequest* ril_vendor_mtk_data_call_req
static void ril_vendor_mtk_initial_attach_apn_check
(struct ril_vendor_hook_mtk *self)
{
if (!self->set_initial_attach_apn_id && !self->initial_attach_apn_ok) {
const struct ofono_gprs_primary_context *pc =
ril_vendor_mtk_internet_context(self);
if (pc) {
GRilIoRequest *req =
ril_vendor_mtk_build_set_attach_apn_req(pc,
self->msg->attach_apn_has_roaming_protocol);
grilio_request_set_timeout(req,
SET_INITIAL_ATTACH_APN_TIMEOUT);
self->set_initial_attach_apn_id =
grilio_queue_send_request_full(self->q, req,
RIL_REQUEST_SET_INITIAL_ATTACH_APN,
ril_vendor_mtk_initial_attach_apn_resp,
NULL, self);
grilio_request_unref(req);
}
}
}
static void ril_vendor_mtk_initial_attach_apn_reset
(struct ril_vendor_hook_mtk *self)
{
self->initial_attach_apn_ok = FALSE;
if (self->set_initial_attach_apn_id) {
grilio_queue_cancel_request(self->q,
self->set_initial_attach_apn_id, FALSE);
self->set_initial_attach_apn_id = 0;
}
}
static void ril_vendor_mtk_watch_imsi_changed(struct sailfish_watch *watch,
void *user_data)
{
struct ril_vendor_hook_mtk *self = user_data;
if (watch->imsi) {
ril_vendor_mtk_initial_attach_apn_check(self);
} else {
ril_vendor_mtk_initial_attach_apn_reset(self);
}
}
static void ril_vendor_mtk_network_pref_mode_changed(struct ril_network *net,
void *user_data)
{
struct ril_vendor_hook_mtk *self = user_data;
if (net->pref_mode >= OFONO_RADIO_ACCESS_MODE_LTE) {
ril_vendor_mtk_initial_attach_apn_check(self);
} else {
ril_vendor_mtk_initial_attach_apn_reset(self);
}
}
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
const void *data, guint len, void *self)
{
ril_vendor_mtk_initial_attach_apn_check(self);
}
static void ril_vendor_mtk_ps_network_state_changed(GRilIoChannel *io,
guint id, const void *data, guint len, void *user_data)
{
struct ril_vendor_hook_mtk *self = user_data;
ril_network_query_registration_state(self->network);
}
static void ril_vendor_mtk_incoming_call_indication(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
{
struct ril_vendor_hook_mtk *self = user_data;
const struct ril_mtk_msg *msg = self->msg;
GRilIoRequest* req = NULL;
GASSERT(id == msg->unsol_incoming_call_indication);
if (msg->request_set_call_indication) {
int nparams, cid, seq;
gchar *call_id = NULL, *seq_no = NULL;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &nparams) && nparams >= 5 &&
(call_id = grilio_parser_get_utf8(&rilp)) != NULL &&
grilio_parser_skip_string(&rilp) /* number */ &&
grilio_parser_skip_string(&rilp) /* type */ &&
grilio_parser_skip_string(&rilp) /* call_mode */ &&
(seq_no = grilio_parser_get_utf8(&rilp)) != NULL &&
gutil_parse_int(call_id, 10, &cid) &&
gutil_parse_int(seq_no, 10, &seq)) {
DBG("slot=%u,cid=%d,seq=%d", self->slot, cid, seq);
req = grilio_request_new();
grilio_request_append_int32(req, 3); /* Param count */
/* mode - IMS_ALLOW_INCOMING_CALL_INDICATION: */
grilio_request_append_int32(req, 0);
grilio_request_append_int32(req, cid);
grilio_request_append_int32(req, seq);
} else {
DBG("failed to parse INCOMING_CALL_INDICATION");
}
g_free(call_id);
g_free(seq_no);
}
if (req) {
grilio_queue_send_request(self->q, req,
msg->request_set_call_indication);
grilio_request_unref(req);
} else {
/* Let ril_voicecall.c know that something happened */
grilio_channel_inject_unsol_event(io,
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
}
}
static GRilIoRequest *ril_vendor_mtk_data_call_req
(struct ril_vendor_hook *hook, int tech, const char *profile,
const char *apn, const char *username, const char *password,
enum ril_auth auth, const char *proto)
@@ -279,24 +455,24 @@ static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_vendor_hook *hook,
static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
{
/*
* With most Qualcomm RIL implementations, querying available band
* modes causes some magic Android properties to appear. Otherwise
* this request is pretty harmless and useless.
*
* Most MediaTek RIL implementations don't support this request and
* don't even bother to reply which slows things down because we wait
* for this request to complete at startup.
*/
defaults->query_available_band_mode = FALSE;
defaults->empty_pin_query = FALSE;
defaults->legacy_imei_query = TRUE;
}
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_from_data
(const void *driver_data, GRilIoChannel *io, const char *path,
const struct ril_slot_config *config)
static void ril_vendor_mtk_hook_subscribe(struct ril_vendor_hook_mtk *self)
{
const struct ril_vendor_mtk_driver_data *mtk_driver_data = driver_data;
const struct ril_mtk_msg *msg = mtk_driver_data->msg;
struct ril_vendor_hook_mtk *self =
g_new0(struct ril_vendor_hook_mtk, 1);
const struct ril_mtk_msg *msg = self->msg;
self->msg = msg;
self->q = grilio_queue_new(io);
self->io = grilio_channel_ref(io);
self->watch = sailfish_watch_new(path);
self->slot = config->slot;
self->ril_event_id[MTK_EVENT_REGISTRATION_SUSPENDED] =
grilio_channel_add_unsol_event_handler(self->io,
ril_vendor_mtk_registration_suspended,
@@ -307,8 +483,51 @@ static struct ril_vendor_hook *ril_vendor_mtk_create_hook_from_data
ril_vendor_mtk_set_attach_apn,
msg->unsol_set_attach_apn, self);
}
DBG("%s slot %u", mtk_driver_data->name, self->slot);
return ril_vendor_hook_init(&self->hook, mtk_driver_data->proc);
if (msg->unsol_ps_network_state_changed) {
self->ril_event_id[MTK_EVENT_PS_NETWORK_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(self->io,
ril_vendor_mtk_ps_network_state_changed,
msg->unsol_ps_network_state_changed, self);
}
if (msg->unsol_incoming_call_indication) {
self->ril_event_id[MTK_EVENT_INCOMING_CALL_INDICATION] =
grilio_channel_add_unsol_event_handler(self->io,
ril_vendor_mtk_incoming_call_indication,
msg->unsol_incoming_call_indication, self);
}
}
static void ril_vendor_mtk_hook_init(struct ril_vendor_hook_mtk *self,
const struct ril_vendor_mtk_driver_data *mtk_driver_data,
ril_vendor_hook_free_proc free, GRilIoChannel *io, const char *path,
const struct ril_slot_config *config, struct ril_network *network)
{
self->msg = mtk_driver_data->msg;
self->q = grilio_queue_new(io);
self->io = grilio_channel_ref(io);
self->watch = sailfish_watch_new(path);
self->slot = config->slot;
self->network = ril_network_ref(network);
self->watch_event_id[WATCH_EVENT_IMSI_CHANGED] =
sailfish_watch_add_imsi_changed_handler(self->watch,
ril_vendor_mtk_watch_imsi_changed, self);
self->network_event_id[NETWORK_EVENT_PREF_MODE_CHANGED] =
ril_network_add_pref_mode_changed_handler(self->network,
ril_vendor_mtk_network_pref_mode_changed, self);
ril_vendor_mtk_hook_subscribe(self);
ril_vendor_hook_init(&self->hook, mtk_driver_data->proc, free);
}
static void ril_vendor_mtk_destroy(struct ril_vendor_hook_mtk *self)
{
grilio_queue_cancel_all(self->q, FALSE);
grilio_channel_remove_all_handlers(self->io, self->ril_event_id);
grilio_queue_unref(self->q);
grilio_channel_unref(self->io);
sailfish_watch_remove_all_handlers(self->watch, self->watch_event_id);
sailfish_watch_unref(self->watch);
ril_network_remove_all_handlers(self->network, self->network_event_id);
ril_network_unref(self->network);
}
static void ril_vendor_mtk_free(struct ril_vendor_hook *hook)
@@ -316,16 +535,26 @@ static void ril_vendor_mtk_free(struct ril_vendor_hook *hook)
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
DBG("slot %u", self->slot);
grilio_queue_cancel_all(self->q, FALSE);
grilio_channel_remove_all_handlers(self->io, self->ril_event_id);
grilio_queue_unref(self->q);
grilio_channel_unref(self->io);
sailfish_watch_unref(self->watch);
ril_vendor_mtk_destroy(self);
g_free(self);
}
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_from_data
(const void *driver_data, GRilIoChannel *io, const char *path,
const struct ril_slot_config *config,
struct ril_network *network)
{
const struct ril_vendor_mtk_driver_data *mtk_driver_data = driver_data;
struct ril_vendor_hook_mtk *self =
g_new0(struct ril_vendor_hook_mtk, 1);
ril_vendor_mtk_hook_init(self, mtk_driver_data, ril_vendor_mtk_free,
io, path, config, network);
DBG("%s slot %u", mtk_driver_data->name, self->slot);
return &self->hook;
}
static const struct ril_vendor_hook_proc ril_vendor_mtk_hook_base_proc = {
.free = ril_vendor_mtk_free,
.request_to_string = ril_vendor_mtk_request_to_string,
.event_to_string = ril_vendor_mtk_event_to_string,
.data_call_req = ril_vendor_mtk_data_call_req
@@ -336,141 +565,127 @@ static const struct ril_vendor_driver ril_vendor_mtk_base = {
.create_hook = ril_vendor_mtk_create_hook_from_data
};
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk_mt6737_data = {
.name = "MT6737",
.msg = &mtk_msg_mt6737,
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk1_data = {
.name = "mtk1",
.msg = &msg_mtk1,
.proc = &ril_vendor_mtk_hook_base_proc
};
static struct ril_vendor_hook_proc ril_vendor_mtk_mt8735_proc = {
static struct ril_vendor_hook_proc ril_vendor_mtk2_proc = {
.base = &ril_vendor_mtk_hook_base_proc,
.data_call_parse = ril_vendor_mtk_data_call_parse_v6
};
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk_mt8735_data = {
.name = "MT8735",
.msg = &mtk_msg_mt8735,
.proc = &ril_vendor_mtk_mt8735_proc
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk2_data = {
.name = "mtk2",
.msg = &msg_mtk2,
.proc = &ril_vendor_mtk2_proc
};
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mt6737) {
.name = "mt6737t",
.driver_data = &ril_vendor_mtk_mt6737_data,
#define DEFAULT_MTK_TYPE (&ril_vendor_mtk1_data)
static const struct ril_vendor_mtk_driver_data *mtk_types [] = {
&ril_vendor_mtk1_data,
&ril_vendor_mtk2_data
};
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk1) {
.name = "mtk1",
.driver_data = &ril_vendor_mtk1_data,
.base = &ril_vendor_mtk_base
};
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mt8735) {
.name = "mt8735",
.driver_data = &ril_vendor_mtk_mt8735_data,
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk2) {
.name = "mtk2",
.driver_data = &ril_vendor_mtk2_data,
.base = &ril_vendor_mtk_base
};
#define DEFAULT_MTK_DRIVER (&ril_vendor_driver_mt6737)
/* Auto-selection */
static const struct ril_vendor_driver *mtk_hw_drivers [] = {
&ril_vendor_driver_mt6737,
&ril_vendor_driver_mt8735
};
/* Automatic driver selection based on /proc/cpuinfo */
static GString *ril_vendor_mtk_read_line(GString *buf, FILE *f)
static gboolean ril_vendor_mtk_auto_set_type
(struct ril_vendor_hook_mtk_auto *self,
const struct ril_vendor_mtk_driver_data *type)
{
int c = fgetc(f);
struct ril_vendor_hook_mtk *mtk = &self->mtk;
gboolean changed = FALSE;
g_string_truncate(buf, 0);
if (c != EOF) {
/* Read the line char by char until we hit EOF or EOL */
while (c != EOF && c != '\r' && c != '\n') {
g_string_append_c(buf, c);
c = fgetc(f);
}
/* Skip EOL characters */
while (c != EOF && (c == '\r' || c == '\n')) {
c = fgetc(f);
}
/* Unget the last char (the first char of the next line) */
if (c != EOF) {
ungetc(c, f);
}
return buf;
if (self->type != type) {
DBG("switching type %s -> %s", self->type->name, type->name);
self->type = type;
mtk->msg = type->msg;
mtk->hook.proc = type->proc;
grilio_channel_remove_all_handlers(mtk->io, mtk->ril_event_id);
ril_vendor_mtk_hook_subscribe(mtk);
changed = TRUE;
}
return NULL;
grilio_channel_remove_handler(mtk->io, self->detect_id);
self->detect_id = 0;
return changed;
}
static char *ril_vendor_mtk_hardware()
static void ril_vendor_mtk_auto_detect_event(GRilIoChannel *io, guint id,
const void *data, guint len, void *self)
{
FILE *f = fopen("/proc/cpuinfo", "r");
char *hardware = NULL;
guint i;
if (f) {
const char prefix[] = "Hardware\t:";
const gsize prefix_len = sizeof(prefix) - 1;
GString *buf = g_string_new("");
for (i = 0; i < G_N_ELEMENTS(mtk_types); i++) {
const struct ril_vendor_mtk_driver_data *type = mtk_types[i];
const struct ril_mtk_msg *msg = type->msg;
const guint *ids = &msg->unsol_msgs;
guint j;
/* Find the "Hardware:" line */
while (ril_vendor_mtk_read_line(buf, f) &&
strncmp(buf->str, prefix, prefix_len));
if (buf->len > prefix_len) {
/* Erase the prefix */
g_string_erase(buf, 0, prefix_len);
/* Remove trailing whitespaces */
while (buf->len > 0 &&
g_ascii_isspace(buf->str[buf->len - 1])) {
g_string_truncate(buf, buf->len - 1);
}
/* Extract the last word */
if (buf->len > 0) {
gsize pos = buf->len;
while (pos > 0 &&
!g_ascii_isspace(buf->str[pos - 1])) {
pos--;
}
if (buf->str[pos]) {
hardware = g_strdup(buf->str + pos);
DBG("Hardware: %s", hardware);
for (j = 0; j < MTK_UNSOL_MSGS; j++) {
if (ids[j] == id) {
DBG("event %u is %s %s", id, type->name,
ril_vendor_mtk_unsol_msg_name(msg,id));
if (ril_vendor_mtk_auto_set_type(self, type)) {
/* And repeat the event to invoke
* the handler */
grilio_channel_inject_unsol_event(io,
id, data, len);
}
return;
}
}
g_string_free(buf, TRUE);
fclose(f);
}
return hardware;
}
static const struct ril_vendor_driver *ril_vendor_mtk_detect()
static void ril_vendor_mtk_auto_free(struct ril_vendor_hook *hook)
{
const struct ril_vendor_driver *driver = DEFAULT_MTK_DRIVER;
char *hw = ril_vendor_mtk_hardware();
struct ril_vendor_hook_mtk_auto *self =
ril_vendor_hook_mtk_auto_cast(hook);
struct ril_vendor_hook_mtk *mtk = &self->mtk;
if (hw) {
guint i;
for (i = 0; i < G_N_ELEMENTS(mtk_hw_drivers); i++) {
if (!strcasecmp(mtk_hw_drivers[i]->name, hw)) {
driver = mtk_hw_drivers[i];
DBG("Driver: %s", driver->name);
break;
}
}
g_free(hw);
}
return driver;
DBG("slot %u", mtk->slot);
grilio_channel_remove_handler(mtk->io, self->detect_id);
ril_vendor_mtk_destroy(mtk);
g_free(self);
}
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_auto
(const void *driver_data, GRilIoChannel *io, const char *path,
const struct ril_slot_config *cfg)
(const void *driver_data, GRilIoChannel *io, const char *path,
const struct ril_slot_config *cfg, struct ril_network *network)
{
return ril_vendor_create_hook(ril_vendor_mtk_detect(), io, path, cfg);
struct ril_vendor_hook_mtk_auto *self =
g_new0(struct ril_vendor_hook_mtk_auto, 1);
struct ril_vendor_hook_mtk *mtk = &self->mtk;
/* Pick the default */
self->type = DEFAULT_MTK_TYPE;
ril_vendor_mtk_hook_init(mtk, self->type, ril_vendor_mtk_auto_free,
io, path, cfg, network);
DBG("%s slot %u", self->type->name, mtk->slot);
/*
* Subscribe for (all) unsolicited events. Keep on listening until
* we receive an MTK specific event that tells us which particular
* kind of MTK adaptation we are using.
*/
self->detect_id = grilio_channel_add_unsol_event_handler(mtk->io,
ril_vendor_mtk_auto_detect_event, 0, self);
return &mtk->hook;
}
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk) {

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -587,39 +587,75 @@ static void ril_voicecall_submit_hangup_req(struct ofono_voicecall *vc,
grilio_request_unref(ioreq);
}
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
static void ril_voicecall_hangup(struct ofono_voicecall *vc,
gboolean (*filter)(struct ofono_call *call),
ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ril_voicecall_request_data *req = NULL;
GSList *l;
if (vd->calls) {
GSList *l;
struct ril_voicecall_request_data *req =
ril_voicecall_request_data_new(vc, cb, data);
/*
* Here the idea is that we submit (potentially) multiple
* hangup requests to RIL and invoke the callback after
* the last request has completed (pending call count
* becomes zero).
*/
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
/*
* Here the idea is that we submit (potentially) multiple
* hangup requests to RIL and invoke the callback after
* the last request has completed (pending call count
* becomes zero).
*/
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
if (!filter || filter(call)) {
if (!req) {
req = ril_voicecall_request_data_new(vc, cb,
data);
}
/* Send request to RIL */
DBG("Hanging up call with id %d", call->id);
ril_voicecall_submit_hangup_req(vc, call->id, req);
} else {
DBG("Skipping call with id %d", call->id);
}
}
/* Release our reference */
if (req) {
/* Release our reference (if any) */
ril_voicecall_request_data_unref(req);
} else {
/* No calls */
/* No requests were submitted */
struct ofono_error error;
cb(ril_error_ok(&error), data);
}
}
static gboolean ril_voicecall_hangup_active_filter(struct ofono_call *call)
{
switch (call->status) {
case CALL_STATUS_ACTIVE:
case CALL_STATUS_DIALING:
case CALL_STATUS_ALERTING:
case CALL_STATUS_INCOMING:
return TRUE;
case CALL_STATUS_HELD:
case CALL_STATUS_WAITING:
case CALL_STATUS_DISCONNECTED:
break;
}
return FALSE;
}
static void ril_voicecall_hangup_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_hangup(vc, ril_voicecall_hangup_active_filter, cb, data);
}
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_hangup(vc, NULL, cb, data);
}
static void ril_voicecall_release_specific(struct ofono_voicecall *vc,
int id, ofono_voicecall_cb_t cb, void *data)
{
@@ -657,7 +693,7 @@ static void ril_voicecall_supp_svc_notification_event(GRilIoChannel *io,
grilio_parser_get_int32(&rilp, &type);
grilio_parser_get_int32(&rilp, &code);
grilio_parser_get_int32(&rilp, &index);
grilio_parser_get_int32(&rilp, NULL);
grilio_parser_get_int32(&rilp, &phone.type);
tmp = grilio_parser_get_utf8(&rilp);
if (tmp) {
@@ -811,8 +847,7 @@ 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, NULL, cb, data);
ril_voicecall_request(RIL_REQUEST_UDUB, vc, NULL, cb, data);
}
static void ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
@@ -946,6 +981,7 @@ const struct ofono_voicecall_driver ril_voicecall_driver = {
.remove = ril_voicecall_remove,
.dial = ril_voicecall_dial,
.answer = ril_voicecall_answer,
.hangup_active = ril_voicecall_hangup_active,
.hangup_all = ril_voicecall_hangup_all,
.release_specific = ril_voicecall_release_specific,
.send_tones = ril_voicecall_send_dtmf,

View File

@@ -0,0 +1,84 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __OFONO_GPRS_FILTER_H
#define __OFONO_GPRS_FILTER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ofono/types.h>
struct ofono_gprs;
struct ofono_gprs_context;
struct ofono_gprs_primary_context;
/* If ctx is NULL then activation gets cancelled */
typedef void (*ofono_gprs_filter_activate_cb_t)
(const struct ofono_gprs_primary_context *ctx, void *data);
typedef void (*ofono_gprs_filter_check_cb_t)(ofono_bool_t allow, void *data);
#define OFONO_GPRS_FILTER_PRIORITY_LOW (-100)
#define OFONO_GPRS_FILTER_PRIORITY_DEFAULT (0)
#define OFONO_GPRS_FILTER_PRIORITY_HIGH (100)
/*
* The api_version field makes it possible to keep using old plugins
* even if struct ofono_gprs_filter gets extended with new callbacks.
*/
#define OFONO_GPRS_FILTER_API_VERSION (1)
/*
* The filter callbacks either invoke the completion callback directly
* or return the id of the cancellable asynchronous operation (but never
* both). If non-zero value is returned, the completion callback has to
* be invoked later on a fresh stack. Once the asynchronous filtering
* operation is cancelled, the associated completion callback must not
* be invoked.
*
* Please avoid making blocking D-Bus calls from the filter callbacks.
*/
struct ofono_gprs_filter {
const char *name;
int api_version; /* OFONO_GPRS_FILTER_API_VERSION */
int priority;
void (*cancel)(unsigned int id);
unsigned int (*filter_activate)(struct ofono_gprs_context *gc,
const struct ofono_gprs_primary_context *ctx,
ofono_gprs_filter_activate_cb_t cb,
void *data);
/* API version 1 */
unsigned int (*filter_check)(struct ofono_gprs *gprs,
ofono_gprs_filter_check_cb_t cb, void *data);
};
int ofono_gprs_filter_register(const struct ofono_gprs_filter *filter);
void ofono_gprs_filter_unregister(const struct ofono_gprs_filter *filter);
#ifdef __cplusplus
}
#endif
#endif /* __OFONO_GPRS_FILTER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -83,6 +83,8 @@ void ofono_gprs_add_context(struct ofono_gprs *gprs,
void ofono_gprs_cid_activated(struct ofono_gprs *gprs, unsigned int cid,
const char *apn);
void ofono_gprs_attached_update(struct ofono_gprs *gprs);
#ifdef __cplusplus
}
#endif

View File

@@ -29,7 +29,9 @@ extern "C" {
#include <ofono/types.h>
struct ofono_modem;
struct ofono_gprs;
struct ofono_sim;
struct ofono_voicecall;
enum ofono_modem_type {
OFONO_MODEM_TYPE_HARDWARE = 0,
@@ -82,6 +84,8 @@ void ofono_modem_remove_interface(struct ofono_modem *modem,
const char *ofono_modem_get_path(struct ofono_modem *modem);
struct ofono_sim *ofono_modem_get_sim(struct ofono_modem *modem);
struct ofono_gprs *ofono_modem_get_gprs(struct ofono_modem *modem);
struct ofono_voicecall *ofono_modem_get_voicecall(struct ofono_modem *modem);
void ofono_modem_set_data(struct ofono_modem *modem, void *data);
void *ofono_modem_get_data(struct ofono_modem *modem);

View File

@@ -0,0 +1,284 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __OFONO_RIL_CONSTANTS_H
#define __OFONO_RIL_CONSTANTS_H
#ifdef __cplusplus
extern "C" {
#endif
/* Error Codes */
enum ril_status {
RIL_E_SUCCESS = 0,
RIL_E_RADIO_NOT_AVAILABLE = 1,
RIL_E_GENERIC_FAILURE = 2,
RIL_E_PASSWORD_INCORRECT = 3,
RIL_E_SIM_PIN2 = 4,
RIL_E_SIM_PUK2 = 5,
RIL_E_REQUEST_NOT_SUPPORTED = 6,
RIL_E_CANCELLED = 7,
RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
RIL_E_SMS_SEND_FAIL_RETRY = 10,
RIL_E_SIM_ABSENT = 11,
RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
RIL_E_MODE_NOT_SUPPORTED = 13,
RIL_E_FDN_CHECK_FAILURE = 14,
RIL_E_ILLEGAL_SIM_OR_ME = 15,
RIL_E_MISSING_RESOURCE = 16,
RIL_E_NO_SUCH_ELEMENT = 17,
RIL_E_DIAL_MODIFIED_TO_USSD = 18,
RIL_E_DIAL_MODIFIED_TO_SS = 19,
RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
RIL_E_USSD_MODIFIED_TO_DIAL = 21,
RIL_E_USSD_MODIFIED_TO_SS = 22,
RIL_E_USSD_MODIFIED_TO_USSD = 23,
RIL_E_SS_MODIFIED_TO_DIAL = 24,
RIL_E_SS_MODIFIED_TO_USSD = 25,
RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
RIL_E_SS_MODIFIED_TO_SS = 27,
RIL_E_LCE_NOT_SUPPORTED = 36,
RIL_E_NO_MEMORY = 37,
RIL_E_INTERNAL_ERR = 38,
RIL_E_SYSTEM_ERR = 39,
RIL_E_MODEM_ERR = 40,
RIL_E_INVALID_STATE = 41,
RIL_E_NO_RESOURCES = 42,
RIL_E_SIM_ERR = 43,
RIL_E_INVALID_ARGUMENTS = 44,
RIL_E_INVALID_SIM_STATE = 45,
RIL_E_INVALID_MODEM_STATE = 46,
RIL_E_INVALID_CALL_ID = 47,
RIL_E_NO_SMS_TO_ACK = 48,
RIL_E_NETWORK_ERR = 49,
RIL_E_REQUEST_RATE_LIMITED = 50,
RIL_E_SIM_BUSY = 51,
RIL_E_SIM_FULL = 52,
RIL_E_NETWORK_REJECT = 53,
RIL_E_OPERATION_NOT_ALLOWED = 54,
RIL_E_EMPTY_RECORD = 55,
RIL_E_INVALID_SMS_FORMAT = 56,
RIL_E_ENCODING_ERR = 57,
RIL_E_INVALID_SMSC_ADDRESS = 58,
RIL_E_NO_SUCH_ENTRY = 59,
RIL_E_NETWORK_NOT_READY = 60,
RIL_E_NOT_PROVISIONED = 61,
RIL_E_NO_SUBSCRIPTION = 62,
RIL_E_NO_NETWORK_FOUND = 63,
RIL_E_DEVICE_IN_USE = 64,
RIL_E_ABORTED = 65,
RIL_E_INVALID_RESPONSE = 66
};
/* RIL Request Messages, ofono -> rild */
#define RIL_REQUEST_GET_SIM_STATUS 1
#define RIL_REQUEST_ENTER_SIM_PIN 2
#define RIL_REQUEST_ENTER_SIM_PUK 3
#define RIL_REQUEST_ENTER_SIM_PIN2 4
#define RIL_REQUEST_ENTER_SIM_PUK2 5
#define RIL_REQUEST_CHANGE_SIM_PIN 6
#define RIL_REQUEST_CHANGE_SIM_PIN2 7
#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
#define RIL_REQUEST_GET_CURRENT_CALLS 9
#define RIL_REQUEST_DIAL 10
#define RIL_REQUEST_GET_IMSI 11
#define RIL_REQUEST_HANGUP 12
#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
#define RIL_REQUEST_CONFERENCE 16
#define RIL_REQUEST_UDUB 17
#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
#define RIL_REQUEST_SIGNAL_STRENGTH 19
#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
#define RIL_REQUEST_OPERATOR 22
#define RIL_REQUEST_RADIO_POWER 23
#define RIL_REQUEST_DTMF 24
#define RIL_REQUEST_SEND_SMS 25
#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
#define RIL_REQUEST_SETUP_DATA_CALL 27
#define RIL_REQUEST_SIM_IO 28
#define RIL_REQUEST_SEND_USSD 29
#define RIL_REQUEST_CANCEL_USSD 30
#define RIL_REQUEST_GET_CLIR 31
#define RIL_REQUEST_SET_CLIR 32
#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
#define RIL_REQUEST_SET_CALL_FORWARD 34
#define RIL_REQUEST_QUERY_CALL_WAITING 35
#define RIL_REQUEST_SET_CALL_WAITING 36
#define RIL_REQUEST_SMS_ACKNOWLEDGE 37
#define RIL_REQUEST_GET_IMEI 38
#define RIL_REQUEST_GET_IMEISV 39
#define RIL_REQUEST_ANSWER 40
#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
#define RIL_REQUEST_SET_FACILITY_LOCK 43
#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
#define RIL_REQUEST_DTMF_START 49
#define RIL_REQUEST_DTMF_STOP 50
#define RIL_REQUEST_BASEBAND_VERSION 51
#define RIL_REQUEST_SEPARATE_CONNECTION 52
#define RIL_REQUEST_SET_MUTE 53
#define RIL_REQUEST_GET_MUTE 54
#define RIL_REQUEST_QUERY_CLIP 55
#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
#define RIL_REQUEST_DATA_CALL_LIST 57
#define RIL_REQUEST_RESET_RADIO 58
#define RIL_REQUEST_OEM_HOOK_RAW 59
#define RIL_REQUEST_OEM_HOOK_STRINGS 60
#define RIL_REQUEST_SCREEN_STATE 61
#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
#define RIL_REQUEST_SET_BAND_MODE 65
#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
#define RIL_REQUEST_STK_GET_PROFILE 67
#define RIL_REQUEST_STK_SET_PROFILE 68
#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
#define RIL_REQUEST_SET_LOCATION_UPDATES 76
#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
#define RIL_REQUEST_SET_TTY_MODE 80
#define RIL_REQUEST_QUERY_TTY_MODE 81
#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
#define RIL_REQUEST_CDMA_FLASH 84
#define RIL_REQUEST_CDMA_BURST_DTMF 85
#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
#define RIL_REQUEST_CDMA_SEND_SMS 87
#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
#define RIL_REQUEST_DEVICE_IDENTITY 98
#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
#define RIL_REQUEST_GET_SMSC_ADDRESS 100
#define RIL_REQUEST_SET_SMSC_ADDRESS 101
#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
#define RIL_REQUEST_ISIM_AUTHENTICATION 105
#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
#define RIL_REQUEST_VOICE_RADIO_TECH 108
#define RIL_REQUEST_GET_CELL_INFO_LIST 109
#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
#define RIL_REQUEST_IMS_SEND_SMS 113
#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
#define RIL_REQUEST_NV_READ_ITEM 118
#define RIL_REQUEST_NV_WRITE_ITEM 119
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
#define RIL_REQUEST_NV_RESET_CONFIG 121
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
#define RIL_REQUEST_ALLOW_DATA 123
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
#define RIL_REQUEST_SIM_AUTHENTICATION 125
#define RIL_REQUEST_GET_DC_RT_INFO 126
#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
#define RIL_REQUEST_SET_DATA_PROFILE 128
#define RIL_REQUEST_SHUTDOWN 129
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
/* RIL Unsolicited Messages, rild -> ofono */
#define RIL_UNSOL_RESPONSE_BASE 1000
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
#define RIL_UNSOL_ON_USSD 1006
#define RIL_UNSOL_ON_USSD_REQUEST 1007
#define RIL_UNSOL_NITZ_TIME_RECEIVED 1008
#define RIL_UNSOL_SIGNAL_STRENGTH 1009
#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
#define RIL_UNSOL_STK_SESSION_END 1012
#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
#define RIL_UNSOL_STK_CALL_SETUP 1015
#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
#define RIL_UNSOL_SIM_REFRESH 1017
#define RIL_UNSOL_CALL_RING 1018
#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
#define RIL_UNSOL_CDMA_CALL_WAITING 1025
#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
#define RIL_UNSOL_CDMA_INFO_REC 1027
#define RIL_UNSOL_OEM_HOOK_RAW 1028
#define RIL_UNSOL_RINGBACK_TONE 1029
#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
#define RIL_UNSOL_RIL_CONNECTED 1034
#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
#define RIL_UNSOL_CELL_INFO_LIST 1036
#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
#define RIL_UNSOL_RADIO_CAPABILITY 1042
#define RIL_UNSOL_ON_SS 1043
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
/* A special request, ofono -> rild */
#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
#ifdef __cplusplus
}
#endif
#endif /* __OFONO_RIL_CONSTANTS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,64 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __OFONO_RIL_TRANSPORT_H
#define __OFONO_RIL_TRANSPORT_H
#include <ofono/types.h>
#include <glib.h>
#ifdef __cplusplus
extern "C" {
#endif
struct grilio_transport;
/*
* The api_version field makes it possible to keep using old plugins
* even if struct ofono_ril_transport gets extended with new callbacks.
*/
#define OFONO_RIL_TRANSPORT_API_VERSION (0)
/*
* The connect callback takes a (char*) -> (char*) hashtable containing
* transport-specific connection parameters. The caller receives a reference
* i.e. it has to unref the returned object.
*/
struct ofono_ril_transport {
const char *name;
int api_version; /* OFONO_RIL_TRANSPORT_API_VERSION */
struct grilio_transport *(*connect)(GHashTable *params);
};
int ofono_ril_transport_register(const struct ofono_ril_transport *t);
void ofono_ril_transport_unregister(const struct ofono_ril_transport *t);
struct grilio_transport *ofono_ril_transport_connect(const char *name,
GHashTable *params);
#ifdef __cplusplus
}
#endif
#endif /* __OFONO_RIL_TRANSPORT_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -56,6 +56,7 @@ enum ofono_error_type {
OFONO_ERROR_TYPE_CEER,
OFONO_ERROR_TYPE_SIM,
OFONO_ERROR_TYPE_FAILURE,
OFONO_ERROR_TYPE_ERRNO
};
enum ofono_disconnect_reason {
@@ -70,16 +71,6 @@ struct ofono_error {
int error;
};
#define OFONO_EINVAL(error) do { \
error->type = OFONO_ERROR_TYPE_FAILURE; \
error->error = -EINVAL; \
} while (0)
#define OFONO_NO_ERROR(error) do { \
error->type = OFONO_ERROR_TYPE_NO_ERROR; \
error->error = 0; \
} while (0)
#define OFONO_MAX_PHONE_NUMBER_LENGTH 80
#define OFONO_MAX_CALLER_NAME_LENGTH 80

View File

@@ -0,0 +1,128 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __OFONO_VOICECALL_FILTER_H
#define __OFONO_VOICECALL_FILTER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ofono/voicecall.h>
/* 27.007 Section 7.6 */
enum ofono_clip_validity {
OFONO_CLIP_VALIDITY_VALID = 0,
OFONO_CLIP_VALIDITY_WITHHELD,
OFONO_CLIP_VALIDITY_NOT_AVAILABLE
};
/* 27.007 Section 7.18 */
enum ofono_call_status {
OFONO_CALL_STATUS_ACTIVE = 0,
OFONO_CALL_STATUS_HELD,
OFONO_CALL_STATUS_DIALING,
OFONO_CALL_STATUS_ALERTING,
OFONO_CALL_STATUS_INCOMING,
OFONO_CALL_STATUS_WAITING,
OFONO_CALL_STATUS_DISCONNECTED
};
/* 27.007 Section 7.18 */
enum ofono_call_direction {
OFONO_CALL_DIRECTION_MOBILE_ORIGINATED = 0,
OFONO_CALL_DIRECTION_MOBILE_TERMINATED
};
/* 27.007 Section 7.30 */
enum ofono_cnap_validity {
OFONO_CNAP_VALIDITY_VALID = 0,
OFONO_CNAP_VALIDITY_WITHHELD,
OFONO_CNAP_VALIDITY_NOT_AVAILABLE
};
enum ofono_voicecall_filter_dial_result {
OFONO_VOICECALL_FILTER_DIAL_CONTINUE, /* Run the next filter */
OFONO_VOICECALL_FILTER_DIAL_BLOCK /* Don't dial*/
};
enum ofono_voicecall_filter_incoming_result {
OFONO_VOICECALL_FILTER_INCOMING_CONTINUE, /* Run the next filter */
OFONO_VOICECALL_FILTER_INCOMING_HANGUP, /* Hangup incoming call */
OFONO_VOICECALL_FILTER_INCOMING_IGNORE /* Ignore incoming call */
};
typedef void (*ofono_voicecall_filter_dial_cb_t)
(enum ofono_voicecall_filter_dial_result result,
void *data);
typedef void (*ofono_voicecall_filter_incoming_cb_t)
(enum ofono_voicecall_filter_incoming_result result,
void *data);
#define OFONO_VOICECALL_FILTER_PRIORITY_LOW (-100)
#define OFONO_VOICECALL_FILTER_PRIORITY_DEFAULT (0)
#define OFONO_VOICECALL_FILTER_PRIORITY_HIGH (100)
/*
* The api_version field makes it possible to keep using old plugins
* even if struct ofono_voicecall_filter gets extended with new callbacks.
*/
#define OFONO_VOICECALL_FILTER_API_VERSION (0)
/*
* The filter callbacks either invoke the completion callback directly
* or return the id of the cancellable asynchronous operation (but never
* both). If non-zero value is returned, the completion callback has to
* be invoked later on a fresh stack. Once the asynchronous filtering
* operation is cancelled, the associated completion callback must not
* be invoked.
*
* Please avoid making blocking D-Bus calls from the filter callbacks.
*/
struct ofono_voicecall_filter {
const char *name;
int api_version; /* OFONO_VOICECALL_FILTER_API_VERSION */
int priority;
void (*filter_cancel)(unsigned int id);
unsigned int (*filter_dial)(struct ofono_voicecall *vc,
const struct ofono_phone_number *number,
enum ofono_clir_option clir,
ofono_voicecall_filter_dial_cb_t cb,
void *data);
unsigned int (*filter_incoming)(struct ofono_voicecall *vc,
const struct ofono_call *call,
ofono_voicecall_filter_incoming_cb_t cb,
void *data);
};
void ofono_voicecall_filter_notify(struct ofono_voicecall *vc);
int ofono_voicecall_filter_register(const struct ofono_voicecall_filter *f);
void ofono_voicecall_filter_unregister(const struct ofono_voicecall_filter *f);
#ifdef __cplusplus
}
#endif
#endif /* __OFONO_VOICECALL_FILTER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -153,6 +153,8 @@ void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id,
*/
void ofono_voicecall_mpty_hint(struct ofono_voicecall *vc, unsigned int ids);
struct ofono_modem *ofono_voicecall_get_modem(struct ofono_voicecall *vc);
int ofono_voicecall_driver_register(const struct ofono_voicecall_driver *d);
void ofono_voicecall_driver_unregister(const struct ofono_voicecall_driver *d);

View File

@@ -96,7 +96,7 @@ static DBusMessage *push_notification_register_agent(DBusConnection *conn,
DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
if (!__ofono_dbus_valid_object_path(agent_path))
if (!dbus_validate_path(agent_path, NULL))
return __ofono_error_invalid_format(msg);
pn->agent = sms_agent_new(AGENT_INTERFACE,

View File

@@ -461,6 +461,8 @@ static void sailfish_watch_set_modem(struct sailfish_watch *self,
if (modem) {
sailfish_watch_setup_modem(self);
}
sailfish_watch_online_update(self,
ofono_modem_get_online(self->modem));
sailfish_watch_emit_queued_signals(self);
}
}

View File

@@ -119,7 +119,7 @@ static DBusMessage *smart_messaging_register_agent(DBusConnection *conn,
DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
if (!__ofono_dbus_valid_object_path(agent_path))
if (!dbus_validate_path(agent_path, NULL))
return __ofono_error_invalid_format(msg);
sm->agent = sms_agent_new(AGENT_INTERFACE,

View File

@@ -56,7 +56,7 @@ static void __ofono_dbus_queue_req_complete
(struct ofono_dbus_queue_request *req,
ofono_dbus_cb_t fn, void *param)
{
DBusMessage *reply = fn(req->msg, param);
DBusMessage *reply = fn ? fn(req->msg, param) : NULL;
if (!reply)
reply = __ofono_error_failed(req->msg);
@@ -129,11 +129,13 @@ void __ofono_dbus_queue_reply_msg(struct ofono_dbus_queue *q,
if (!q || !q->requests) {
/* This should never happen */
dbus_message_unref(reply);
if (reply) {
dbus_message_unref(reply);
}
return;
}
/* De-queue the request */
/* De-queue one request */
done = q->requests;
next = done->next;
q->requests = next;
@@ -148,8 +150,19 @@ void __ofono_dbus_queue_reply_msg(struct ofono_dbus_queue *q,
__ofono_dbus_queue_req_free(done);
/* Submit the next request if there is any */
if (next) {
next->fn(next->msg, next->data);
while (next && reply) {
reply = next->fn(next->msg, next->data);
if (reply) {
/* The request has completed synchronously */
done = next;
next = done->next;
q->requests = next;
done->next = NULL;
/* Send the reply */
__ofono_dbus_pending_reply(&done->msg, reply);
__ofono_dbus_queue_req_free(done);
}
}
}
@@ -190,7 +203,8 @@ void __ofono_dbus_queue_reply_all_fn(struct ofono_dbus_queue *q,
ofono_dbus_reply_cb_t fn)
{
__ofono_dbus_queue_reply_all_fn_param(q,
__ofono_dbus_queue_reply_all_wrapper, fn);
__ofono_dbus_queue_reply_all_wrapper,
fn ? fn : __ofono_error_failed);
}
void __ofono_dbus_queue_reply_all_fn_param(struct ofono_dbus_queue *q,

View File

@@ -24,6 +24,7 @@
#endif
#include <glib.h>
#include <errno.h>
#include <gdbus.h>
#include "ofono.h"
@@ -37,7 +38,7 @@ struct error_mapping_entry {
DBusMessage *(*ofono_error_func)(DBusMessage *);
};
struct error_mapping_entry cme_errors_mapping[] = {
static const struct error_mapping_entry cme_errors_mapping[] = {
{ 3, __ofono_error_not_allowed },
{ 4, __ofono_error_not_supported },
{ 16, __ofono_error_incorrect_password },
@@ -45,6 +46,16 @@ struct error_mapping_entry cme_errors_mapping[] = {
{ 31, __ofono_error_timed_out },
{ 32, __ofono_error_access_denied },
{ 50, __ofono_error_invalid_args },
{ }
};
static const struct error_mapping_entry errno_errors_mapping[] = {
{ EACCES, __ofono_error_access_denied },
{ EOPNOTSUPP, __ofono_error_not_supported },
{ ENOSYS, __ofono_error_not_implemented },
{ ETIMEDOUT, __ofono_error_timed_out },
{ EINPROGRESS, __ofono_error_busy },
{ }
};
static void append_variant(DBusMessageIter *iter,
@@ -419,26 +430,31 @@ DBusMessage *__ofono_error_network_terminated(DBusMessage *msg)
" network");
}
static DBusMessage *__ofono_map_error(const struct error_mapping_entry *map,
int error, DBusMessage *msg)
{
const struct error_mapping_entry *e;
for (e = map; e->ofono_error_func; e++)
if (e->error == error)
return e->ofono_error_func(msg);
return __ofono_error_failed(msg);
}
DBusMessage *__ofono_error_from_error(const struct ofono_error *error,
DBusMessage *msg)
{
struct error_mapping_entry *e;
int maxentries;
int i;
switch (error->type) {
case OFONO_ERROR_TYPE_CME:
e = cme_errors_mapping;
maxentries = sizeof(cme_errors_mapping) /
sizeof(struct error_mapping_entry);
for (i = 0; i < maxentries; i++)
if (e[i].error == error->error)
return e[i].ofono_error_func(msg);
break;
return __ofono_map_error(cme_errors_mapping, error->error, msg);
case OFONO_ERROR_TYPE_CMS:
return __ofono_error_failed(msg);
case OFONO_ERROR_TYPE_CEER:
return __ofono_error_failed(msg);
case OFONO_ERROR_TYPE_ERRNO:
return __ofono_map_error(errno_errors_mapping,
ABS(error->error), msg);
default:
return __ofono_error_failed(msg);
}
@@ -456,50 +472,6 @@ void __ofono_dbus_pending_reply(DBusMessage **msg, DBusMessage *reply)
*msg = NULL;
}
gboolean __ofono_dbus_valid_object_path(const char *path)
{
unsigned int i;
char c = '\0';
if (path == NULL)
return FALSE;
if (path[0] == '\0')
return FALSE;
if (path[0] && !path[1] && path[0] == '/')
return TRUE;
if (path[0] != '/')
return FALSE;
for (i = 0; path[i]; i++) {
if (path[i] == '/' && c == '/')
return FALSE;
c = path[i];
if (path[i] >= 'a' && path[i] <= 'z')
continue;
if (path[i] >= 'A' && path[i] <= 'Z')
continue;
if (path[i] >= '0' && path[i] <= '9')
continue;
if (path[i] == '_' || path[i] == '/')
continue;
return FALSE;
}
if (path[i-1] == '/')
return FALSE;
return TRUE;
}
DBusConnection *ofono_dbus_get_connection(void)
{
return g_connection;

View File

@@ -1347,6 +1347,7 @@ void ofono_emulator_send_final(struct ofono_emulator *em,
case OFONO_ERROR_TYPE_CEER:
case OFONO_ERROR_TYPE_SIM:
case OFONO_ERROR_TYPE_FAILURE:
case OFONO_ERROR_TYPE_ERRNO:
failure:
g_at_server_send_final(em->server, G_AT_SERVER_RESULT_ERROR);
break;

View File

@@ -135,7 +135,7 @@ static DBusMessage *gnss_register_agent(DBusConnection *conn,
&agent_path, DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
if (!__ofono_dbus_valid_object_path(agent_path))
if (!dbus_validate_path(agent_path, NULL))
return __ofono_error_invalid_format(msg);
gnss->posr_agent = gnss_agent_new(agent_path,

548
ofono/src/gprs-filter.c Normal file
View File

@@ -0,0 +1,548 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ofono.h"
#include <errno.h>
#include <string.h>
struct gprs_filter_request;
struct gprs_filter_request_fn {
const char *name;
gboolean (*can_process)(const struct ofono_gprs_filter *filter);
guint (*process)(const struct ofono_gprs_filter *filter,
struct gprs_filter_request *req);
void (*complete)(struct gprs_filter_request *req, gboolean allow);
void (*free)(struct gprs_filter_request *req);
};
struct gprs_filter_request {
int refcount;
struct gprs_filter_chain *chain;
struct ofono_gprs_context *gc;
const struct gprs_filter_request_fn *fn;
GSList *filter_link;
guint pending_id;
guint next_id;
ofono_destroy_func destroy;
void* user_data;
};
struct gprs_filter_request_activate {
struct gprs_filter_request req;
struct ofono_gprs_primary_context ctx;
gprs_filter_activate_cb_t cb;
};
struct gprs_filter_request_check {
struct gprs_filter_request req;
ofono_gprs_filter_check_cb_t cb;
};
struct gprs_filter_chain {
struct ofono_gprs *gprs;
GSList *req_list;
};
static GSList *gprs_filter_list = NULL;
static void gprs_filter_request_init(struct gprs_filter_request *req,
const struct gprs_filter_request_fn *fn,
struct gprs_filter_chain *chain, struct ofono_gprs_context *gc,
ofono_destroy_func destroy, void *user_data)
{
req->chain = chain;
req->fn = fn;
req->gc = gc;
req->filter_link = gprs_filter_list;
req->destroy = destroy;
req->user_data = user_data;
/*
* The list holds an implicit reference to the message. The reference
* is released by gprs_filter_request_free when the message is removed
* from the list.
*/
req->refcount = 1;
chain->req_list = g_slist_append(chain->req_list, req);
}
static void gprs_filter_request_cancel(struct gprs_filter_request *req)
{
if (req->pending_id) {
const struct ofono_gprs_filter *f = req->filter_link->data;
/*
* If the filter returns id of the pending operation,
* then it must provide the cancel callback
*/
f->cancel(req->pending_id);
req->pending_id = 0;
}
if (req->next_id) {
g_source_remove(req->next_id);
req->next_id = 0;
}
}
static void gprs_filter_request_dispose(struct gprs_filter_request *req)
{
/* May be invoked several times per request */
if (req->destroy) {
ofono_destroy_func destroy = req->destroy;
req->destroy = NULL;
destroy(req->user_data);
}
}
static void gprs_filter_request_free(struct gprs_filter_request *req)
{
gprs_filter_request_dispose(req);
req->fn->free(req);
}
#define gprs_filter_request_ref(req) ((req)->refcount++, req)
static int gprs_filter_request_unref(struct gprs_filter_request *req)
{
const int refcount = --(req->refcount);
if (!refcount) {
gprs_filter_request_free(req);
}
return refcount;
}
static void gprs_filter_request_free1(gpointer data)
{
struct gprs_filter_request *req = data;
/*
* This is a g_slist_free_full() callback for use by
* __ofono_gprs_filter_chain_free(), meaning that the
* chain is no more. Zero the pointer to it in case if
* this is not the last reference.
*/
req->chain = NULL;
gprs_filter_request_unref(req);
}
static void gprs_filter_request_dequeue(struct gprs_filter_request *req)
{
struct gprs_filter_chain *chain = req->chain;
GSList *l;
/*
* Single-linked list is not particularly good at searching
* and removing the elements but since it should be pretty
* short (typically just one request), it's not worth optimization.
*/
if (chain && (l = g_slist_find(chain->req_list, req)) != NULL) {
gprs_filter_request_free1(l->data);
chain->req_list = g_slist_delete_link(chain->req_list, l);
}
}
static void gprs_filter_request_complete(struct gprs_filter_request *req,
gboolean allow)
{
gprs_filter_request_ref(req);
req->fn->complete(req, allow);
gprs_filter_request_dispose(req);
gprs_filter_request_dequeue(req);
gprs_filter_request_unref(req);
}
static void gprs_filter_request_process(struct gprs_filter_request *req)
{
GSList *l = req->filter_link;
const struct ofono_gprs_filter *f = l->data;
const struct gprs_filter_request_fn *fn = req->fn;
while (f && !fn->can_process(f)) {
l = l->next;
f = l ? l->data : NULL;
}
gprs_filter_request_ref(req);
if (f) {
req->filter_link = l;
req->pending_id = fn->process(f, req);
} else {
gprs_filter_request_complete(req, TRUE);
}
gprs_filter_request_unref(req);
}
static void gprs_filter_request_next(struct gprs_filter_request *req,
GSourceFunc fn)
{
req->pending_id = 0;
req->next_id = g_idle_add(fn, req);
}
static gboolean gprs_filter_request_continue_cb(gpointer data)
{
struct gprs_filter_request *req = data;
req->next_id = 0;
req->filter_link = req->filter_link->next;
if (req->filter_link) {
gprs_filter_request_process(req);
} else {
gprs_filter_request_complete(req, TRUE);
}
return G_SOURCE_REMOVE;
}
static gboolean gprs_filter_request_disallow_cb(gpointer data)
{
struct gprs_filter_request *req = data;
req->next_id = 0;
gprs_filter_request_complete(req, FALSE);
return G_SOURCE_REMOVE;
}
/*==========================================================================*
* gprs_filter_request_activate
*==========================================================================*/
static void gprs_filter_copy_context(struct ofono_gprs_primary_context *dest,
const struct ofono_gprs_primary_context *src)
{
dest->cid = src->cid;
dest->proto = src->proto;
dest->auth_method = src->auth_method;
strncpy(dest->apn, src->apn, OFONO_GPRS_MAX_APN_LENGTH);
strncpy(dest->username, src->username, OFONO_GPRS_MAX_USERNAME_LENGTH);
strncpy(dest->password, src->password, OFONO_GPRS_MAX_PASSWORD_LENGTH);
dest->apn[OFONO_GPRS_MAX_APN_LENGTH] = 0;
dest->username[OFONO_GPRS_MAX_USERNAME_LENGTH] = 0;
dest->password[OFONO_GPRS_MAX_PASSWORD_LENGTH] = 0;
}
static struct gprs_filter_request_activate *gprs_filter_request_activate_cast
(struct gprs_filter_request *req)
{
return (struct gprs_filter_request_activate *)req;
}
static gboolean gprs_filter_request_activate_can_process
(const struct ofono_gprs_filter *f)
{
return f->filter_activate != NULL;
}
static void gprs_filter_request_activate_cb
(const struct ofono_gprs_primary_context *ctx, void *data)
{
struct gprs_filter_request_activate *act = data;
struct gprs_filter_request *req = &act->req;
const struct ofono_gprs_filter *filter = req->filter_link->data;
if (ctx) {
if (ctx != &act->ctx) {
/* The filter may have updated context settings */
gprs_filter_copy_context(&act->ctx, ctx);
}
gprs_filter_request_next(req, gprs_filter_request_continue_cb);
} else {
DBG("%s not allowing to activate mobile data", filter->name);
gprs_filter_request_next(req, gprs_filter_request_disallow_cb);
}
}
static guint gprs_filter_request_activate_process
(const struct ofono_gprs_filter *f,
struct gprs_filter_request *req)
{
struct gprs_filter_request_activate *act =
gprs_filter_request_activate_cast(req);
return f->filter_activate(req->gc, &act->ctx,
gprs_filter_request_activate_cb, act);
}
static void gprs_filter_request_activate_complete
(struct gprs_filter_request *req, gboolean allow)
{
struct gprs_filter_request_activate *act =
gprs_filter_request_activate_cast(req);
act->cb(allow ? &act->ctx : NULL, req->user_data);
}
static void gprs_filter_request_activate_free(struct gprs_filter_request *req)
{
g_slice_free1(sizeof(struct gprs_filter_request_activate), req);
}
static struct gprs_filter_request *gprs_filter_request_activate_new
(struct gprs_filter_chain *chain, struct ofono_gprs_context *gc,
const struct ofono_gprs_primary_context *ctx,
gprs_filter_activate_cb_t cb, ofono_destroy_func destroy,
void *data)
{
static const struct gprs_filter_request_fn activate_fn = {
.name = "activate",
.can_process = gprs_filter_request_activate_can_process,
.process = gprs_filter_request_activate_process,
.complete = gprs_filter_request_activate_complete,
.free = gprs_filter_request_activate_free
};
struct gprs_filter_request_activate *act =
g_slice_new0(struct gprs_filter_request_activate);
struct gprs_filter_request *req = &act->req;
gprs_filter_request_init(req, &activate_fn, chain, gc, destroy, data);
gprs_filter_copy_context(&act->ctx, ctx);
act->cb = cb;
return req;
}
/*==========================================================================*
* gprs_filter_request_check
*==========================================================================*/
static struct gprs_filter_request_check *gprs_filter_request_check_cast
(struct gprs_filter_request *req)
{
return (struct gprs_filter_request_check *)req;
}
static gboolean gprs_filter_request_check_can_process
(const struct ofono_gprs_filter *f)
{
return f->api_version >= 1 && f->filter_check != NULL;
}
static void gprs_filter_request_check_cb(ofono_bool_t allow, void *data)
{
struct gprs_filter_request_check *check = data;
struct gprs_filter_request *req = &check->req;
const struct ofono_gprs_filter *filter = req->filter_link->data;
if (allow) {
gprs_filter_request_next(req, gprs_filter_request_continue_cb);
} else {
DBG("%s not allowing mobile data", filter->name);
gprs_filter_request_next(req, gprs_filter_request_disallow_cb);
}
}
static guint gprs_filter_request_check_process
(const struct ofono_gprs_filter *f,
struct gprs_filter_request *req)
{
return f->filter_check(req->chain->gprs, gprs_filter_request_check_cb,
gprs_filter_request_check_cast(req));
}
static void gprs_filter_request_check_complete
(struct gprs_filter_request *req, gboolean allow)
{
gprs_filter_request_check_cast(req)->cb(allow, req->user_data);
}
static void gprs_filter_request_check_free(struct gprs_filter_request *req)
{
g_slice_free1(sizeof(struct gprs_filter_request_check), req);
}
static struct gprs_filter_request *gprs_filter_request_check_new
(struct gprs_filter_chain *chain, gprs_filter_check_cb_t cb,
ofono_destroy_func destroy, void *data)
{
static const struct gprs_filter_request_fn check_fn = {
.name = "check",
.can_process = gprs_filter_request_check_can_process,
.process = gprs_filter_request_check_process,
.complete = gprs_filter_request_check_complete,
.free = gprs_filter_request_check_free
};
struct gprs_filter_request_check *check =
g_slice_new0(struct gprs_filter_request_check);
struct gprs_filter_request *req = &check->req;
gprs_filter_request_init(req, &check_fn, chain, NULL, destroy, data);
check->cb = cb;
return req;
}
/*==========================================================================*
* gprs_filter_chain
*==========================================================================*/
struct gprs_filter_chain *__ofono_gprs_filter_chain_new(struct ofono_gprs *gp)
{
struct gprs_filter_chain *chain = NULL;
if (gp) {
chain = g_new0(struct gprs_filter_chain, 1);
chain->gprs = gp;
}
return chain;
}
void __ofono_gprs_filter_chain_free(struct gprs_filter_chain *chain)
{
if (chain) {
__ofono_gprs_filter_chain_cancel(chain, NULL);
g_free(chain);
}
}
void __ofono_gprs_filter_chain_cancel(struct gprs_filter_chain *chain,
struct ofono_gprs_context *gc)
{
if (chain) {
GSList *l, *canceled;
/* Move canceled requests to a separate list */
if (gc) {
GSList *prev = NULL;
canceled = NULL;
l = chain->req_list;
while (l) {
GSList *next = l->next;
struct gprs_filter_request *req = l->data;
if (req->gc == gc) {
/* This one will get canceled */
l->next = canceled;
canceled = l;
if (prev) {
prev->next = next;
} else {
chain->req_list = next;
}
} else {
/* This one survives */
prev = l;
}
l = next;
}
} else {
/* Everything is getting canceled */
canceled = chain->req_list;
chain->req_list = NULL;
}
/* Actually cancel each request */
for (l = canceled; l; l = l->next) {
gprs_filter_request_cancel(l->data);
}
/* And deallocate them */
g_slist_free_full(canceled, gprs_filter_request_free1);
}
}
void __ofono_gprs_filter_chain_activate(struct gprs_filter_chain *chain,
struct ofono_gprs_context *gc,
const struct ofono_gprs_primary_context *ctx,
gprs_filter_activate_cb_t cb, ofono_destroy_func destroy,
void *user_data)
{
if (chain && gprs_filter_list && ctx && cb) {
gprs_filter_request_process
(gprs_filter_request_activate_new(chain, gc, ctx,
cb, destroy, user_data));
} else {
if (cb) {
cb(ctx, user_data);
}
if (destroy) {
destroy(user_data);
}
}
}
void __ofono_gprs_filter_chain_check(struct gprs_filter_chain *chain,
gprs_filter_check_cb_t cb, ofono_destroy_func destroy,
void *user_data)
{
if (chain && gprs_filter_list && cb) {
gprs_filter_request_process
(gprs_filter_request_check_new(chain, cb, destroy,
user_data));
} else {
if (cb) {
cb(TRUE, user_data);
}
if (destroy) {
destroy(user_data);
}
}
}
/*==========================================================================*
* ofono_gprs_filter
*==========================================================================*/
/**
* Returns 0 if both are equal;
* <0 if a comes before b;
* >0 if a comes after b.
*/
static gint gprs_filter_sort(gconstpointer a, gconstpointer b)
{
const struct ofono_gprs_filter *a_filter = a;
const struct ofono_gprs_filter *b_filter = b;
if (a_filter->priority > b_filter->priority) {
/* a comes before b */
return -1;
} else if (a_filter->priority < b_filter->priority) {
/* a comes after b */
return 1;
} else {
/* Whatever, as long as the sort is stable */
return strcmp(a_filter->name, b_filter->name);
}
}
int ofono_gprs_filter_register(const struct ofono_gprs_filter *filter)
{
if (!filter || !filter->name) {
return -EINVAL;
}
DBG("%s", filter->name);
gprs_filter_list = g_slist_insert_sorted(gprs_filter_list,
(void*)filter, gprs_filter_sort);
return 0;
}
void ofono_gprs_filter_unregister(const struct ofono_gprs_filter *filter)
{
if (filter) {
DBG("%s", filter->name);
gprs_filter_list = g_slist_remove(gprs_filter_list, filter);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -85,6 +85,7 @@ struct ofono_gprs {
void *driver_data;
struct ofono_atom *atom;
unsigned int spn_watch;
struct gprs_filter_chain *filters;
};
struct ipv4_settings {
@@ -136,7 +137,13 @@ struct pri_context {
struct ofono_gprs *gprs;
};
static void gprs_attached_update(struct ofono_gprs *gprs);
/*
* In Sailfish OS fork gprs_attached_update() is exported to plugins
* as ofono_gprs_attached_update(). Exported functions must start
* with ofono_ prefix.
*/
#define gprs_attached_update(gprs) ofono_gprs_attached_update(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,
@@ -368,6 +375,9 @@ static void release_context(struct pri_context *ctx)
if (ctx == NULL || ctx->gprs == NULL || ctx->context_driver == NULL)
return;
__ofono_gprs_filter_chain_cancel(ctx->gprs->filters,
ctx->context_driver);
gprs_cid_release(ctx->gprs, ctx->context.cid);
ctx->context.cid = 0;
ctx->context_driver->inuse = FALSE;
@@ -1047,16 +1057,17 @@ static DBusMessage *pri_provision_context(DBusConnection *conn,
for (i = 0; i < count; i++) {
const struct ofono_gprs_provision_data *ap = settings + i;
if (ap->type == ctx->type && ap_valid(ap)) {
if ((!ctx->active &&
!ctx->pending && !ctx->gprs->pending) ||
!pri_deactivation_required(ctx, ap)) {
if (ctx->pending || ctx->gprs->pending) {
/* Context is being messed with */
reply = __ofono_error_busy(msg);
} else if (ctx->active &&
pri_deactivation_required(ctx, ap)) {
/* Context needs to be deactivated first */
reply = __ofono_error_busy(msg);
} else {
/* Re-provision the context */
pri_reset_context_properties(ctx, ap);
reply = dbus_message_new_method_return(msg);
} else {
/* Context should be inactive */
if (ctx->gprs->pending || ctx->pending)
reply = __ofono_error_busy(msg);
}
break;
}
@@ -1546,6 +1557,51 @@ static DBusMessage *pri_set_auth_method(struct pri_context *ctx,
return NULL;
}
struct pri_request_data {
struct pri_context *pri;
DBusMessage *msg;
};
static struct pri_request_data *pri_request_new(struct pri_context *pri)
{
struct pri_request_data *data = g_new0(struct pri_request_data, 1);
data->pri = pri;
data->msg = pri->pending;
return data;
}
static void pri_request_free(void *user_data)
{
struct pri_request_data *data = user_data;
struct pri_context *pri = data->pri;
if (pri->pending && pri->pending == data->msg) {
__ofono_dbus_pending_reply(&pri->pending,
__ofono_error_canceled(pri->pending));
}
g_free(data);
}
static void pri_activate_filt(const struct ofono_gprs_primary_context *ctx,
void *user_data)
{
struct pri_request_data *data = user_data;
struct pri_context *pri = data->pri;
data->msg = NULL;
if (ctx) {
struct ofono_gprs_context *gc = pri->context_driver;
gc->driver->activate_primary(gc, ctx, pri_activate_callback,
pri);
} else if (pri->pending != NULL) {
__ofono_dbus_pending_reply(&pri->pending,
__ofono_error_access_denied(pri->pending));
}
}
static DBusMessage *pri_set_property(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -1601,8 +1657,9 @@ static DBusMessage *pri_set_property(DBusConnection *conn,
ctx->pending = dbus_message_ref(msg);
if (value)
gc->driver->activate_primary(gc, &ctx->context,
pri_activate_callback, ctx);
__ofono_gprs_filter_chain_activate(gc->gprs->filters,
gc, &ctx->context, pri_activate_filt,
pri_request_free, pri_request_new(ctx));
else
gc->driver->deactivate_primary(gc, ctx->context.cid,
pri_deactivate_callback, ctx);
@@ -1886,14 +1943,8 @@ static void release_active_contexts(struct ofono_gprs *gprs)
}
}
static void gprs_attached_update(struct ofono_gprs *gprs)
static void gprs_set_attached(struct ofono_gprs *gprs, ofono_bool_t attached)
{
ofono_bool_t attached;
attached = gprs->driver_attached &&
(gprs->status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
gprs->status == NETWORK_REGISTRATION_STATUS_ROAMING);
if (attached == gprs->attached)
return;
@@ -1920,6 +1971,32 @@ static void gprs_attached_update(struct ofono_gprs *gprs)
gprs_set_attached_property(gprs, attached);
}
static void gprs_attached_check_cb(ofono_bool_t allow, void *user_data)
{
gprs_set_attached((struct ofono_gprs *)user_data, allow);
}
void gprs_attached_update(struct ofono_gprs *gprs)
{
ofono_bool_t attached = gprs->driver_attached &&
(gprs->status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
gprs->status == NETWORK_REGISTRATION_STATUS_ROAMING);
if (!attached) {
/* Cancel all other checks - nothing is allowed if we are
* not attached */
__ofono_gprs_filter_chain_cancel(gprs->filters, NULL);
/* We are done synchronously */
gprs_set_attached(gprs, FALSE);
} else {
/* This implicitely cancels the previous check if it's still
* running, so that we never have two simultanous checks. */
__ofono_gprs_filter_chain_check(gprs->filters,
gprs_attached_check_cb, NULL, gprs);
}
}
static void registration_status_cb(const struct ofono_error *error,
int status, void *data)
{
@@ -1988,6 +2065,12 @@ static void gprs_netreg_update(struct ofono_gprs *gprs)
DBG("attach: %u, driver_attached: %u", attach, gprs->driver_attached);
/*
* In Sailfish OS the Attached flag is used by connman to check
* whether context activation is possible. There won't be any
* context activation if Attached stays FALSE.
*/
#if 0
if (ofono_netreg_get_technology(gprs->netreg) ==
ACCESS_TECHNOLOGY_EUTRAN)
/*
@@ -1995,6 +2078,7 @@ static void gprs_netreg_update(struct ofono_gprs *gprs)
* context activation.
*/
return;
#endif
if (gprs->driver_attached == attach)
return;
@@ -3068,6 +3152,9 @@ static void gprs_context_remove(struct ofono_atom *atom)
if (gc->driver && gc->driver->remove)
gc->driver->remove(gc);
if (gc->gprs)
__ofono_gprs_filter_chain_cancel(gc->gprs->filters, gc);
g_free(gc);
}
@@ -3383,6 +3470,7 @@ static void gprs_remove(struct ofono_atom *atom)
if (gprs->driver && gprs->driver->remove)
gprs->driver->remove(gprs);
__ofono_gprs_filter_chain_free(gprs->filters);
g_free(gprs);
}
@@ -3419,6 +3507,7 @@ struct ofono_gprs *ofono_gprs_create(struct ofono_modem *modem,
gprs->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
gprs->netreg_status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
gprs->pid_map = idmap_new(MAX_CONTEXTS);
gprs->filters = __ofono_gprs_filter_chain_new(gprs);
return gprs;
}

View File

@@ -190,6 +190,16 @@ struct ofono_sim *ofono_modem_get_sim(struct ofono_modem *modem)
return __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
}
struct ofono_gprs *ofono_modem_get_gprs(struct ofono_modem *modem)
{
return __ofono_atom_find(OFONO_ATOM_TYPE_GPRS, modem);
}
struct ofono_voicecall *ofono_modem_get_voicecall(struct ofono_modem *modem)
{
return __ofono_atom_find(OFONO_ATOM_TYPE_VOICECALL, modem);
}
struct ofono_atom *__ofono_modem_add_atom(struct ofono_modem *modem,
enum ofono_atom_type type,
void (*destruct)(struct ofono_atom *),
@@ -1882,7 +1892,7 @@ struct ofono_modem *ofono_modem_create(const char *name, const char *type)
else
snprintf(path, sizeof(path), "/%s", name);
if (__ofono_dbus_valid_object_path(path) == FALSE)
if (!dbus_validate_path(path, NULL))
return NULL;
modem = g_try_new0(struct ofono_modem, 1);

View File

@@ -353,7 +353,7 @@ static DBusMessage *netmon_register_agent(DBusConnection *conn,
DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
if (!__ofono_dbus_valid_object_path(agent_path))
if (!dbus_validate_path(agent_path, NULL))
return __ofono_error_invalid_format(msg);
if (!period)

View File

@@ -77,8 +77,6 @@ DBusMessage *__ofono_error_from_error(const struct ofono_error *error,
void __ofono_dbus_pending_reply(DBusMessage **msg, DBusMessage *reply);
gboolean __ofono_dbus_valid_object_path(const char *path);
struct ofono_watchlist_item {
unsigned int id;
void *notify;
@@ -592,6 +590,51 @@ void __ofono_sms_filter_chain_recv_text(struct sms_filter_chain *chain,
const struct sms_scts *scts,
sms_dispatch_recv_text_cb_t default_handler);
#include <ofono/gprs-filter.h>
struct gprs_filter_chain;
typedef void (*gprs_filter_activate_cb_t)
(const struct ofono_gprs_primary_context *ctx, void *user_data);
typedef void (*gprs_filter_check_cb_t)(ofono_bool_t allow, void *user_data);
struct gprs_filter_chain *__ofono_gprs_filter_chain_new(struct ofono_gprs *gp);
void __ofono_gprs_filter_chain_free(struct gprs_filter_chain *chain);
void __ofono_gprs_filter_chain_cancel(struct gprs_filter_chain *chain,
struct ofono_gprs_context *gc);
void __ofono_gprs_filter_chain_activate(struct gprs_filter_chain *chain,
struct ofono_gprs_context *gc,
const struct ofono_gprs_primary_context *ctx,
gprs_filter_activate_cb_t act, ofono_destroy_func destroy,
void *user_data);
void __ofono_gprs_filter_chain_check(struct gprs_filter_chain *chain,
gprs_filter_check_cb_t cb, ofono_destroy_func destroy,
void *user_data);
#include <ofono/voicecall-filter.h>
struct voicecall_filter_chain;
struct voicecall_filter_chain *__ofono_voicecall_filter_chain_new
(struct ofono_voicecall *vc);
void __ofono_voicecall_filter_chain_cancel(struct voicecall_filter_chain *c,
const struct ofono_call *call);
void __ofono_voicecall_filter_chain_restart(struct voicecall_filter_chain *c,
const struct ofono_call *call);
void __ofono_voicecall_filter_chain_free(struct voicecall_filter_chain *c);
void __ofono_voicecall_filter_chain_dial(struct voicecall_filter_chain *c,
const struct ofono_phone_number *number,
enum ofono_clir_option clir,
ofono_voicecall_filter_dial_cb_t cb,
ofono_destroy_func destroy, void *user_data);
void __ofono_voicecall_filter_chain_dial_check(struct voicecall_filter_chain *c,
const struct ofono_call *call,
ofono_voicecall_filter_dial_cb_t cb,
ofono_destroy_func destroy, void *user_data);
void __ofono_voicecall_filter_chain_incoming(struct voicecall_filter_chain *c,
const struct ofono_call *call,
ofono_voicecall_filter_incoming_cb_t cb,
ofono_destroy_func destroy, void *user_data);
#include <ofono/sim-mnclength.h>
int __ofono_sim_mnclength_get_mnclength(const char *imsi);

View File

@@ -428,7 +428,6 @@ static void export_phonebook_cb(const struct ofono_error *error, void *data)
g_slist_foreach(phonebook->merge_list, print_merged_entry,
phonebook->vcards);
g_slist_free_full(phonebook->merge_list, destroy_merged_entry);
g_slist_free(phonebook->merge_list);
phonebook->merge_list = NULL;
phonebook->storage_index++;

View File

@@ -211,17 +211,26 @@ void __ofono_plugin_cleanup(void)
DBG("");
/*
* Terminate the plugins but don't unload the libraries yet.
* Plugins may reference data structures allocated by each other.
*/
for (list = plugins; list; list = list->next) {
struct ofono_plugin *plugin = list->data;
if (plugin->active == TRUE && plugin->desc->exit)
plugin->desc->exit();
}
/* Second pass - unload the libraries */
for (list = plugins; list; list = list->next) {
struct ofono_plugin *plugin = list->data;
if (plugin->handle)
dlclose(plugin->handle);
g_free(plugin);
}
g_slist_free(plugins);
/* Finally, free the memory */
g_slist_free_full(plugins, g_free);
plugins = NULL;
}

78
ofono/src/ril-transport.c Normal file
View File

@@ -0,0 +1,78 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <ofono/ril-transport.h>
#include <ofono/log.h>
#include <string.h>
#include <errno.h>
static GSList *ril_transports = NULL;
struct grilio_transport *ofono_ril_transport_connect(const char *name,
GHashTable *params)
{
if (name) {
GSList *l;
for (l = ril_transports; l; l = l->next) {
const struct ofono_ril_transport *t = l->data;
if (!strcmp(name, t->name)) {
return t->connect ? t->connect(params) : NULL;
}
}
ofono_error("Unknown RIL transport: %s", name);
}
return NULL;
}
int ofono_ril_transport_register(const struct ofono_ril_transport *t)
{
if (!t || !t->name) {
return -EINVAL;
} else {
GSList *l;
for (l = ril_transports; l; l = l->next) {
const struct ofono_ril_transport *t1 = l->data;
if (!strcmp(t->name, t1->name)) {
DBG("%s already registered", t->name);
return -EALREADY;
}
}
DBG("%s", t->name);
ril_transports = g_slist_append(ril_transports, (void*)t);
return 0;
}
}
void ofono_ril_transport_unregister(const struct ofono_ril_transport *t)
{
if (t && t->name) {
DBG("%s", t->name);
ril_transports = g_slist_remove(ril_transports, t);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -722,7 +722,7 @@ static DBusMessage *stk_register_agent(DBusConnection *conn,
DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
if (!__ofono_dbus_valid_object_path(agent_path))
if (!dbus_validate_path(agent_path, NULL))
return __ofono_error_invalid_format(msg);
stk->default_agent = stk_agent_new(agent_path,
@@ -839,7 +839,7 @@ static DBusMessage *stk_select_item(DBusConnection *conn,
DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
if (!__ofono_dbus_valid_object_path(agent_path))
if (!dbus_validate_path(agent_path, NULL))
return __ofono_error_invalid_format(msg);
for (i = 0; i < selection && menu->items[i].text; i++);

View File

@@ -417,13 +417,18 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs,
}
if (status == OFONO_USSD_STATUS_TERMINATED) {
ussd_change_state(ussd, USSD_STATE_IDLE);
if (ussd->state == USSD_STATE_ACTIVE && data && data_len > 0) {
/* Interpret that as a Notify */
status = OFONO_USSD_STATUS_NOTIFY;
} else {
ussd_change_state(ussd, USSD_STATE_IDLE);
if (ussd->pending == NULL)
return;
if (ussd->pending == NULL)
return;
reply = __ofono_error_network_terminated(ussd->pending);
goto out;
reply = __ofono_error_network_terminated(ussd->pending);
goto out;
}
}
if (status == OFONO_USSD_STATUS_NOT_SUPPORTED) {
@@ -808,6 +813,22 @@ static void ussd_unregister(struct ofono_atom *atom)
DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = __ofono_atom_get_modem(atom);
const char *path = __ofono_atom_get_path(atom);
DBusMessage *reply;
if (ussd->pending) {
reply = __ofono_error_canceled(ussd->pending);
__ofono_dbus_pending_reply(&ussd->pending, reply);
}
if (ussd->cancel) {
reply = dbus_message_new_method_return(ussd->cancel);
__ofono_dbus_pending_reply(&ussd->cancel, reply);
}
if (ussd->req)
ussd_request_finish(ussd, -ECANCELED, 0, NULL, 0);
ussd_change_state(ussd, USSD_STATE_IDLE);
g_slist_free_full(ussd->ss_control_list, ssc_entry_destroy);
ussd->ss_control_list = NULL;

View File

@@ -0,0 +1,662 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ofono.h"
#include "common.h"
#include <errno.h>
#include <string.h>
struct voicecall_filter_request;
struct voicecall_filter_request_fn {
const char *name;
gboolean (*can_process)(const struct ofono_voicecall_filter *filter);
guint (*process)(const struct ofono_voicecall_filter *filter,
struct voicecall_filter_request *req);
void (*allow)(struct voicecall_filter_request *req);
void (*free)(struct voicecall_filter_request *req);
};
struct voicecall_filter_request {
int refcount;
const struct voicecall_filter_request_fn *fn;
const struct ofono_call *call;
struct voicecall_filter_chain *chain;
GSList *filter_link;
guint pending_id;
guint next_id;
ofono_destroy_func destroy;
void* user_data;
};
struct voicecall_filter_request_dial {
struct voicecall_filter_request req;
const struct ofono_phone_number *number;
enum ofono_clir_option clir;
ofono_voicecall_filter_dial_cb_t cb;
};
struct voicecall_filter_request_incoming {
struct voicecall_filter_request req;
ofono_voicecall_filter_incoming_cb_t cb;
};
struct voicecall_filter_chain {
struct ofono_voicecall *vc;
GSList *req_list;
};
static GSList *voicecall_filters = NULL;
static void voicecall_filter_request_init(struct voicecall_filter_request *req,
const struct voicecall_filter_request_fn *fn,
struct voicecall_filter_chain *chain, const struct ofono_call *call,
ofono_destroy_func destroy, void *user_data)
{
req->fn = fn;
req->chain = chain;
req->call = call;
req->filter_link = voicecall_filters;
req->destroy = destroy;
req->user_data = user_data;
/*
* The list holds an implicit reference to the message. The reference
* is released by voicecall_filter_request_free when the message is
* removed from the list.
*/
req->refcount = 1;
chain->req_list = g_slist_append(chain->req_list, req);
}
static void voicecall_filter_request_cancel
(struct voicecall_filter_request *req)
{
if (req->pending_id) {
const struct ofono_voicecall_filter *f = req->filter_link->data;
/*
* If the filter returns id of the pending operation,
* then it must provide the cancel callback
*/
f->filter_cancel(req->pending_id);
req->pending_id = 0;
}
if (req->next_id) {
g_source_remove(req->next_id);
req->next_id = 0;
}
}
static void voicecall_filter_request_dispose
(struct voicecall_filter_request *req)
{
/* May be invoked several times per request */
if (req->destroy) {
ofono_destroy_func destroy = req->destroy;
req->destroy = NULL;
destroy(req->user_data);
}
}
static void voicecall_filter_request_free(struct voicecall_filter_request *req)
{
voicecall_filter_request_dispose(req);
req->fn->free(req);
}
#define voicecall_filter_request_ref(req) ((req)->refcount++, req)
static int voicecall_filter_request_unref(struct voicecall_filter_request *req)
{
const int refcount = --(req->refcount);
if (!refcount) {
voicecall_filter_request_free(req);
}
return refcount;
}
static void voicecall_filter_request_done(struct voicecall_filter_request *req)
{
/* Zero the pointer to it in case if this is not the last reference. */
req->chain = NULL;
voicecall_filter_request_unref(req);
}
static void voicecall_filter_request_dequeue
(struct voicecall_filter_request *req)
{
struct voicecall_filter_chain *chain = req->chain;
GSList *l;
/*
* Single-linked list is not particularly good at searching
* and removing the elements but since it should be pretty
* short (typically just one request), it's not worth optimization.
*/
if (chain && (l = g_slist_find(chain->req_list, req)) != NULL) {
voicecall_filter_request_done(l->data);
chain->req_list = g_slist_delete_link(chain->req_list, l);
}
}
static void voicecall_filter_request_complete
(struct voicecall_filter_request *req,
void (*complete)(struct voicecall_filter_request *req))
{
voicecall_filter_request_ref(req);
complete(req);
voicecall_filter_request_dispose(req);
voicecall_filter_request_dequeue(req);
voicecall_filter_request_unref(req);
}
static void voicecall_filter_request_process
(struct voicecall_filter_request *req)
{
GSList *l = req->filter_link;
const struct ofono_voicecall_filter *f = l->data;
const struct voicecall_filter_request_fn *fn = req->fn;
while (f && !fn->can_process(f)) {
l = l->next;
f = l ? l->data : NULL;
}
voicecall_filter_request_ref(req);
if (f) {
req->filter_link = l;
req->pending_id = fn->process(f, req);
} else {
voicecall_filter_request_complete(req, fn->allow);
}
voicecall_filter_request_unref(req);
}
static void voicecall_filter_request_next(struct voicecall_filter_request *req,
GSourceFunc fn)
{
req->pending_id = 0;
req->next_id = g_idle_add(fn, req);
}
static gboolean voicecall_filter_request_continue_cb(gpointer data)
{
struct voicecall_filter_request *req = data;
req->next_id = 0;
req->filter_link = req->filter_link->next;
if (req->filter_link) {
voicecall_filter_request_process(req);
} else {
voicecall_filter_request_complete(req, req->fn->allow);
}
return G_SOURCE_REMOVE;
}
/*==========================================================================*
* voicecall_filter_request_dial
*==========================================================================*/
static struct voicecall_filter_request_dial *
voicecall_filter_request_dial_cast
(struct voicecall_filter_request *req)
{
return (struct voicecall_filter_request_dial *)req;
}
static void voicecall_filter_request_dial_block_complete_cb
(struct voicecall_filter_request *req)
{
struct voicecall_filter_request_dial *dial =
voicecall_filter_request_dial_cast(req);
dial->cb(OFONO_VOICECALL_FILTER_DIAL_BLOCK, req->user_data);
}
static gboolean voicecall_filter_request_dial_block_cb(gpointer data)
{
struct voicecall_filter_request_dial *dial = data;
struct voicecall_filter_request *req = &dial->req;
req->next_id = 0;
voicecall_filter_request_complete(req,
voicecall_filter_request_dial_block_complete_cb);
return G_SOURCE_REMOVE;
}
static void voicecall_filter_request_dial_cb
(enum ofono_voicecall_filter_dial_result result, void *data)
{
struct voicecall_filter_request_dial *dial = data;
struct voicecall_filter_request *req = &dial->req;
const struct ofono_voicecall_filter *filter = req->filter_link->data;
GSourceFunc next_cb;
if (result == OFONO_VOICECALL_FILTER_DIAL_BLOCK) {
ofono_info("%s is refusing to dial %s", filter->name,
phone_number_to_string(dial->number));
next_cb = voicecall_filter_request_dial_block_cb;
} else {
/* OFONO_VOICECALL_FILTER_DIAL_CONTINUE */
DBG("%s is ok with dialing %s", filter->name,
phone_number_to_string(dial->number));
next_cb = voicecall_filter_request_continue_cb;
}
voicecall_filter_request_next(req, next_cb);
}
static gboolean voicecall_filter_request_dial_can_process
(const struct ofono_voicecall_filter *f)
{
return f->filter_dial != NULL;
}
static guint voicecall_filter_request_dial_process
(const struct ofono_voicecall_filter *f,
struct voicecall_filter_request *req)
{
struct voicecall_filter_request_dial *dial =
voicecall_filter_request_dial_cast(req);
return f->filter_dial(req->chain->vc, dial->number, dial->clir,
voicecall_filter_request_dial_cb, dial);
}
static void voicecall_filter_request_dial_allow
(struct voicecall_filter_request *req)
{
struct voicecall_filter_request_dial *dial =
voicecall_filter_request_dial_cast(req);
dial->cb(OFONO_VOICECALL_FILTER_DIAL_CONTINUE, req->user_data);
}
static void voicecall_filter_request_dial_free
(struct voicecall_filter_request *req)
{
g_slice_free1(sizeof(struct voicecall_filter_request_dial), req);
}
static struct voicecall_filter_request *voicecall_filter_request_dial_new
(struct voicecall_filter_chain *chain,
const struct ofono_phone_number *number,
enum ofono_clir_option clir,
ofono_voicecall_filter_dial_cb_t cb,
ofono_destroy_func destroy, void *data)
{
static const struct voicecall_filter_request_fn fn = {
.name = "dial",
.can_process = voicecall_filter_request_dial_can_process,
.process = voicecall_filter_request_dial_process,
.allow = voicecall_filter_request_dial_allow,
.free = voicecall_filter_request_dial_free
};
struct voicecall_filter_request_dial *dial =
g_slice_new0(struct voicecall_filter_request_dial);
struct voicecall_filter_request *req = &dial->req;
voicecall_filter_request_init(req, &fn, chain, NULL, destroy, data);
dial->number = number;
dial->clir = clir;
dial->cb = cb;
return req;
}
/*==========================================================================*
* voicecall_filter_request_incoming
*==========================================================================*/
static struct voicecall_filter_request_incoming *
voicecall_filter_request_incoming_cast
(struct voicecall_filter_request *req)
{
return (struct voicecall_filter_request_incoming *)req;
}
static void voicecall_filter_request_incoming_hangup_complete_cb
(struct voicecall_filter_request *req)
{
struct voicecall_filter_request_incoming *in =
voicecall_filter_request_incoming_cast(req);
in->cb(OFONO_VOICECALL_FILTER_INCOMING_HANGUP, req->user_data);
}
static gboolean voicecall_filter_request_incoming_hangup_cb(gpointer data)
{
struct voicecall_filter_request_incoming *in = data;
struct voicecall_filter_request *req = &in->req;
req->next_id = 0;
voicecall_filter_request_complete(req,
voicecall_filter_request_incoming_hangup_complete_cb);
return G_SOURCE_REMOVE;
}
static void voicecall_filter_request_incoming_ignore_complete_cb
(struct voicecall_filter_request *req)
{
struct voicecall_filter_request_incoming *in =
voicecall_filter_request_incoming_cast(req);
in->cb(OFONO_VOICECALL_FILTER_INCOMING_IGNORE, req->user_data);
}
static gboolean voicecall_filter_request_incoming_ignore_cb(gpointer data)
{
struct voicecall_filter_request_incoming *in = data;
struct voicecall_filter_request *req = &in->req;
req->next_id = 0;
voicecall_filter_request_complete(req,
voicecall_filter_request_incoming_ignore_complete_cb);
return G_SOURCE_REMOVE;
}
static void voicecall_filter_request_incoming_cb
(enum ofono_voicecall_filter_incoming_result result, void *data)
{
struct voicecall_filter_request_incoming *in = data;
struct voicecall_filter_request *req = &in->req;
const struct ofono_voicecall_filter *filter = req->filter_link->data;
GSourceFunc next_cb;
if (result == OFONO_VOICECALL_FILTER_INCOMING_HANGUP) {
ofono_info("%s hangs up incoming call from %s", filter->name,
phone_number_to_string(&req->call->phone_number));
next_cb = voicecall_filter_request_incoming_hangup_cb;
} else if (result == OFONO_VOICECALL_FILTER_INCOMING_IGNORE) {
ofono_info("%s ignores incoming call from %s", filter->name,
phone_number_to_string(&req->call->phone_number));
next_cb = voicecall_filter_request_incoming_ignore_cb;
} else {
/* OFONO_VOICECALL_FILTER_INCOMING_CONTINUE */
DBG("%s is ok with accepting %s", filter->name,
phone_number_to_string(&req->call->phone_number));
next_cb = voicecall_filter_request_continue_cb;
}
voicecall_filter_request_next(req, next_cb);
}
static gboolean voicecall_filter_request_incoming_can_process
(const struct ofono_voicecall_filter *f)
{
return f->filter_incoming != NULL;
}
static guint voicecall_filter_request_incoming_process
(const struct ofono_voicecall_filter *f,
struct voicecall_filter_request *req)
{
return f->filter_incoming(req->chain->vc, req->call,
voicecall_filter_request_incoming_cb,
voicecall_filter_request_incoming_cast(req));
}
static void voicecall_filter_request_incoming_allow
(struct voicecall_filter_request *req)
{
struct voicecall_filter_request_incoming *in =
voicecall_filter_request_incoming_cast(req);
in->cb(OFONO_VOICECALL_FILTER_INCOMING_CONTINUE, req->user_data);
}
static void voicecall_filter_request_incoming_free
(struct voicecall_filter_request *req)
{
g_slice_free1(sizeof(struct voicecall_filter_request_incoming), req);
}
static struct voicecall_filter_request *voicecall_filter_request_incoming_new
(struct voicecall_filter_chain *chain, const struct ofono_call *call,
ofono_voicecall_filter_incoming_cb_t cb,
ofono_destroy_func destroy, void *data)
{
static const struct voicecall_filter_request_fn fn = {
.name = "incoming",
.can_process = voicecall_filter_request_incoming_can_process,
.process = voicecall_filter_request_incoming_process,
.allow = voicecall_filter_request_incoming_allow,
.free = voicecall_filter_request_incoming_free
};
struct voicecall_filter_request_incoming *in =
g_slice_new0(struct voicecall_filter_request_incoming);
struct voicecall_filter_request *req = &in->req;
voicecall_filter_request_init(req, &fn, chain, call, destroy, data);
in->cb = cb;
return req;
}
/*==========================================================================*
* voicecall_filter_chain
*==========================================================================*/
struct voicecall_filter_chain *__ofono_voicecall_filter_chain_new
(struct ofono_voicecall *vc)
{
struct voicecall_filter_chain *chain = NULL;
if (vc) {
chain = g_new0(struct voicecall_filter_chain, 1);
chain->vc = vc;
}
return chain;
}
void __ofono_voicecall_filter_chain_free(struct voicecall_filter_chain *chain)
{
if (chain) {
__ofono_voicecall_filter_chain_cancel(chain, NULL);
g_free(chain);
}
}
static GSList *voicecall_filter_chain_select(struct voicecall_filter_chain *c,
const struct ofono_call *call)
{
if (c) {
GSList *selected;
/* Move selected requests to a separate list */
if (call) {
GSList *prev = NULL;
GSList *l = c->req_list;
selected = NULL;
while (l) {
GSList *next = l->next;
struct voicecall_filter_request *req = l->data;
if (req->call == call) {
/* This one will get canceled */
l->next = selected;
selected = l;
if (prev) {
prev->next = next;
} else {
c->req_list = next;
}
} else {
/* This one survives */
prev = l;
}
l = next;
}
} else {
/* Select everything */
selected = c->req_list;
c->req_list = NULL;
}
return selected;
} else {
return NULL;
}
}
void __ofono_voicecall_filter_chain_restart(struct voicecall_filter_chain *c,
const struct ofono_call *call)
{
GSList *l, *canceled = voicecall_filter_chain_select(c, call);
/* Cancel and resubmit each request */
for (l = canceled; l; l = l->next) {
struct voicecall_filter_request *req = l->data;
voicecall_filter_request_cancel(req);
voicecall_filter_request_process(req);
}
}
void __ofono_voicecall_filter_chain_cancel(struct voicecall_filter_chain *c,
const struct ofono_call *call)
{
GSList *l, *canceled = voicecall_filter_chain_select(c, call);
/* Cancel and deallocate each request */
for (l = canceled; l; l = l->next) {
struct voicecall_filter_request *req = l->data;
voicecall_filter_request_cancel(req);
voicecall_filter_request_done(req);
}
}
void __ofono_voicecall_filter_chain_dial(struct voicecall_filter_chain *chain,
const struct ofono_phone_number *number,
enum ofono_clir_option clir,
ofono_voicecall_filter_dial_cb_t cb,
ofono_destroy_func destroy, void *user_data)
{
if (chain && voicecall_filters && number && cb) {
voicecall_filter_request_process
(voicecall_filter_request_dial_new(chain, number,
clir, cb, destroy, user_data));
} else {
if (cb) {
cb(OFONO_VOICECALL_FILTER_DIAL_CONTINUE, user_data);
}
if (destroy) {
destroy(user_data);
}
}
}
void __ofono_voicecall_filter_chain_dial_check(struct voicecall_filter_chain *c,
const struct ofono_call *call,
ofono_voicecall_filter_dial_cb_t cb,
ofono_destroy_func destroy, void *user_data)
{
if (c && voicecall_filters && call && cb) {
struct voicecall_filter_request *req =
voicecall_filter_request_dial_new(c,
&call->phone_number, OFONO_CLIR_OPTION_DEFAULT,
cb, destroy, user_data);
req->call = call;
voicecall_filter_request_process(req);
} else {
if (cb) {
cb(OFONO_VOICECALL_FILTER_DIAL_CONTINUE, user_data);
}
if (destroy) {
destroy(user_data);
}
}
}
void __ofono_voicecall_filter_chain_incoming(struct voicecall_filter_chain *fc,
const struct ofono_call *call,
ofono_voicecall_filter_incoming_cb_t cb,
ofono_destroy_func destroy, void *user_data)
{
if (fc && voicecall_filters && call && cb) {
voicecall_filter_request_process
(voicecall_filter_request_incoming_new(fc, call,
cb, destroy, user_data));
} else {
if (cb) {
cb(OFONO_VOICECALL_FILTER_INCOMING_CONTINUE, user_data);
}
if (destroy) {
destroy(user_data);
}
}
}
/*==========================================================================*
* ofono_voicecall_filter
*==========================================================================*/
/**
* Returns 0 if both are equal;
* <0 if a comes before b;
* >0 if a comes after b.
*/
static gint voicecall_filter_sort(gconstpointer a, gconstpointer b)
{
const struct ofono_voicecall_filter *a_filter = a;
const struct ofono_voicecall_filter *b_filter = b;
if (a_filter->priority > b_filter->priority) {
/* a comes before b */
return -1;
} else if (a_filter->priority < b_filter->priority) {
/* a comes after b */
return 1;
} else {
/* Whatever, as long as the sort is stable */
return strcmp(a_filter->name, b_filter->name);
}
}
int ofono_voicecall_filter_register(const struct ofono_voicecall_filter *f)
{
if (!f || !f->name) {
return -EINVAL;
}
DBG("%s", f->name);
voicecall_filters = g_slist_insert_sorted(voicecall_filters, (void*)f,
voicecall_filter_sort);
return 0;
}
void ofono_voicecall_filter_unregister(const struct ofono_voicecall_filter *f)
{
if (f) {
DBG("%s", f->name);
voicecall_filters = g_slist_remove(voicecall_filters, f);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -78,6 +78,8 @@ struct ofono_voicecall {
struct ofono_emulator *pending_em;
unsigned int pending_id;
struct voicecall_agent *vc_agent;
struct voicecall_filter_chain *filters;
GSList *incoming_filter_list;
};
struct voicecall {
@@ -118,6 +120,14 @@ struct emulator_status {
int status;
};
struct dial_filter_req {
struct ofono_voicecall *vc;
struct ofono_phone_number pn;
enum ofono_clir_option clir;
ofono_voicecall_cb_t cb;
void *data;
};
static const char *default_en_list[] = { "911", "112", NULL };
static const char *default_en_list_no_sim[] = { "119", "118", "999", "110",
"08", "000", NULL };
@@ -694,6 +704,9 @@ static void voicecall_destroy(gpointer userdata)
{
struct voicecall *voicecall = (struct voicecall *)userdata;
__ofono_voicecall_filter_chain_cancel(voicecall->vc->filters,
voicecall->call);
g_free(voicecall->call);
g_free(voicecall->message);
@@ -1496,7 +1509,7 @@ static void manager_dial_callback(const struct ofono_error *error, void *data)
}
reply = __ofono_error_failed(vc->pending);
reply = __ofono_error_from_error(error, vc->pending);
}
__ofono_dbus_pending_reply(&vc->pending, reply);
@@ -1505,6 +1518,168 @@ static void manager_dial_callback(const struct ofono_error *error, void *data)
voicecalls_emit_call_added(vc, v);
}
static void dummy_callback(const struct ofono_error *error, void *data)
{
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
DBG("command failed with error: %s",
telephony_error_to_str(error));
}
static void filter_hangup(struct voicecall *v)
{
struct ofono_voicecall *vc = v->vc;
const struct ofono_call *call = v->call;
const struct ofono_voicecall_driver *driver = vc->driver;
switch (call->status) {
case OFONO_CALL_STATUS_WAITING:
if (driver->set_udub) {
driver->set_udub(vc, dummy_callback, vc);
return;
} else if (driver->release_specific) {
driver->release_specific(vc, call->id,
dummy_callback, vc);
return;
}
break;
case OFONO_CALL_STATUS_ACTIVE:
case OFONO_CALL_STATUS_DIALING:
case OFONO_CALL_STATUS_ALERTING:
if (driver->hangup_active) {
driver->hangup_active(vc, dummy_callback, vc);
return;
}
/* no break */
default:
if (driver->release_specific) {
driver->release_specific(vc, call->id,
dummy_callback, vc);
return;
}
break;
}
ofono_warn("Couldn't disconnect %s call %d",
call_status_to_string(call->status), call->id);
}
static void filter_dial_check_cb(enum ofono_voicecall_filter_dial_result result,
void *data)
{
struct voicecall *v = data;
if (result == OFONO_VOICECALL_FILTER_DIAL_CONTINUE) {
DBG("No need to release %s call %d",
call_status_to_string(v->call->status), v->call->id);
} else {
DBG("Need to release %s call %d",
call_status_to_string(v->call->status), v->call->id);
filter_hangup(v);
}
}
static void filter_incoming_check_cb
(enum ofono_voicecall_filter_incoming_result result, void *data)
{
struct voicecall *v = data;
if (result == OFONO_VOICECALL_FILTER_INCOMING_CONTINUE) {
DBG("No need to release %s call %d",
call_status_to_string(v->call->status), v->call->id);
} else {
DBG("Need to release %s call %d",
call_status_to_string(v->call->status), v->call->id);
filter_hangup(v);
}
}
static void filter_incoming_cb(enum ofono_voicecall_filter_incoming_result res,
void *data)
{
struct voicecall *v = data;
struct ofono_voicecall *vc = v->vc;
vc->incoming_filter_list = g_slist_remove(vc->incoming_filter_list, v);
if (res == OFONO_VOICECALL_FILTER_INCOMING_HANGUP) {
if (vc->driver->release_specific) {
vc->driver->release_specific(vc, v->call->id,
dummy_callback, vc);
}
voicecall_destroy(v);
} else if (res == OFONO_VOICECALL_FILTER_INCOMING_IGNORE) {
voicecall_destroy(v);
} else if (voicecall_dbus_register(v)) {
struct ofono_voicecall *vc = v->vc;
vc->call_list = g_slist_insert_sorted(vc->call_list, v,
call_compare);
voicecalls_emit_call_added(vc, v);
}
}
void ofono_voicecall_filter_notify(struct ofono_voicecall *vc)
{
GSList *l;
struct voicecall *v;
/* Cancel all active filtering requests */
__ofono_voicecall_filter_chain_cancel(vc->filters, NULL);
/* Re-check incoming_filter_list */
for (l = vc->incoming_filter_list; l; l = l->next) {
v = l->data;
__ofono_voicecall_filter_chain_incoming(vc->filters, v->call,
filter_incoming_cb, NULL, v);
}
/* Re-check the calls that have already passed the filter */
for (l = vc->call_list; l; l = l->next) {
v = l->data;
if (v->call->direction == CALL_DIRECTION_MOBILE_ORIGINATED) {
__ofono_voicecall_filter_chain_dial_check(vc->filters,
v->call, filter_dial_check_cb, NULL, v);
} else {
__ofono_voicecall_filter_chain_incoming(vc->filters,
v->call, filter_incoming_check_cb, NULL, v);
}
}
}
static void dial_filter_cb(enum ofono_voicecall_filter_dial_result result,
void *req_data)
{
struct dial_filter_req *req = req_data;
if (result == OFONO_VOICECALL_FILTER_DIAL_BLOCK) {
struct ofono_error error;
error.type = OFONO_ERROR_TYPE_ERRNO;
error.error = EACCES;
req->cb(&error, req->data);
} else {
struct ofono_voicecall *vc = req->vc;
/* OFONO_VOICECALL_FILTER_DIAL_CONTINUE */
vc->driver->dial(vc, &req->pn, req->clir, req->cb, req->data);
}
}
static void dial_filter(struct ofono_voicecall *vc,
const struct ofono_phone_number *pn,
enum ofono_clir_option clir,
ofono_voicecall_cb_t cb, void *data)
{
struct dial_filter_req *req = g_new0(struct dial_filter_req, 1);
req->vc = vc;
req->pn = *pn;
req->clir = clir;
req->cb = cb;
req->data = data;
__ofono_voicecall_filter_chain_dial(vc->filters, &req->pn, clir,
dial_filter_cb, g_free, req);
}
static int voicecall_dial(struct ofono_voicecall *vc, const char *number,
enum ofono_clir_option clir,
ofono_voicecall_cb_t cb, void *data)
@@ -1542,7 +1717,11 @@ static int voicecall_dial(struct ofono_voicecall *vc, const char *number,
string_to_phone_number(number, &ph);
vc->driver->dial(vc, &ph, clir, cb, vc);
/* No filtering for emergency calls */
if (is_emergency_number(vc, number))
vc->driver->dial(vc, &ph, clir, cb, vc);
else
dial_filter(vc, &ph, clir, cb, vc);
return 0;
}
@@ -2158,7 +2337,7 @@ static DBusMessage *voicecall_register_agent(DBusConnection *conn,
&agent_path, DBUS_TYPE_INVALID) == FALSE)
return __ofono_error_invalid_args(msg);
if (!__ofono_dbus_valid_object_path(agent_path))
if (!dbus_validate_path(agent_path, NULL))
return __ofono_error_invalid_format(msg);
vc->vc_agent = voicecall_agent_new(agent_path,
@@ -2272,6 +2451,18 @@ void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id,
__ofono_modem_callid_release(modem, id);
l = g_slist_find_custom(vc->incoming_filter_list, GUINT_TO_POINTER(id),
call_compare_by_id);
if (l) {
/* Incoming call was disconnected in the process of being
* filtered. voicecall_destroy cancels it. */
vc->incoming_filter_list = g_slist_delete_link
(vc->incoming_filter_list, l);
voicecall_destroy(l->data);
return;
}
l = g_slist_find_custom(vc->call_list, GUINT_TO_POINTER(id),
call_compare_by_id);
@@ -2356,6 +2547,26 @@ void ofono_voicecall_notify(struct ofono_voicecall *vc,
call->status, call->id, call->phone_number.number,
call->called_number.number, call->name);
l = g_slist_find_custom(vc->incoming_filter_list,
GUINT_TO_POINTER(call->id), call_compare_by_id);
if (l) {
/* The call has changed in the process of being filtered. */
DBG("Found filtered call with id: %d", call->id);
v = l->data;
/* Update the call */
voicecall_set_call_status(v, call->status);
voicecall_set_call_lineid(v, &call->phone_number,
call->clip_validity);
voicecall_set_call_calledid(v, &call->called_number);
voicecall_set_call_name(v, call->name, call->cnap_validity);
/* And restart the filtering */
__ofono_voicecall_filter_chain_restart(vc->filters, v->call);
return;
}
l = g_slist_find_custom(vc->call_list, GUINT_TO_POINTER(call->id),
call_compare_by_id);
@@ -2421,6 +2632,16 @@ void ofono_voicecall_notify(struct ofono_voicecall *vc,
v->detect_time = time(NULL);
if (call->status == CALL_STATUS_INCOMING ||
call->status == CALL_STATUS_WAITING) {
/* Incoming calls have to go through filtering */
vc->incoming_filter_list = g_slist_append
(vc->incoming_filter_list, v);
__ofono_voicecall_filter_chain_incoming(vc->filters, v->call,
filter_incoming_cb, NULL, v);
return;
}
if (!voicecall_dbus_register(v)) {
ofono_error("Unable to register voice call");
goto error;
@@ -2886,6 +3107,10 @@ static void voicecall_unregister(struct ofono_atom *atom)
g_slist_free(vc->call_list);
vc->call_list = NULL;
/* voicecall_destroy cancels the filtering */
g_slist_free_full(vc->incoming_filter_list, voicecall_destroy);
vc->incoming_filter_list = NULL;
ofono_modem_remove_interface(modem, OFONO_VOICECALL_MANAGER_INTERFACE);
g_dbus_unregister_interface(conn, path,
OFONO_VOICECALL_MANAGER_INTERFACE);
@@ -2900,6 +3125,8 @@ static void voicecall_remove(struct ofono_atom *atom)
if (vc == NULL)
return;
__ofono_voicecall_filter_chain_free(vc->filters);
if (vc->driver && vc->driver->remove)
vc->driver->remove(vc);
@@ -2954,6 +3181,7 @@ struct ofono_voicecall *ofono_voicecall_create(struct ofono_modem *modem,
break;
}
vc->filters = __ofono_voicecall_filter_chain_new(vc);
return vc;
}
@@ -3702,6 +3930,7 @@ void ofono_voicecall_register(struct ofono_voicecall *vc)
vc->hfp_watch = __ofono_modem_add_atom_watch(modem,
OFONO_ATOM_TYPE_EMULATOR_HFP,
emulator_hfp_watch, vc, NULL);
}
void ofono_voicecall_remove(struct ofono_voicecall *vc)
@@ -3719,6 +3948,11 @@ void *ofono_voicecall_get_data(struct ofono_voicecall *vc)
return vc->driver_data;
}
struct ofono_modem *ofono_voicecall_get_modem(struct ofono_voicecall *vc)
{
return __ofono_atom_get_modem(vc->atom);
}
int ofono_voicecall_get_next_callid(struct ofono_voicecall *vc)
{
struct ofono_modem *modem;
@@ -3816,10 +4050,14 @@ static void dial_request(struct ofono_voicecall *vc)
struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom);
__ofono_modem_inc_emergency_mode(modem);
}
vc->driver->dial(vc, &vc->dial_req->ph, OFONO_CLIR_OPTION_DEFAULT,
/* No filtering for emergency calls */
vc->driver->dial(vc, &vc->dial_req->ph,
OFONO_CLIR_OPTION_DEFAULT, dial_request_cb, vc);
} else {
dial_filter(vc, &vc->dial_req->ph, OFONO_CLIR_OPTION_DEFAULT,
dial_request_cb, vc);
}
}
static void dial_req_disconnect_cb(const struct ofono_error *error, void *data)

View File

@@ -16,14 +16,20 @@ TESTS="\
test-cdmasms \
test-sms-root \
test-caif \
test-dbus-queue \
test-gprs-filter \
test-provision \
test-ril_util \
test-ril_config \
test-ril-transport \
test-sms-filter \
test-voicecall-filter \
test-sailfish_cell_info \
test-sailfish_cell_info_dbus \
test-sailfish_manager \
test-sailfish_sim_info \
test-sailfish_sim_info_dbus"
test-sailfish_sim_info_dbus \
test-sailfish_watch"
pushd `dirname $0` > /dev/null
TEST_DIR="$PWD"

View File

@@ -0,0 +1,659 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 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.
*/
#include "test-dbus.h"
#include <ofono/dbus.h>
#include "ofono.h"
#include "dbus-queue.h"
#include <gutil_log.h>
#include <gutil_macros.h>
#define TEST_TIMEOUT (10) /* seconds */
#define TEST_DBUS_INTERFACE "test.interface"
#define TEST_DBUS_METHOD "Test"
#define TEST_DBUS_PATH "/"
#define TEST_ERROR_CANCELED "org.ofono.Error.Canceled"
#define TEST_ERROR_FAILED "org.ofono.Error.Failed"
#define GDBUS_TEST_METHOD(fn) GDBUS_ASYNC_METHOD(TEST_DBUS_METHOD, \
GDBUS_ARGS( { "arg", "i" }), NULL, fn)
static gboolean test_debug;
/* ==== common ==== */
static gboolean test_timeout(gpointer param)
{
g_assert(!"TIMEOUT");
return G_SOURCE_REMOVE;
}
static guint test_setup_timeout(void)
{
if (test_debug) {
return 0;
} else {
return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, NULL);
}
}
#define test_register_interface(methods,data) \
g_assert(g_dbus_register_interface(ofono_dbus_get_connection(), \
TEST_DBUS_PATH, TEST_DBUS_INTERFACE, \
methods, NULL, NULL, data, NULL))
static void test_client_call(struct test_dbus_context* dbus, dbus_int32_t arg,
DBusPendingCallNotifyFunction fn)
{
DBusPendingCall *call;
DBusConnection* conn = dbus->client_connection;
DBusMessage *msg = dbus_message_new_method_call(NULL, TEST_DBUS_PATH,
TEST_DBUS_INTERFACE, TEST_DBUS_METHOD);
dbus_message_append_args(msg, DBUS_TYPE_INT32, &arg, DBUS_TYPE_INVALID);
g_assert(dbus_connection_send_with_reply(conn, msg, &call,
DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, fn, dbus, NULL);
dbus_message_unref(msg);
}
static void test_expect_canceled(DBusPendingCall *call, void *unused)
{
DBG("");
test_dbus_check_error_reply(call, TEST_ERROR_CANCELED);
}
static void test_expect_failed(DBusPendingCall *call, void *unused)
{
DBG("");
test_dbus_check_error_reply(call, TEST_ERROR_FAILED);
}
/* ==== basic ==== */
static void test_basic(void)
{
__ofono_dbus_queue_free(__ofono_dbus_queue_new());
/* These are NULL tolerant: */
__ofono_dbus_queue_free(NULL);
__ofono_dbus_queue_reply_ok(NULL);
__ofono_dbus_queue_reply_failed(NULL);
__ofono_dbus_queue_reply_all_ok(NULL);
__ofono_dbus_queue_reply_all_failed(NULL);
__ofono_dbus_queue_reply_msg(NULL, NULL);
g_assert(!__ofono_dbus_queue_pending(NULL));
g_assert(!__ofono_dbus_queue_set_pending(NULL, NULL));
}
/* ==== free ==== */
struct test_free_data {
struct test_dbus_context dbus;
struct ofono_dbus_queue *queue;
};
static DBusMessage *test_free_cb(DBusMessage *msg, void *data)
{
DBG("");
return NULL;
}
static void test_free_reply(DBusPendingCall *call, void *dbus)
{
struct test_free_data *test = G_CAST(dbus, struct test_free_data, dbus);
DBG("");
test_dbus_check_error_reply(call, TEST_ERROR_CANCELED);
g_main_loop_quit(test->dbus.loop);
}
static DBusMessage *test_free_handler(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct test_free_data *test = data;
DBG("");
/* test_free_cb queues the message */
__ofono_dbus_queue_request(test->queue, test_free_cb, msg, test);
/* And this cancels it: */
__ofono_dbus_queue_free(test->queue);
test->queue = NULL;
return NULL;
}
static const GDBusMethodTable test_free_methods[] = {
{ GDBUS_TEST_METHOD(test_free_handler) },
{ }
};
static void test_free_start(struct test_dbus_context *dbus)
{
struct test_free_data *test = G_CAST(dbus, struct test_free_data, dbus);
test_register_interface(test_free_methods, test);
test_client_call(dbus, 0, test_free_reply);
}
static void test_free(void)
{
struct test_free_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test_dbus_setup(&test.dbus);
test.dbus.start = test_free_start;
test.queue = __ofono_dbus_queue_new();
g_main_loop_run(test.dbus.loop);
g_assert(!test.queue); /* Freed by test_free_handler */
test_dbus_shutdown(&test.dbus);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== cancel ==== */
struct test_cancel_data {
struct test_dbus_context dbus;
struct ofono_dbus_queue *queue;
};
static gboolean test_cancel_msg(void *data)
{
struct test_cancel_data *test = data;
/* This is will cancel the message: */
__ofono_dbus_queue_reply_msg(test->queue, NULL);
return G_SOURCE_REMOVE;
}
static DBusMessage *test_cancel_cb(DBusMessage *msg, void *data)
{
DBG("");
g_idle_add(test_cancel_msg, data);
return NULL;
}
static void test_cancel_reply(DBusPendingCall *call, void *dbus)
{
struct test_cancel_data *test =
G_CAST(dbus, struct test_cancel_data, dbus);
DBG("");
test_dbus_check_error_reply(call, TEST_ERROR_CANCELED);
g_main_loop_quit(test->dbus.loop);
}
static DBusMessage *test_cancel_handler(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct test_cancel_data *test = data;
DBG("");
__ofono_dbus_queue_request(test->queue, test_cancel_cb, msg, test);
return NULL;
}
static const GDBusMethodTable test_cancel_methods[] = {
{ GDBUS_TEST_METHOD(test_cancel_handler) },
{ }
};
static void test_cancel_start(struct test_dbus_context *dbus)
{
struct test_cancel_data *test =
G_CAST(dbus, struct test_cancel_data, dbus);
test_register_interface(test_cancel_methods, test);
test_client_call(dbus, 0, test_cancel_reply);
}
static void test_cancel(void)
{
struct test_cancel_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test_dbus_setup(&test.dbus);
test.dbus.start = test_cancel_start;
test.queue = __ofono_dbus_queue_new();
g_main_loop_run(test.dbus.loop);
__ofono_dbus_queue_free(test.queue);
test_dbus_shutdown(&test.dbus);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== async ==== */
struct test_async_data {
struct test_dbus_context dbus;
struct ofono_dbus_queue *queue;
};
static gboolean test_async_complete(void *data)
{
struct test_cancel_data *test = data;
__ofono_dbus_queue_reply_fn(test->queue,
dbus_message_new_method_return);
return G_SOURCE_REMOVE;
}
static DBusMessage *test_async_cb(DBusMessage *msg, void *data)
{
DBG("");
g_idle_add(test_async_complete, data);
return NULL;
}
static void test_async_last_reply(DBusPendingCall *call, void *dbus)
{
struct test_async_data *test =
G_CAST(dbus, struct test_async_data, dbus);
DBG("");
test_dbus_check_empty_reply(call, NULL);
g_main_loop_quit(test->dbus.loop);
}
static DBusMessage *test_async_handler(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct test_cancel_data *test = data;
DBG("");
__ofono_dbus_queue_request(test->queue, test_async_cb, msg, data);
return NULL;
}
static const GDBusMethodTable test_async_methods[] = {
{ GDBUS_TEST_METHOD(test_async_handler) },
{ }
};
static void test_async_start(struct test_dbus_context *dbus)
{
struct test_async_data *test =
G_CAST(dbus, struct test_async_data, dbus);
test_register_interface(test_async_methods, test);
test_client_call(dbus, 0, test_dbus_expect_empty_reply);
test_client_call(dbus, 1, test_dbus_expect_empty_reply);
test_client_call(dbus, 2, test_dbus_expect_empty_reply);
test_client_call(dbus, 3, test_async_last_reply);
}
static void test_async(void)
{
struct test_async_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test_dbus_setup(&test.dbus);
test.dbus.start = test_async_start;
test.queue = __ofono_dbus_queue_new();
g_main_loop_run(test.dbus.loop);
__ofono_dbus_queue_free(test.queue);
test_dbus_shutdown(&test.dbus);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== sync ==== */
struct test_sync_data {
struct test_dbus_context dbus;
struct ofono_dbus_queue *queue;
};
static DBusMessage *test_sync_cb(DBusMessage *msg, void *data)
{
DBG("");
return dbus_message_new_method_return(msg);
}
static void test_sync_reply(DBusPendingCall *call, void *dbus)
{
struct test_sync_data *test = G_CAST(dbus, struct test_sync_data, dbus);
DBG("");
test_dbus_check_empty_reply(call, NULL);
g_main_loop_quit(test->dbus.loop);
}
static DBusMessage *test_sync_handler(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct test_sync_data *test = data;
DBG("");
/* test_sync_cb immediately completes it */
__ofono_dbus_queue_request(test->queue, test_sync_cb, msg, test);
return NULL;
}
static const GDBusMethodTable test_sync_methods[] = {
{ GDBUS_TEST_METHOD(test_sync_handler) },
{ }
};
static void test_sync_start(struct test_dbus_context *dbus)
{
struct test_sync_data *test = G_CAST(dbus, struct test_sync_data, dbus);
test_register_interface(test_sync_methods, test);
test_client_call(dbus, 0, test_sync_reply);
}
static void test_sync(void)
{
struct test_sync_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test_dbus_setup(&test.dbus);
test.dbus.start = test_sync_start;
test.queue = __ofono_dbus_queue_new();
g_main_loop_run(test.dbus.loop);
__ofono_dbus_queue_free(test.queue);
test_dbus_shutdown(&test.dbus);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== reply ==== */
struct test_reply_data {
struct test_dbus_context dbus;
struct ofono_dbus_queue *queue;
};
static void test_reply_last_reply(DBusPendingCall *call, void *dbus)
{
struct test_reply_data *test =
G_CAST(dbus, struct test_reply_data, dbus);
DBG("");
test_dbus_check_error_reply(call, TEST_ERROR_FAILED);
g_main_loop_quit(test->dbus.loop);
}
static DBusMessage *test_reply_1(DBusMessage *msg, void *data)
{
DBG("");
return NULL;
}
static DBusMessage *test_reply_2(DBusMessage *msg, void *data)
{
DBG("");
return NULL;
}
static DBusMessage *test_reply_handler(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct test_reply_data *test = data;
dbus_int32_t arg;
g_assert(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &arg,
DBUS_TYPE_INVALID));
DBG("%d", arg);
switch (arg) {
case 0:
/* Queue is empty, we can use __ofono_dbus_queue_set_pending */
g_assert(__ofono_dbus_queue_set_pending(test->queue, msg));
break;
case 1:
case 4:
/* Queue is not empty anymore */
g_assert(__ofono_dbus_queue_pending(test->queue));
g_assert(!__ofono_dbus_queue_set_pending(test->queue, msg));
__ofono_dbus_queue_request(test->queue, test_reply_1,
msg, NULL);
break;
case 2:
/* Same callback, different data */
__ofono_dbus_queue_request(test->queue, test_reply_1,
msg, test);
break;
case 3:
__ofono_dbus_queue_request(test->queue, test_reply_2,
msg, NULL);
break;
case 5:
__ofono_dbus_queue_request(test->queue, test_reply_2,
msg, NULL);
/* This completes the first one, with NULL handler */
__ofono_dbus_queue_reply_all_fn_param(test->queue, NULL, NULL);
g_assert(__ofono_dbus_queue_pending(test->queue));
/* And this one completes 2 others with test_reply_1 */
__ofono_dbus_queue_reply_all_fn(test->queue,
dbus_message_new_method_return);
g_assert(__ofono_dbus_queue_pending(test->queue));
/* This one test_reply_1 with different data */
__ofono_dbus_queue_reply_all_fn(test->queue,
__ofono_error_canceled);
/* And this one fails 2 others with test_reply_2 */
__ofono_dbus_queue_reply_all_fn(test->queue, NULL);
g_assert(!__ofono_dbus_queue_pending(test->queue));
/* And this one does nothing */
__ofono_dbus_queue_reply_all_fn(test->queue,
dbus_message_new_method_return);
break;
}
return NULL;
}
static const GDBusMethodTable test_reply_methods[] = {
{ GDBUS_TEST_METHOD(test_reply_handler) },
{ }
};
static void test_reply_start(struct test_dbus_context *dbus)
{
struct test_reply_data *test =
G_CAST(dbus, struct test_reply_data, dbus);
test_register_interface(test_reply_methods, test);
test_client_call(dbus, 0, test_expect_failed);
test_client_call(dbus, 1, test_dbus_expect_empty_reply);
test_client_call(dbus, 2, test_expect_canceled);
test_client_call(dbus, 3, test_expect_failed);
test_client_call(dbus, 4, test_dbus_expect_empty_reply);
test_client_call(dbus, 5, test_reply_last_reply);
}
static void test_reply(void)
{
struct test_reply_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test_dbus_setup(&test.dbus);
test.dbus.start = test_reply_start;
test.queue = __ofono_dbus_queue_new();
g_main_loop_run(test.dbus.loop);
__ofono_dbus_queue_free(test.queue);
test_dbus_shutdown(&test.dbus);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== ok ==== */
struct test_ok_data {
struct test_dbus_context dbus;
struct ofono_dbus_queue *queue;
};
static DBusMessage *test_ok_1(DBusMessage *msg, void *data)
{
DBG("");
return NULL;
}
static DBusMessage *test_ok_2(DBusMessage *msg, void *data)
{
DBG("");
return dbus_message_new_method_return(msg);
}
static void test_ok_last_reply(DBusPendingCall *call, void *dbus)
{
struct test_ok_data *test = G_CAST(dbus, struct test_ok_data, dbus);
DBG("");
test_dbus_check_empty_reply(call, NULL);
g_main_loop_quit(test->dbus.loop);
}
static DBusMessage *test_ok_handler(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct test_ok_data *test = data;
dbus_int32_t arg;
g_assert(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &arg,
DBUS_TYPE_INVALID));
DBG("%d", arg);
if (arg == 0) {
/* This is the first call, it blocks the queue */
__ofono_dbus_queue_request(test->queue, test_ok_1, msg, test);
} else {
g_assert(__ofono_dbus_queue_pending(test->queue));
__ofono_dbus_queue_request(test->queue, test_ok_2, msg, test);
/* This is the second call, complete the first one.
* That unblocks the seconds one. */
__ofono_dbus_queue_reply_ok(test->queue);
/* This call has no effect, it's actually an error (the
* message has already been replied to) but such situation
* is handled by __ofono_dbus_queue_reply_msg */
__ofono_dbus_queue_reply_msg(test->queue,
dbus_message_new_method_return(msg));
/* This one does nothing too */
__ofono_dbus_queue_reply_fn(test->queue, NULL);
}
return NULL;
}
static const GDBusMethodTable test_ok_methods[] = {
{ GDBUS_TEST_METHOD(test_ok_handler) },
{ }
};
static void test_ok_start(struct test_dbus_context *dbus)
{
struct test_ok_data *test = G_CAST(dbus, struct test_ok_data, dbus);
test_register_interface(test_ok_methods, test);
test_client_call(dbus, 0, test_dbus_check_empty_reply);
test_client_call(dbus, 1, test_ok_last_reply);
}
static void test_ok(void)
{
struct test_ok_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test_dbus_setup(&test.dbus);
test.dbus.start = test_ok_start;
test.queue = __ofono_dbus_queue_new();
g_main_loop_run(test.dbus.loop);
__ofono_dbus_queue_free(test.queue);
test_dbus_shutdown(&test.dbus);
if (timeout) {
g_source_remove(timeout);
}
}
#define TEST_(name) "/dbus-queue/" name
int main(int argc, char *argv[])
{
int i;
g_test_init(&argc, &argv, NULL);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
test_debug = TRUE;
} else {
GWARN("Unsupported command line option %s", arg);
}
}
gutil_log_timestamp = FALSE;
gutil_log_default.level = g_test_verbose() ?
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
__ofono_log_init("test-dbus-queue",
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("free"), test_free);
g_test_add_func(TEST_("cancel"), test_cancel);
g_test_add_func(TEST_("async"), test_async);
g_test_add_func(TEST_("sync"), test_sync);
g_test_add_func(TEST_("reply"), test_reply);
g_test_add_func(TEST_("ok"), test_ok);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -18,6 +18,8 @@
#include <dbus/dbus-glib-lowlevel.h>
#include <unistd.h>
struct test_polkit_auth_check {
void (*function)(dbus_bool_t authorized, void *user_data);
void *user_data;
@@ -233,13 +235,11 @@ const char *test_dbus_get_object_path(DBusMessageIter *it)
return value;
}
void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data)
void test_dbus_check_empty_reply(DBusPendingCall *call, void *unused)
{
struct test_dbus_context *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
DBG("");
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
@@ -248,9 +248,29 @@ void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data)
dbus_message_unref(reply);
dbus_pending_call_unref(call);
}
void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data)
{
struct test_dbus_context *test = data;
DBG("");
test_dbus_check_empty_reply(call, data);
test_dbus_loop_quit_later(test->loop);
}
void test_dbus_check_error_reply(DBusPendingCall *call, const char *error)
{
DBusMessage *msg = dbus_pending_call_steal_reply(call);
const char *name;
g_assert(dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_ERROR);
name = dbus_message_get_error_name(msg);
g_assert(!g_strcmp0(name, error));
dbus_message_unref(msg);
dbus_pending_call_unref(call);
}
void test_dbus_check_string_reply(DBusPendingCall *call, const char *str)
{
DBusMessage *reply = dbus_pending_call_steal_reply(call);
@@ -307,15 +327,22 @@ static void test_dbus_connection_cb(DBusServer *server, DBusConnection *conn,
void test_dbus_setup(struct test_dbus_context *test)
{
char *path;
char *address;
GMainContext *context;
/* Generate unique non-existent path */
path = g_dir_make_tmp ("test-dbus.XXXXXX", NULL);
g_assert(path);
rmdir(path);
address = g_strconcat("unix:path=", path, NULL);
test->loop = g_main_loop_new(NULL, TRUE);
context = g_main_loop_get_context(test->loop);
test->server = dbus_server_listen("unix:runtime=yes;unix:tmpdir=/tmp",
NULL);
test->server = dbus_server_listen(address, NULL);
g_assert(test->server);
address = dbus_server_get_address(test->server);
DBG("listening on %s", address);
dbus_server_setup_with_g_main(test->server, context);
@@ -328,7 +355,8 @@ void test_dbus_setup(struct test_dbus_context *test)
g_assert(dbus_connection_add_filter(test->client_connection,
test_dbus_client_message_cb, test, NULL));
DBG("connected on %s", address);
dbus_free(address);
g_free(address);
g_free(path);
}
void test_dbus_shutdown(struct test_dbus_context *test)

View File

@@ -19,13 +19,13 @@
#include <ofono/gdbus.h>
struct test_dbus_context {
GMainLoop *loop;
DBusServer *server;
DBusConnection *server_connection;
DBusConnection *client_connection;
GSList* client_signals;
void (*start)(struct test_dbus_context *test);
guint timeout_id;
GMainLoop *loop;
DBusServer *server;
DBusConnection *server_connection;
DBusConnection *client_connection;
GSList* client_signals;
void (*start)(struct test_dbus_context *test);
guint timeout_id;
};
void test_dbus_setup(struct test_dbus_context *context);
@@ -39,7 +39,9 @@ gboolean test_dbus_get_bool(DBusMessageIter *it);
const char *test_dbus_get_string(DBusMessageIter *it);
const char *test_dbus_get_object_path(DBusMessageIter *it);
void test_dbus_check_error_reply(DBusPendingCall *call, const char *error);
void test_dbus_check_string_reply(DBusPendingCall *call, const char *str);
void test_dbus_check_empty_reply(DBusPendingCall *call, void *unused);
void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data);
DBusMessage *test_dbus_find_signal(struct test_dbus_context *test,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ofono.h"
#include <ofono/ril-transport.h>
#include <string.h>
#include <errno.h>
static void test_null(void)
{
struct ofono_ril_transport noname;
memset(&noname, 0, sizeof(noname));
g_assert(ofono_ril_transport_register(NULL) == -EINVAL);
g_assert(ofono_ril_transport_register(&noname) == -EINVAL);
ofono_ril_transport_unregister(NULL);
ofono_ril_transport_unregister(&noname);
g_assert(!ofono_ril_transport_connect(NULL, NULL));
}
static void test_register(void)
{
struct ofono_ril_transport foo;
struct ofono_ril_transport bar;
memset(&foo, 0, sizeof(foo));
memset(&bar, 0, sizeof(bar));
foo.name = "foo";
bar.name = "bar";
g_assert(ofono_ril_transport_register(&foo) == 0);
g_assert(ofono_ril_transport_register(&bar) == 0);
g_assert(ofono_ril_transport_register(&bar) == (-EALREADY));
g_assert(!ofono_ril_transport_connect(foo.name, NULL));
g_assert(!ofono_ril_transport_connect("test", NULL));
ofono_ril_transport_unregister(&foo);
ofono_ril_transport_unregister(&bar);
}
static struct grilio_transport *test_connect_cb(GHashTable *params)
{
static int dummy;
return (void*)&dummy;
}
static void test_connect(void)
{
static const struct ofono_ril_transport test = {
.name = "test",
.api_version = OFONO_RIL_TRANSPORT_API_VERSION,
.connect = test_connect_cb
};
g_assert(ofono_ril_transport_register(&test) == 0);
/* The returned pointer points to a static variable, no need to free */
g_assert(ofono_ril_transport_connect(test.name, NULL));
ofono_ril_transport_unregister(&test);
}
#define TEST_(name) "/ril-transport/" name
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
__ofono_log_init("test-ril_util",
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("register"), test_register);
g_test_add_func(TEST_("connect"), test_connect);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,864 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "drivers/ril/ril_config.h"
#include <ofono/log.h>
#include "ofono.h"
#include <gutil_strv.h>
#include <gutil_ints.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#define TMP_DIR_TEMPLATE "test-ril_config-XXXXXX"
static void test_get_value(const char *conf, void (*test)(GKeyFile *k))
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/test.conf", NULL);
GKeyFile *k = g_key_file_new();
g_assert(g_file_set_contents(file, conf, -1, NULL));
g_assert(g_key_file_load_from_file(k, file, 0, NULL));
DBG("%s:\n%s", file, conf);
test(k);
remove(file);
remove(dir);
g_key_file_unref(k);
g_free(file);
g_free(dir);
}
static gboolean test_keyfile_empty(GKeyFile *k)
{
gsize n = 0;
char **groups = g_key_file_get_groups(k, &n);
g_strfreev(groups);
return !n;
}
static void test_merge_ignore(const char *filename, const char *contents,
const char *dirname, const char *filename1, const char *contents1)
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/", filename, NULL);
char *subdir = g_strconcat(dir, "/", dirname, NULL);
char *file1 = g_strconcat(subdir, "/", filename1, NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(file1);
remove(subdir);
remove(dir);
g_free(file);
g_free(file1);
g_free(dir);
g_free(subdir);
}
static void test_merge1(const char *conf, const char *conf1, const char *out)
{
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *file1 = g_strconcat(subdir, "/bar.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, conf, -1, NULL));
g_assert(g_file_set_contents(file1, conf1, -1, NULL));
DBG("reading %s", file);
g_key_file_set_list_separator(k, ',');
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, out));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(file1);
remove(subdir);
remove(dir);
g_free(file);
g_free(file1);
g_free(dir);
g_free(subdir);
}
/* ==== get_string ==== */
static void test_get_string0_cb(GKeyFile *k)
{
char *value = ril_config_get_string(k, "g", "k");
g_assert(!g_strcmp0(value, "v"));
g_free(value);
g_assert(!ril_config_get_string(k, RILCONF_SETTINGS_GROUP, "k"));
g_assert(!ril_config_get_string(k, "foo", "k"));
}
static void test_get_string0(void)
{
static const char conf [] = "[g]\nk=v\n";
test_get_value(conf, test_get_string0_cb);
}
static void test_get_string1_cb(GKeyFile *k)
{
char *value = ril_config_get_string(k, RILCONF_SETTINGS_GROUP, "k");
g_assert(!g_strcmp0(value, "v"));
g_free(value);
value = ril_config_get_string(k, "g", "k");
g_assert(!g_strcmp0(value, "v"));
g_free(value);
}
static void test_get_string1(void)
{
static const char conf [] = "[" RILCONF_SETTINGS_GROUP "]\nk=v\n";
test_get_value(conf, test_get_string1_cb);
}
static void test_get_string2_cb(GKeyFile *k)
{
char *value = ril_config_get_string(k, RILCONF_SETTINGS_GROUP, "k");
g_assert(!g_strcmp0(value, "v1"));
g_free(value);
value = ril_config_get_string(k, "g", "k");
g_assert(!g_strcmp0(value, "v2"));
g_free(value);
value = ril_config_get_string(k, "g1", "k");
g_assert(!g_strcmp0(value, "v1"));
g_free(value);
}
static void test_get_string2(void)
{
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk=v1\n\n"
"[g]\nk=v2\n";
test_get_value(conf, test_get_string2_cb);
}
/* ==== get_strings ==== */
static void test_get_strings0_cb(GKeyFile *k)
{
char **values = ril_config_get_strings(k, "g", "k", ',');
g_assert(values);
g_assert(gutil_strv_length(values) == 0);
g_strfreev(values);
values = ril_config_get_strings(k, RILCONF_SETTINGS_GROUP, "k", ',');
g_assert(values);
g_assert(gutil_strv_length(values) == 0);
g_strfreev(values);
}
static void test_get_strings0(void)
{
static const char conf [] = "[" RILCONF_SETTINGS_GROUP "]\nk=\n";
test_get_value(conf, test_get_strings0_cb);
}
static void test_get_strings1_cb(GKeyFile *k)
{
char **values = ril_config_get_strings(k, "g", "k", ',');
g_assert(gutil_strv_length(values) == 2);
g_assert(!g_strcmp0(values[0], "v0"));
g_assert(!g_strcmp0(values[1], "v1"));
g_strfreev(values);
g_assert(!ril_config_get_strings(k, RILCONF_SETTINGS_GROUP, "k", ','));
}
static void test_get_strings1(void)
{
static const char conf [] = "[g]\nk=v0 , v1\n";
test_get_value(conf, test_get_strings1_cb);
}
/* ==== get_integer ==== */
static void test_get_integer0_cb(GKeyFile *k)
{
int val = -1;
g_assert(!ril_config_get_integer(k, "g1", "k1", NULL));
g_assert(!ril_config_get_integer(k, "g1", "k1", &val));
g_assert(val == -1);
g_assert(ril_config_get_integer(k, "g", "k", NULL));
g_assert(ril_config_get_integer(k, "g", "k", &val));
g_assert(val == 1);
g_assert(ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", &val));
g_assert(val == 0);
}
static void test_get_integer0(void)
{
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk=0\n\n"
"[g]\nk=1\n";
test_get_value(conf, test_get_integer0_cb);
}
static void test_get_integer1_cb(GKeyFile *k)
{
int val = -1;
g_assert(!ril_config_get_integer(k, "g", "k", NULL));
g_assert(!ril_config_get_integer(k, "g", "k", &val));
g_assert(val == -1);
g_assert(!ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", NULL));
g_assert(!ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", &val));
g_assert(val == -1);
}
static void test_get_integer1(void)
{
/* Invalid integer values */
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk=foo\n\n"
"[g]\nk=bar\n";
test_get_value(conf, test_get_integer1_cb);
}
static void test_get_integer2_cb(GKeyFile *k)
{
int val = -1;
g_assert(ril_config_get_integer(k, "g", "k", NULL));
g_assert(ril_config_get_integer(k, "g", "k", &val));
g_assert(val == 1);
g_assert(ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", NULL));
g_assert(ril_config_get_integer(k, RILCONF_SETTINGS_GROUP, "k", &val));
g_assert(val == 1);
}
static void test_get_integer2(void)
{
/* Invalid value in [g] but a valid one in [Settings] */
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk=1\n"
"\n[g]\nk=foo\n";
test_get_value(conf, test_get_integer2_cb);
}
/* ==== get_boolean ==== */
static void test_get_boolean0_cb(GKeyFile *k)
{
gboolean val = FALSE;
g_assert(!ril_config_get_boolean(k, "g1", "k1", NULL));
g_assert(!ril_config_get_boolean(k, "g1", "k1", &val));
g_assert(!val);
g_assert(ril_config_get_boolean(k, "g", "k", NULL));
g_assert(ril_config_get_boolean(k, "g", "k", &val));
g_assert(val == TRUE);
g_assert(ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", &val));
g_assert(val == FALSE);
}
static void test_get_boolean0(void)
{
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk=false\n\n"
"[g]\nk=true\n";
test_get_value(conf, test_get_boolean0_cb);
}
static void test_get_boolean1_cb(GKeyFile *k)
{
gboolean val = TRUE;
g_assert(!ril_config_get_boolean(k, "g", "k", NULL));
g_assert(!ril_config_get_boolean(k, "g", "k", &val));
g_assert(val == TRUE);
g_assert(!ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", NULL));
g_assert(!ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", &val));
g_assert(val == TRUE);
}
static void test_get_boolean1(void)
{
/* Invalid boolean values */
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk=foo\n\n"
"[g]\nk=bar\n";
test_get_value(conf, test_get_boolean1_cb);
}
static void test_get_boolean2_cb(GKeyFile *k)
{
gboolean val = FALSE;
g_assert(ril_config_get_boolean(k, "g", "k", NULL));
g_assert(ril_config_get_boolean(k, "g", "k", &val));
g_assert(val == TRUE);
g_assert(ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", NULL));
g_assert(ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", &val));
g_assert(val == TRUE);
}
static void test_get_boolean2(void)
{
/* Invalid value in [g] but a valid one in [Settings] */
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk=true\n"
"\n[g]\nk=foo\n";
test_get_value(conf, test_get_boolean2_cb);
}
static void test_get_boolean3_cb(GKeyFile *k)
{
gboolean val = FALSE;
g_assert(ril_config_get_boolean(k, "g", "k", NULL));
g_assert(ril_config_get_boolean(k, "g", "k", &val));
g_assert(val == TRUE);
g_assert(!ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", NULL));
g_assert(!ril_config_get_boolean(k, RILCONF_SETTINGS_GROUP, "k", &val));
g_assert(val == TRUE);
}
static void test_get_boolean3(void)
{
/* Valid value in [g] and invalid one in [Settings] */
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk=foo\n\n"
"[g]\nk=true\n";
test_get_value(conf, test_get_boolean3_cb);
}
/* ==== get_flag ==== */
static void test_get_flag_cb(GKeyFile *k)
{
const int f = 0x01;
int mask = 0;
g_assert(!ril_config_get_flag(k, "g1", "k1", f, &mask));
g_assert(!mask);
g_assert(ril_config_get_flag(k, "g", "k", f, &mask));
g_assert(mask & f);
g_assert(ril_config_get_flag(k, RILCONF_SETTINGS_GROUP, "k", f, &mask));
g_assert(!(mask & f));
}
static void test_get_flag(void)
{
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk=false\n\n"
"[g]\nk=true\n";
test_get_value(conf, test_get_flag_cb);
}
/* ==== get_enum ==== */
static void test_get_enum_cb(GKeyFile *k)
{
int val = 0;
g_assert(!ril_config_get_enum(k, "g1", "k1", &val, "foo", 1, NULL));
g_assert(!val);
g_assert(!ril_config_get_enum(k, "g", "k", NULL, "foo", 1, NULL));
g_assert(!ril_config_get_enum(k, "g", "k", &val, "foo", 1, NULL));
g_assert(!val);
g_assert(ril_config_get_enum(k,"g","k",NULL,"foo",1,"bar",2,NULL));
g_assert(ril_config_get_enum(k,"g","k",&val,"bar",2,"foo",1,NULL));
g_assert(val == 2);
g_assert(ril_config_get_enum(k, "g", "x", NULL,
"a", 1, "b", 2, "y", 3, NULL));
g_assert(ril_config_get_enum(k, "g", "x", &val,
"a", 1, "b", 2, "y", 3, NULL));
g_assert(val == 3);
g_assert(ril_config_get_enum(k, RILCONF_SETTINGS_GROUP, "k", NULL,
"foo", 1, NULL));
g_assert(ril_config_get_enum(k, RILCONF_SETTINGS_GROUP, "k", &val,
"foo", 1, NULL));
g_assert(val == 1);
}
static void test_get_enum(void)
{
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk= foo# comment\n\n"
"[g]\nk= bar \nx=y\n";
test_get_value(conf, test_get_enum_cb);
}
/* ==== get_ints ==== */
static void test_get_ints_cb(GKeyFile *k)
{
GUtilInts *ints;
const int* data;
guint count;
g_assert(!ril_config_get_ints(k, "g1", "k1"));
g_assert(!ril_config_get_ints(k, "g", "k2")); /* Empty */
ints = ril_config_get_ints(k, "g", "k");
data = gutil_ints_get_data(ints, &count);
g_assert(count == 2);
g_assert(data[0] == 0);
g_assert(data[1] == 1);
gutil_ints_unref(ints);
ints = ril_config_get_ints(k, "g", "k1");
data = gutil_ints_get_data(ints, &count);
g_assert(count == 3);
g_assert(data[0] == 2);
g_assert(data[1] == 3);
g_assert(data[2] == 4);
gutil_ints_unref(ints);
}
static void test_get_ints(void)
{
static const char conf [] =
"[" RILCONF_SETTINGS_GROUP "]\nk = 0, 1, x\n"
"[g]\nk1=2,3,4 # comment\nk2=\n";
test_get_value(conf, test_get_ints_cb);
}
/* ==== ints_to_string ==== */
static void test_ints_to_string(void)
{
static const int data[] = { 1, 2 };
GUtilInts* ints = gutil_ints_new_static(data, G_N_ELEMENTS(data));
char *str = ril_config_ints_to_string(ints, ',');
g_assert(!g_strcmp0(str, "1,2"));
g_free(str);
gutil_ints_unref(ints);
g_assert(!ril_config_ints_to_string(NULL, 0));
}
/* ==== merge_basic ==== */
static void test_merge_basic(void)
{
GKeyFile *k = g_key_file_new();
char *nonexistent = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
ril_config_merge_files(NULL, NULL);
remove(nonexistent);
ril_config_merge_files(k, nonexistent);
g_assert(test_keyfile_empty(k));
ril_config_merge_files(k, NULL);
g_assert(test_keyfile_empty(k));
ril_config_merge_files(k, "");
g_assert(test_keyfile_empty(k));
g_key_file_unref(k);
g_free(nonexistent);
}
/* ==== merge_simple ==== */
static void test_merge_simple(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
char *data;
GKeyFile *k = g_key_file_new();
g_assert(g_file_set_contents(file, contents, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(dir);
g_free(file);
g_free(dir);
}
/* ==== merge_empty_dir ==== */
static void test_merge_empty_dir(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(subdir);
remove(dir);
g_free(file);
g_free(dir);
g_free(subdir);
}
/* ==== merge_ignore ==== */
static void test_merge_ignore0(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *subdir2 = g_strconcat(subdir, "/dir.conf", NULL);
char *file = g_strconcat(dir, "/foo.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
/* Two empty subdirectories, one with matching name, one not */
g_assert(!mkdir(subdir, 0700));
g_assert(!mkdir(subdir2, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, contents));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(subdir2);
remove(subdir);
remove(dir);
g_free(file);
g_free(dir);
g_free(subdir);
g_free(subdir2);
}
static void test_merge_ignore1(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\nb=3\n";
/* File has no suffix */
test_merge_ignore("foo.conf", contents, "foo.d", "file", contents1);
}
static void test_merge_ignore2(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[[[[[[[";
/* File is not a valid keyfile */
test_merge_ignore("foo.conf", contents, "foo.d", "a.conf", contents1);
}
/* ==== merge_sort ==== */
static void test_merge_sort(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\nb=3\n";
static const char contents2 [] = "[foo]\nb=4\n";
static const char result [] = "[foo]\na=1\nb=4\n";
/* Test file sort order */
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
char *file = g_strconcat(dir, "/foo.", NULL);
char *subdir = g_strconcat(dir, "/foo.d", NULL);
char *file1 = g_strconcat(subdir, "/1.conf", NULL);
char *file2 = g_strconcat(subdir, "/2.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, contents, -1, NULL));
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
g_assert(g_file_set_contents(file2, contents2, -1, NULL));
DBG("reading %s", file);
ril_config_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, result));
g_free(data);
g_key_file_unref(k);
remove(file);
remove(file1);
remove(file2);
remove(subdir);
remove(dir);
g_free(file);
g_free(file1);
g_free(file2);
g_free(dir);
g_free(subdir);
}
/* ==== merge_remove_group ==== */
static void test_merge_remove_group(void)
{
static const char contents [] = "[foo]\na=1\n\n[bar]\nb=1\n";
static const char contents1 [] = "[!bar]\n";
static const char result [] = "[foo]\na=1\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_remove_key ==== */
static void test_merge_remove_key(void)
{
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\n!b=\n\n!=\n";
static const char result [] = "[foo]\na=1\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_default_value ==== */
static void test_merge_default_value(void)
{
/* b is assigned the default value, a stays as is */
static const char contents [] = "[foo]\na=1\n";
static const char contents1 [] = "[foo]\na:=2\nb:=3\n";
static const char result [] = "[foo]\na=1\nb=3\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_list_add ==== */
static void test_merge_list_add0(void)
{
/* Adding empty list */
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\na+=\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_add1(void)
{
/* a=1 turns into a=1,2, */
static const char contents [] = "[foo]\na=1\nb=2\n";
static const char contents1 [] = "[foo]\na+=2,\n";
static const char result [] = "[foo]\na=1,2,\nb=2\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_add2(void)
{
/* 2 is already there */
static const char contents [] = "[foo]\na=1,2,\nb=2\n";
static const char contents1 [] = "[foo]\na?=2\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_add3(void)
{
/* 2 is already there, 3 is not */
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na?=2,3,\n";
static const char result [] = "[foo]\na=1,2,3,\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_add4(void)
{
/* b=2,3, is created */
static const char contents [] = "[foo]\na=1\n";
static const char contents1 [] = "[foo]\nb?=2,3,\n";
static const char result [] = "[foo]\na=1\nb=2,3,\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_add5(void)
{
/* Add a new group */
static const char contents [] = "[foo]\na=1\n";
static const char contents1 [] = "[bar]\nb=2\n";
static const char result [] = "[foo]\na=1\n\n[bar]\nb=2\n";
test_merge1(contents, contents1, result);
}
/* ==== merge_list_remove ==== */
static void test_merge_list_remove0(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na-=\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_remove1(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na-=2,\n";
static const char result [] = "[foo]\na=1,\n";
test_merge1(contents, contents1, result);
}
static void test_merge_list_remove2(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\na-=3\n";
test_merge1(contents, contents1, contents);
}
static void test_merge_list_remove3(void)
{
static const char contents [] = "[foo]\na=1,2,\n";
static const char contents1 [] = "[foo]\nb-=1\n";
test_merge1(contents, contents1, contents);
}
#define TEST_(name) "/ril_config/" name
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
__ofono_log_init("test-ril_config",
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
g_test_add_func(TEST_("get_string0"), test_get_string0);
g_test_add_func(TEST_("get_string1"), test_get_string1);
g_test_add_func(TEST_("get_string2"), test_get_string2);
g_test_add_func(TEST_("get_strings0"), test_get_strings0);
g_test_add_func(TEST_("get_strings1"), test_get_strings1);
g_test_add_func(TEST_("get_integer0"), test_get_integer0);
g_test_add_func(TEST_("get_integer1"), test_get_integer1);
g_test_add_func(TEST_("get_integer2"), test_get_integer2);
g_test_add_func(TEST_("get_boolean0"), test_get_boolean0);
g_test_add_func(TEST_("get_boolean1"), test_get_boolean1);
g_test_add_func(TEST_("get_boolean2"), test_get_boolean2);
g_test_add_func(TEST_("get_boolean3"), test_get_boolean3);
g_test_add_func(TEST_("get_flag"), test_get_flag);
g_test_add_func(TEST_("get_enum"), test_get_enum);
g_test_add_func(TEST_("get_ints"), test_get_ints);
g_test_add_func(TEST_("ints_to_string"), test_ints_to_string);
g_test_add_func(TEST_("merge_basic"), test_merge_basic);
g_test_add_func(TEST_("merge_simple"), test_merge_simple);
g_test_add_func(TEST_("merge_empty_dir"), test_merge_empty_dir);
g_test_add_func(TEST_("merge_ignore0"), test_merge_ignore0);
g_test_add_func(TEST_("merge_ignore1"), test_merge_ignore1);
g_test_add_func(TEST_("merge_ignore2"), test_merge_ignore2);
g_test_add_func(TEST_("merge_sort"), test_merge_sort);
g_test_add_func(TEST_("merge_remove_group"), test_merge_remove_group);
g_test_add_func(TEST_("merge_remove_key"), test_merge_remove_key);
g_test_add_func(TEST_("merge_default_value"), test_merge_default_value);
g_test_add_func(TEST_("merge_list_add0"), test_merge_list_add0);
g_test_add_func(TEST_("merge_list_add1"), test_merge_list_add1);
g_test_add_func(TEST_("merge_list_add2"), test_merge_list_add2);
g_test_add_func(TEST_("merge_list_add3"), test_merge_list_add3);
g_test_add_func(TEST_("merge_list_add4"), test_merge_list_add4);
g_test_add_func(TEST_("merge_list_add5"), test_merge_list_add5);
g_test_add_func(TEST_("merge_list_remove0"), test_merge_list_remove0);
g_test_add_func(TEST_("merge_list_remove1"), test_merge_list_remove1);
g_test_add_func(TEST_("merge_list_remove2"), test_merge_list_remove2);
g_test_add_func(TEST_("merge_list_remove3"), test_merge_list_remove3);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -81,27 +81,6 @@ void test_parse_mcc_mnc(void)
g_assert(!op.tech);
}
void test_parse_int(void)
{
int value;
g_assert(!ril_parse_int(NULL, 0, NULL));
g_assert(!ril_parse_int("", 0, NULL));
g_assert(!ril_parse_int("garbage", 0, NULL));
g_assert(!ril_parse_int("0 trailing garbage", 0, NULL));
g_assert(ril_parse_int("0", 0, NULL));
g_assert(ril_parse_int("0", 0, &value));
g_assert(value == 0);
g_assert(!ril_parse_int("0x10000000000000000", 0, &value));
g_assert(!ril_parse_int("-2147483649", 0, &value));
g_assert(!ril_parse_int("4294967295", 0, &value));
g_assert(ril_parse_int(" 0x7fffffff ", 0, &value));
g_assert(value == 0x7fffffff);
g_assert(ril_parse_int(" 7fffffff ", 16, &value));
g_assert(value == 0x7fffffff);
g_assert(!ril_parse_int("0xffffffff", 0, &value));
}
void test_strings(void)
{
g_assert(!g_strcmp0(ril_error_to_string(RIL_E_SUCCESS), "OK"));
@@ -128,7 +107,6 @@ int main(int argc, char *argv[])
g_test_add_func(TEST_("parse_tech"), test_parse_tech);
g_test_add_func(TEST_("parse_mcc_mnc"), test_parse_mcc_mnc);
g_test_add_func(TEST_("parse_int"), test_parse_int);
g_test_add_func(TEST_("strings"), test_strings);
return g_test_run();

View File

@@ -0,0 +1,710 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 <sailfish_watch.h>
#include "ofono.h"
#include <gutil_log.h>
static GSList *g_modem_list = NULL;
static struct ofono_watchlist *g_modemwatches = NULL;
#define TEST_PATH "/test_0"
#define TEST_PATH_1 "/test_1"
#define TEST_ICCID "0000000000000000000"
#define TEST_IMSI "244120000000000"
#define TEST_SPN "Test"
/* Fake ofono_atom */
struct ofono_atom {
enum ofono_atom_type type;
gboolean registered;
void *data;
struct ofono_modem *modem;
};
void *__ofono_atom_get_data(struct ofono_atom *atom)
{
return atom->data;
}
/* Fake ofono_netreg */
struct ofono_netreg {
struct ofono_atom atom;
};
/* Fake ofono_sim */
struct ofono_sim {
struct ofono_atom atom;
const char *spn;
const char *spn_dc;
const char *imsi;
const char *iccid;
enum ofono_sim_state state;
struct ofono_watchlist *spn_watches;
struct ofono_watchlist *imsi_watches;
struct ofono_watchlist *iccid_watches;
struct ofono_watchlist *state_watches;
};
static unsigned int add_watch_item(struct ofono_watchlist *list,
void *notify, void *data, ofono_destroy_func destroy)
{
struct ofono_watchlist_item *watch =
g_new0(struct ofono_watchlist_item, 1);
watch->notify = notify;
watch->destroy = destroy;
watch->notify_data = data;
return __ofono_watchlist_add_item(list, watch);
}
unsigned int ofono_sim_add_iccid_watch(struct ofono_sim *sim,
ofono_sim_iccid_event_cb_t cb, void *data,
ofono_destroy_func destroy)
{
guint id = add_watch_item(sim->iccid_watches, cb, data, destroy);
if (sim->iccid) {
cb(sim->iccid, data);
}
return id;
}
void ofono_sim_remove_iccid_watch(struct ofono_sim *sim, unsigned int id)
{
__ofono_watchlist_remove_item(sim->iccid_watches, id);
}
static void iccid_watches_cb(gpointer data, gpointer user_data)
{
struct ofono_sim *sim = user_data;
struct ofono_watchlist_item *item = data;
ofono_sim_iccid_event_cb_t cb = item->notify;
cb(sim->iccid, item->notify_data);
}
static inline void iccid_watches_notify(struct ofono_sim *sim)
{
g_slist_foreach(sim->iccid_watches->items, iccid_watches_cb, sim);
}
unsigned int ofono_sim_add_imsi_watch(struct ofono_sim *sim,
ofono_sim_imsi_event_cb_t cb, void *data,
ofono_destroy_func destroy)
{
guint id = add_watch_item(sim->imsi_watches, cb, data, destroy);
if (sim->imsi) {
cb(sim->imsi, data);
}
return id;
}
void ofono_sim_remove_imsi_watch(struct ofono_sim *sim, unsigned int id)
{
__ofono_watchlist_remove_item(sim->imsi_watches, id);
}
static void imsi_watches_cb(gpointer data, gpointer user_data)
{
struct ofono_sim *sim = user_data;
struct ofono_watchlist_item *item = data;
ofono_sim_imsi_event_cb_t cb = item->notify;
cb(sim->imsi, item->notify_data);
}
static inline void imsi_watches_notify(struct ofono_sim *sim)
{
g_slist_foreach(sim->imsi_watches->items, imsi_watches_cb, sim);
}
ofono_bool_t ofono_sim_add_spn_watch(struct ofono_sim *sim, unsigned int *id,
ofono_sim_spn_cb_t cb, void *data, ofono_destroy_func destroy)
{
*id = add_watch_item(sim->spn_watches, cb, data, destroy);
if (sim->spn) {
cb(sim->spn, sim->spn_dc, data);
}
return TRUE;
}
ofono_bool_t ofono_sim_remove_spn_watch(struct ofono_sim *sim, unsigned int *id)
{
if (__ofono_watchlist_remove_item(sim->spn_watches, *id)) {
*id = 0;
return TRUE;
} else {
return FALSE;
}
}
static void spn_watches_cb(gpointer data, gpointer user_data)
{
struct ofono_sim *sim = user_data;
struct ofono_watchlist_item *item = data;
ofono_sim_spn_cb_t notify = item->notify;
notify(sim->spn, sim->spn_dc, item->notify_data);
}
static inline void spn_watches_notify(struct ofono_sim *sim)
{
g_slist_foreach(sim->spn_watches->items, spn_watches_cb, sim);
}
unsigned int ofono_sim_add_state_watch(struct ofono_sim *sim,
ofono_sim_state_event_cb_t notify,
void *data, ofono_destroy_func destroy)
{
return add_watch_item(sim->state_watches, notify, data, destroy);
}
void ofono_sim_remove_state_watch(struct ofono_sim *sim, unsigned int id)
{
__ofono_watchlist_remove_item(sim->state_watches, id);
}
static void state_watches_cb(gpointer data, gpointer user_data)
{
struct ofono_sim *sim = user_data;
struct ofono_watchlist_item *item = data;
ofono_sim_state_event_cb_t notify = item->notify;
notify(sim->state, item->notify_data);
}
static void state_watches_notify(struct ofono_sim *sim)
{
g_slist_foreach(sim->state_watches->items, state_watches_cb, sim);
}
/* Fake modem */
struct ofono_modem {
const char *path;
gboolean online;
GSList *atoms;
struct ofono_watchlist *atom_watches;
struct ofono_watchlist *online_watches;
struct ofono_sim sim;
struct ofono_netreg netreg;
};
struct atom_watch {
struct ofono_watchlist_item item;
enum ofono_atom_type type;
};
void __ofono_modemwatch_init(void)
{
g_assert(!g_modem_list);
g_assert(!g_modemwatches);
g_modemwatches = __ofono_watchlist_new(g_free);
}
void __ofono_modemwatch_cleanup(void)
{
g_assert(!g_modem_list);
__ofono_watchlist_free(g_modemwatches);
g_modemwatches = NULL;
}
unsigned int __ofono_modemwatch_add(ofono_modemwatch_cb_t cb, void *data,
ofono_destroy_func destroy)
{
return add_watch_item(g_modemwatches, cb, data, destroy);
}
gboolean __ofono_modemwatch_remove(unsigned int id)
{
return __ofono_watchlist_remove_item(g_modemwatches, id);
}
static void call_modemwatches(struct ofono_modem *modem, gboolean added)
{
GSList *l;
DBG("%p added:%d", modem, added);
for (l = g_modemwatches->items; l; l = l->next) {
struct ofono_watchlist_item *watch = l->data;
ofono_modemwatch_cb_t notify = watch->notify;
notify(modem, added, watch->notify_data);
}
}
const char *ofono_modem_get_path(struct ofono_modem *modem)
{
return modem->path;
}
ofono_bool_t ofono_modem_get_online(struct ofono_modem *modem)
{
return modem && modem->online;
}
struct ofono_modem *ofono_modem_find(ofono_modem_compare_cb_t func,
void *user_data)
{
GSList *l;
for (l = g_modem_list; l; l = l->next) {
struct ofono_modem *modem = l->data;
if (func(modem, user_data)) {
return modem;
}
}
return NULL;
}
unsigned int __ofono_modem_add_atom_watch(struct ofono_modem *modem,
enum ofono_atom_type type, ofono_atom_watch_func notify,
void *data, ofono_destroy_func destroy)
{
GSList *l;
unsigned int id;
struct atom_watch *watch = g_new0(struct atom_watch, 1);
watch->type = type;
watch->item.notify = notify;
watch->item.destroy = destroy;
watch->item.notify_data = data;
id = __ofono_watchlist_add_item(modem->atom_watches, &watch->item);
for (l = modem->atoms; l; l = l->next) {
struct ofono_atom *atom = l->data;
if (atom->type == type && atom->registered) {
notify(atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED,
data);
}
}
return id;
}
static void call_watches(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond)
{
GSList *l;
for (l = atom->modem->atom_watches->items; l; l = l->next) {
struct atom_watch *watch = l->data;
if (watch->type == atom->type) {
ofono_atom_watch_func notify = watch->item.notify;
notify(atom, cond, watch->item.notify_data);
}
}
}
gboolean __ofono_modem_remove_atom_watch(struct ofono_modem *modem,
unsigned int id)
{
return __ofono_watchlist_remove_item(modem->atom_watches, id);
}
unsigned int __ofono_modem_add_online_watch(struct ofono_modem *modem,
ofono_modem_online_notify_func notify,
void *data, ofono_destroy_func destroy)
{
return add_watch_item(modem->online_watches, notify, data, destroy);
}
void __ofono_modem_remove_online_watch(struct ofono_modem *modem,
unsigned int id)
{
__ofono_watchlist_remove_item(modem->online_watches, id);
}
static void notify_online_watches_cb(gpointer data, gpointer user_data)
{
struct ofono_modem *modem = user_data;
struct ofono_watchlist_item *item = data;
ofono_modem_online_notify_func notify = item->notify;
notify(modem, modem->online, item->notify_data);
}
static void notify_online_watches(struct ofono_modem *modem)
{
g_slist_foreach(modem->online_watches->items,
notify_online_watches_cb, modem);
}
/* Utilities */
static void test_modem_register_atom(struct ofono_modem *modem,
struct ofono_atom *atom)
{
if (!atom->registered) {
atom->registered = TRUE;
modem->atoms = g_slist_append(modem->atoms, atom);
call_watches(atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED);
}
}
static void test_modem_unregister_atom(struct ofono_modem *modem,
struct ofono_atom *atom)
{
if (atom->registered) {
atom->registered = FALSE;
call_watches(atom, OFONO_ATOM_WATCH_CONDITION_UNREGISTERED);
modem->atoms = g_slist_remove(modem->atoms, atom);
}
}
static void test_modem_init1(struct ofono_modem *modem, const char *path)
{
struct ofono_netreg *netreg = &modem->netreg;
struct ofono_sim *sim = &modem->sim;
/* Assume that the structure has been zero-initialized */
modem->path = path;
modem->atom_watches = __ofono_watchlist_new(g_free);
modem->online_watches = __ofono_watchlist_new(g_free);
netreg->atom.type = OFONO_ATOM_TYPE_NETREG;
netreg->atom.modem = modem;
netreg->atom.data = netreg;
sim->atom.type = OFONO_ATOM_TYPE_SIM;
sim->atom.modem = modem;
sim->atom.data = sim;
sim->iccid_watches = __ofono_watchlist_new(g_free);
sim->imsi_watches = __ofono_watchlist_new(g_free);
sim->state_watches = __ofono_watchlist_new(g_free);
sim->spn_watches = __ofono_watchlist_new(g_free);
sim->state = OFONO_SIM_STATE_NOT_PRESENT;
g_modem_list = g_slist_prepend(g_modem_list, modem);
call_modemwatches(modem, TRUE);
}
static void test_modem_init(struct ofono_modem *modem)
{
test_modem_init1(modem, TEST_PATH);
}
static void test_modem_shutdown(struct ofono_modem *modem)
{
struct ofono_sim *sim = &modem->sim;
call_modemwatches(modem, FALSE);
g_modem_list = g_slist_remove(g_modem_list, modem);
g_slist_free(modem->atoms);
__ofono_watchlist_free(sim->iccid_watches);
__ofono_watchlist_free(sim->imsi_watches);
__ofono_watchlist_free(sim->state_watches);
__ofono_watchlist_free(sim->spn_watches);
__ofono_watchlist_free(modem->atom_watches);
__ofono_watchlist_free(modem->online_watches);
}
static void test_inc_cb(struct sailfish_watch *watch, void *user_data)
{
(*((int *)user_data))++;
}
/* ==== basic ==== */
static void test_basic(void)
{
struct sailfish_watch *watch;
struct sailfish_watch *watch1;
struct ofono_modem modem, modem1;
/* NULL resistance */
g_assert(!sailfish_watch_new(NULL));
g_assert(!sailfish_watch_ref(NULL));
sailfish_watch_unref(NULL);
g_assert(!sailfish_watch_add_modem_changed_handler(NULL, NULL, NULL));
g_assert(!sailfish_watch_add_online_changed_handler(NULL, NULL, NULL));
g_assert(!sailfish_watch_add_sim_changed_handler(NULL, NULL, NULL));
g_assert(!sailfish_watch_add_sim_state_changed_handler(NULL, NULL,
NULL));
g_assert(!sailfish_watch_add_iccid_changed_handler(NULL, NULL, NULL));
g_assert(!sailfish_watch_add_imsi_changed_handler(NULL, NULL, NULL));
g_assert(!sailfish_watch_add_spn_changed_handler(NULL, NULL, NULL));
g_assert(!sailfish_watch_add_netreg_changed_handler(NULL, NULL, NULL));
sailfish_watch_remove_handler(NULL, 0);
sailfish_watch_remove_handlers(NULL, NULL, 0);
/* Instance caching */
memset(&modem, 0, sizeof(modem));
memset(&modem1, 0, sizeof(modem1));
__ofono_modemwatch_init();
test_modem_init1(&modem, TEST_PATH);
watch = sailfish_watch_new(TEST_PATH);
watch1 = sailfish_watch_new(TEST_PATH_1);
/* The second modem is added after the watch is created */
test_modem_init1(&modem1, TEST_PATH_1);
/* The second notification has no effect */
call_modemwatches(&modem1, TRUE);
g_assert(watch);
g_assert(watch1);
g_assert(watch->modem == &modem);
g_assert(watch1->modem == &modem1);
g_assert(sailfish_watch_new(TEST_PATH) == watch);
g_assert(sailfish_watch_new(TEST_PATH_1) == watch1);
sailfish_watch_unref(watch);
sailfish_watch_unref(watch1);
/* More NULLs and zeros */
g_assert(!sailfish_watch_add_modem_changed_handler(watch, NULL, NULL));
g_assert(!sailfish_watch_add_online_changed_handler(watch, NULL, NULL));
g_assert(!sailfish_watch_add_sim_changed_handler(watch, NULL, NULL));
g_assert(!sailfish_watch_add_sim_state_changed_handler(watch, NULL,
NULL));
g_assert(!sailfish_watch_add_iccid_changed_handler(watch, NULL, NULL));
g_assert(!sailfish_watch_add_imsi_changed_handler(watch, NULL, NULL));
g_assert(!sailfish_watch_add_spn_changed_handler(watch, NULL, NULL));
g_assert(!sailfish_watch_add_netreg_changed_handler(watch, NULL, NULL));
sailfish_watch_remove_handler(watch, 0);
sailfish_watch_remove_handlers(watch, NULL, 0);
/* The first modem is removed when the watch is still alive */
test_modem_shutdown(&modem);
sailfish_watch_unref(watch);
sailfish_watch_unref(watch1);
test_modem_shutdown(&modem1);
__ofono_modemwatch_cleanup();
}
/* ==== modem ==== */
static void test_modem(void)
{
struct sailfish_watch *watch;
struct ofono_modem modem;
gulong id;
int n = 0;
__ofono_modemwatch_init();
watch = sailfish_watch_new(TEST_PATH);
id = sailfish_watch_add_modem_changed_handler(watch, test_inc_cb, &n);
g_assert(id);
memset(&modem, 0, sizeof(modem));
test_modem_init(&modem);
g_assert(n == 1);
sailfish_watch_remove_handler(watch, id);
sailfish_watch_unref(watch);
test_modem_shutdown(&modem);
__ofono_modemwatch_cleanup();
}
/* ==== online ==== */
static void test_online(void)
{
struct sailfish_watch *watch;
struct ofono_modem modem;
gulong id;
int n = 0;
memset(&modem, 0, sizeof(modem));
__ofono_modemwatch_init();
test_modem_init(&modem);
watch = sailfish_watch_new(TEST_PATH);
g_assert(!watch->online);
modem.online = TRUE;
id = sailfish_watch_add_online_changed_handler(watch, test_inc_cb, &n);
notify_online_watches(&modem);
g_assert(watch->online);
g_assert(n == 1);
notify_online_watches(&modem); /* Second one has no effect */
g_assert(n == 1);
test_modem_shutdown(&modem);
g_assert(!watch->online);
g_assert(n == 2);
sailfish_watch_remove_handler(watch, id);
sailfish_watch_unref(watch);
__ofono_modemwatch_cleanup();
}
/* ==== netreg ==== */
static void test_netreg(void)
{
struct sailfish_watch *watch;
struct ofono_modem modem;
gulong id;
int n = 0;
memset(&modem, 0, sizeof(modem));
__ofono_modemwatch_init();
test_modem_init(&modem);
watch = sailfish_watch_new(TEST_PATH);
g_assert(!watch->netreg);
id = sailfish_watch_add_netreg_changed_handler(watch, test_inc_cb, &n);
test_modem_register_atom(&modem, &modem.netreg.atom);
g_assert(watch->netreg == &modem.netreg);
g_assert(n == 1);
test_modem_unregister_atom(&modem, &modem.netreg.atom);
g_assert(!watch->netreg);
g_assert(n == 2);
test_modem_register_atom(&modem, &modem.netreg.atom);
g_assert(watch->netreg == &modem.netreg);
g_assert(n == 3);
test_modem_shutdown(&modem);
g_assert(!watch->netreg);
g_assert(n == 4);
sailfish_watch_remove_handler(watch, id);
sailfish_watch_unref(watch);
__ofono_modemwatch_cleanup();
}
/* ==== sim ==== */
static void test_sim(void)
{
struct sailfish_watch *watch;
struct ofono_modem modem;
struct ofono_sim *sim = &modem.sim;
gulong id[4];
int n[G_N_ELEMENTS(id)];
#define SIM 0
#define ICCID 1
#define IMSI 2
#define SPN 3
memset(&modem, 0, sizeof(modem));
__ofono_modemwatch_init();
test_modem_init(&modem);
watch = sailfish_watch_new(TEST_PATH);
g_assert(!watch->iccid);
g_assert(!watch->imsi);
g_assert(!watch->spn);
memset(id, 0, sizeof(id));
memset(n, 0, sizeof(n));
id[SIM] = sailfish_watch_add_sim_changed_handler(watch,
test_inc_cb, n + SIM);
id[ICCID] = sailfish_watch_add_iccid_changed_handler(watch,
test_inc_cb, n + ICCID);
id[IMSI] = sailfish_watch_add_imsi_changed_handler(watch,
test_inc_cb, n + IMSI);
id[SPN] = sailfish_watch_add_spn_changed_handler(watch,
test_inc_cb, n + SPN);
test_modem_register_atom(&modem, &modem.sim.atom);
g_assert(watch->sim == &modem.sim);
g_assert(n[SIM] == 1);
/* Simulate insert */
sim->state = OFONO_SIM_STATE_INSERTED;
state_watches_notify(sim);
/* ICCID retrieval */
sim->iccid = TEST_ICCID;
iccid_watches_notify(sim);
g_assert(!g_strcmp0(watch->iccid, sim->iccid));
g_assert(n[ICCID] == 1);
/* EFspn retrieval */
sim->spn = TEST_SPN;
spn_watches_notify(sim);
/* Not yet... We first expect IMSI */
g_assert(!watch->spn);
g_assert(n[SPN] == 0);
sim->imsi = TEST_IMSI;
imsi_watches_notify(sim);
g_assert(!g_strcmp0(watch->imsi, sim->imsi));
g_assert(!g_strcmp0(watch->spn, sim->spn));
g_assert(n[IMSI] == 1);
g_assert(n[SPN] == 1);
/* Ready */
sim->state = OFONO_SIM_STATE_READY;
state_watches_notify(sim);
/* And finally remove the SIM */
sim->state = OFONO_SIM_STATE_NOT_PRESENT;
state_watches_notify(sim);
g_assert(!watch->iccid);
g_assert(!watch->imsi);
g_assert(!watch->spn);
g_assert(n[ICCID] == 2);
g_assert(n[IMSI] == 2);
g_assert(n[SPN] == 2);
test_modem_unregister_atom(&modem, &modem.sim.atom);
g_assert(!watch->sim);
g_assert(n[SIM] == 2);
sailfish_watch_remove_all_handlers(watch, id);
sailfish_watch_unref(watch);
test_modem_shutdown(&modem);
__ofono_modemwatch_cleanup();
}
#define TEST_(name) "/sailfish_watch/" name
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
gutil_log_timestamp = FALSE;
gutil_log_default.level = g_test_verbose() ?
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
__ofono_log_init("test-sailfish_watch",
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("modem"), test_modem);
g_test_add_func(TEST_("online"), test_online);
g_test_add_func(TEST_("netreg"), test_netreg);
g_test_add_func(TEST_("sim"), test_sim);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,8 @@ Source: %{name}-%{version}.tar.bz2
Requires: dbus
Requires: systemd
Requires: ofono-configs
Requires: libgrilio >= 1.0.20
Requires: libglibutil >= 1.0.23
Requires: libgrilio >= 1.0.25
Requires: libglibutil >= 1.0.30
Requires: mobile-broadband-provider-info
Requires(preun): systemd
Requires(post): systemd
@@ -21,8 +21,8 @@ BuildRequires: pkgconfig(dbus-glib-1)
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libudev) >= 145
BuildRequires: pkgconfig(libwspcodec) >= 2.0
BuildRequires: pkgconfig(libgrilio) >= 1.0.20
BuildRequires: pkgconfig(libglibutil) >= 1.0.23
BuildRequires: pkgconfig(libgrilio) >= 1.0.25
BuildRequires: pkgconfig(libglibutil) >= 1.0.30
BuildRequires: pkgconfig(libdbuslogserver-dbus)
BuildRequires: pkgconfig(libmce-glib) >= 1.0.5
BuildRequires: pkgconfig(mobile-broadband-provider-info)