Compare commits

..

122 Commits

Author SHA1 Message Date
Slava Monich
b5ed6d16db [ril] First fix permissions on top-level directories. JB#39961
... and then descend into subdirectories. Even though it doesn't
really matter since we are starting as root, it does seem to be
a bit more logical.
2017-10-13 18:32:28 +03:00
Slava Monich
fd0a1a9adb [ril] Fix storage directory permissions at startup. Fixes JB#39961
Also, made the identity configurable and got rid of hardcoded radio
uid and gid, those are now queried at runtime.
2017-10-13 18:32:28 +03:00
Slava Monich
49efa5bd18 [test] Added test-ril_util
Conflicts:
	ofono/unit/coverage
2017-10-13 18:32:26 +03:00
Slava Monich
e4a08ddb3f [ril] Added ril_parse_int utility 2017-10-13 18:31:48 +03:00
Slava Monich
b92ddd870e [ril] Don't mix slice and default allocators in ril_plugin.c
And it generally doesn't make sense to use slice allocator for allocating
the structures that are a) large and b) allocated at startup and not freed
until the program exits.
2017-10-13 18:31:48 +03:00
Slava Monich
09fa97c53a Merge branch 'default_timeout' into 'master'
Use default start timeout for default configuration

See merge request !148
2017-09-25 06:46:56 +00:00
Slava Monich
3eaa8a46bd [ril] Use default start timeout for default configuration. Fixes JB#39840
If /etc/ofono/ril_subscription.conf doesn't exist or doesn't contain
any modem sections (the latter is the case on Jolla 1 for historical
reasons) ofono falls back to the default configuration which should
use the default start timeout.
2017-09-23 18:07:57 +03:00
Slava Monich
4401319136 Merge branch 'ready' into 'master'
Set the ready flag if no drivers is registered with sailfish_manager

See merge request !147
2017-09-15 15:48:25 +00:00
Slava Monich
472ddcf0b1 Merge branch 'optionalmodem' into 'master'
Support for optional modems

See merge request !119
2017-09-15 15:48:09 +00:00
Slava Monich
b7e0f276a1 [ril] Support for optional modems. Fixes MER#1783 2017-09-15 17:14:57 +03:00
Slava Monich
5d251aea3a [ofono] More unit tests for the ready flag 2017-09-14 15:03:57 +03:00
Slava Monich
cdc0065284 [ofono] Set the ready flag if no drivers is registered with sailfish_manager. Fixes MER#1808
If there are no supported modems, ofono should be happy and the ready
flag should become true because the UI is waiting for this flag at
startup (and in this case there's nothing to wait for).
2017-09-14 15:01:45 +03:00
Slava Monich
6d65dc5bf0 Merge branch 'cellinfo' into 'master'
Move cell info API to the driver independent area.

See merge request !146
2017-09-14 08:39:03 +00:00
Slava Monich
5d02c0bba4 [ofono] Added unit test for sailfish_cell_info 2017-09-14 00:32:32 +03:00
Slava Monich
b99513e080 [ofono] Move cell info API to the driver independent area. Fixes JB#39725
So that it could be used by any driver, not just by RIL.
2017-09-14 00:29:13 +03:00
Slava Monich
3cf328c781 Merge branch 'ack' into 'master'
Support for logging new packet types (RIL v13)

See merge request !145
2017-09-12 13:36:33 +00:00
Slava Monich
bce68611a1 [ril] Support for logging new packet types (RIL v13). JB#39228 2017-09-12 00:18:52 +03:00
Slava Monich
cc497feee7 Merge branch 'online' into 'master'
Fix online state tracking

See merge request !143
2017-09-06 10:18:23 +00:00
Matti Kosola
725606af8d Merge branch 'jb39622' into 'master'
Handle normal call end with error cause.

See merge request !144
2017-09-06 08:58:25 +00:00
Juho Hämäläinen
52db6e5459 [ofono] Handle normal call end with error cause. Fixes JB#39622
With multi-sim setup we get last cause code 0xffff when incoming
call is ending due to other multi-sim phone answering the call.
Due to this handle the 0xffff as remote hangup if call status is
incoming.
2017-09-06 11:51:57 +03:00
Slava Monich
83441bc203 [ril] Fixed online state tracking. Fixes JB#39592 2017-09-05 12:14:52 +03:00
Slava Monich
4054f09b60 Merge branch 'samecaps' into 'master'
Avoid pointless radio caps switches

See merge request !142
2017-09-04 13:49:44 +00:00
Slava Monich
38aa8cff87 Merge branch 'cellinfo12' into 'master'
Support for RIL_CellInfo_v12

See merge request !141
2017-09-04 13:49:30 +00:00
Slava Monich
4959292938 [ofono] Avoid pointless radio caps switches. Fixes JB#39589
Not only it makes no sense, it can also get ofono into an infinite
switch loop.
2017-09-03 16:20:08 +02:00
Slava Monich
c69cea52cf [ofono] Support for RIL_CellInfo_v12. Fixes JB#39220
Required by RIL version 12 and above.
2017-09-03 16:12:56 +02:00
Slava Monich
4e0b8f7b48 Merge branch 'mms' into 'master'
Use REQUEST_SEND_SMS_EXPECT_MORE when appropriate

See merge request !140
2017-08-29 13:52:55 +00:00
Slava Monich
9c87063c4a [ril] Use REQUEST_SEND_SMS_EXPECT_MORE when appropriate
It's identical to RIL_REQUEST_SEND_SMS, except that more messages are
expected to be sent soon. If possible, SMS relay protocol link is kept
open (eg TS 27.005 AT+CMMS command)
2017-08-29 13:19:08 +03:00
Slava Monich
dc5a87f4f2 unit: Avoid use of uninitialised data in test-simutil
GTest: run: /testsimutil/ber tlv encode EFpnn
==16777== Conditional jump or move depends on uninitialised value(s)
==16777==    at 0x4068CB: ber_tlv_iter_next (simutil.c:369)
==16777==    by 0x406C39: ber_tlv_find_by_tag (simutil.c:483)
==16777==    by 0x407E1D: sim_eons_add_pnn_record (simutil.c:1027)
==16777==    by 0x402C39: test_ber_tlv_builder_efpnn (test-simutil.c:181)
==16777==    by 0x4EA3A80: g_test_run_suite_internal
==16777==    by 0x4EA3F9A: g_test_run_suite
==16777==    by 0x4EA3FD0: g_test_run
==16777==    by 0x4042FA: main (test-simutil.c:518)
2017-08-25 11:15:20 +03:00
Slava Monich
ecd35181a3 unit: test-sms: Fix memory leaks in the unit test 2017-08-25 01:41:06 +03:00
Slava Monich
96d6daf67e smsutil: Prevent invalid access in cbs_decode_text
Valgrind was complaining about it like this:

==18099== Conditional jump or move depends on uninitialised value(s)
==18099==    at 0x4C32281: strspn
==18099==    by 0x41286B: cbs_decode_text (smsutil.c:4140)
==18099==    by 0x40675C: test_cbs_encode_decode (test-sms.c:1417)
2017-08-25 01:38:16 +03:00
Slava Monich
e9702f6ec1 [ofono] sailfish_manager: require manager_create callback
Missing manager_create callback would cause a memory leak like this:

==9972== 96 bytes in 4 blocks are definitely lost in loss record 336 of 356
==9972==    at 0x483F3EC: malloc (vg_replace_malloc.c:299)
==9972==    by 0x4AEE0DF: g_malloc (gmem.c:94)
==9972==    by 0x4B03F51: g_slice_alloc (gslice.c:1025)
==9972==    by 0x4B0438F: g_slice_alloc0 (gslice.c:1051)
==9972==    by 0x1200B: sailfish_slot_manager_new (sailfish_manager.c:1019)
==9972==    by 0x12243: sailfish_slot_driver_init (sailfish_manager.c:1075)
==9972==    by 0x4AE906F: g_main_dispatch (gmain.c:3154)
==9972==    by 0x4AE906F: g_main_context_dispatch (gmain.c:3769)
==9972==    by 0x4AE931D: g_main_context_iterate.isra.4 (gmain.c:3840)
==9972==    by 0x4AE958F: g_main_loop_run (gmain.c:4034)
==9972==    by 0xACB7: test_basic (test-sailfish_manager.c:370)
==9972==    by 0x4B0B89F: test_case_run (gtestutils.c:2158)
==9972==    by 0x4B0B89F: g_test_run_suite_internal (gtestutils.c:2241)
==9972==    by 0x4B0BACD: g_test_run_suite_internal (gtestutils.c:2253)
2017-08-25 00:45:20 +03:00
Slava Monich
0746c615bc Merge branch 'protocol' into 'master'
Support for APN protocol in MBPI

See merge request !139
2017-08-24 21:44:36 +00:00
Slava Monich
970020a3b0 [ofono] Added tests for fetching APN protocol from MBPI. JB#39520 2017-08-24 17:45:13 +03:00
Slava Monich
f3d5e3d5c6 [ofono] mbpi: Add support for APN protocol in MBPI. Fixes #JB39520 2017-08-24 17:44:14 +03:00
Slava Monich
bb880ab14a Merge branch 'fix' into 'master'
Fix regressions after the recent huge merge

See merge request !137
2017-08-23 11:31:04 +00:00
Slava Monich
922d5e17ee [ril] Fixed a bug in ril_plugin_find_unused_slot. Fixes JB#39481
Both slots ended up with the same slot number wreaking all kinds of havoc
2017-08-23 12:40:47 +03:00
Slava Monich
7886ce04a1 [ril] Deserialize RIL I/O when SIM status becomes known. JB#39481 2017-08-23 12:39:53 +03:00
Slava Monich
5213398826 [ofono] Renamed __ofono_dbg -> ofono_dbg to allow binary plugins to use DBG macro
Only symbols starting with ofono_ can be resolved.
2017-08-22 18:11:55 +03:00
Slava Monich
0bbcc127be [ofono] Add test-sailfish_manager and test-sailfish_sim_info to the ignore list 2017-08-22 15:43:32 +03:00
Slava Monich
f7db0a0459 sms: Pass const pointer to dispatch_app_datagram 2017-08-22 15:39:28 +03:00
Slava Monich
2d18086c80 Merge branch 'sailfish_manager' into 'master'
Move Sailfish OS specific D-Bus interfaces to a separate plugin

See merge request !136
2017-08-22 12:15:27 +00:00
Slava Monich
0f4560c2eb [ofono] Moved RIL-independent stuff out of Sailfish OS RIL driver. JB#39257
The new sailfish_manager plugin contains the code necessary for
proper integration of ofono into Sailfish OS (mostly, that's
Sailfish OS specific D-Bus interfaces) and can be used by pretty
much any driver, not necessarily ril.
2017-08-22 12:07:01 +03:00
Slava Monich
7d80344d6b [ofono] network: Added ofono_netreg_get_name() function
Returns the name of the current operator.
2017-07-24 01:17:33 +03:00
Sergey Chupligin
c0c4148099 [ril] Added option to disable voicecall handling. Contributes to MER#1798 2017-07-21 15:34:39 +03:00
Slava Monich
34755f1a79 [ril] Housekeeping
Took out unnecessary include
2017-07-16 21:26:46 +03:00
Slava Monich
282d560c37 [ril] Changed the name of the common section in the error statistics file
Trying to get rid of RIL specific names, before it's too late.
2017-07-16 15:37:59 +03:00
Slava Monich
e4bca84876 [pushforwarder] Housekeeping
Removed unnecessary checks for memory allocation failures.

Replaced inotify stuff with a simpler version of the same thing -
since we already depend on libglibutil, there's no reason not to
use functions from there.
2017-07-15 12:54:15 +03:00
Slava Monich
aa0ded78b0 Merge branch 'slow_down' into 'master'
Serialize critical request sequences

See merge request !132
2017-07-13 18:40:45 +00:00
Slava Monich
eb15b12caf [ril] Don't start radio caps switch until SIM I/O calms down. JB#38689
That seems to significantly reduce the probability of a failure at startup
(we are reading the phonebook right after SIM interface is initialized)
2017-07-13 18:10:18 +03:00
Slava Monich
81b5c716e2 [ril] Notify the UI if the capability switch transaction fails. JB#38689
That bumps ModemManager protocol version to 8
2017-07-13 12:01:46 +03:00
Slava Monich
33c330988f [ril] Handle the case of one of the SIMs missing. JB#38689
LTE could be enabled for the slot that has no SIM card in it.
In that case we want to swap the capabilities so that LTE
becomes available to the slot that does have a SIM in it.
2017-07-12 19:04:26 +03:00
Slava Monich
910057a265 [ril] Make radio capability switch more reliable. JB#38689
1. Don't allow any other requests while radio caps switch is ongoing.
2. Wait for all other requests to complete before starting the switch
3. Deactivate data calls, disable data before the switch
4. Increased the timeouts
2017-07-12 17:39:40 +03:00
Slava Monich
19f0f8d96e [ril] If SET_UICC_SUBSCRIPTION times out, drop (rather than cancel) it. jb#38689
So that it gets removed from the list of pending requests and
doesn't block the next request.
2017-07-12 16:01:47 +03:00
Slava Monich
f1f3c17c4c [ril] Made PIN requests blocking. JB#38998 2017-07-12 15:58:05 +03:00
Slava Monich
29d891cbce [ril] Made SET_SUPP_SVC_NOTIFICATION blocking. JB#38998
To slow things down at startup. Some RILs just don't like it too fast.
2017-07-12 15:55:55 +03:00
Slava Monich
89fa0d5d6a [ril] Made GSM_GET_BROADCAST_SMS_CONFIG blocking. JB#38998 2017-07-12 15:53:12 +03:00
Slava Monich
c382d9f456 [ril] Poll data call state if DEACTIVATE_DATA_CALL request fails. JB#38998
Also exposed ril_request_allow_data_new and ril_request_deactivate_data_call_new
functions - those may need to be used outside of the ril_data module.
2017-07-12 15:53:01 +03:00
Slava Monich
b209b6bee6 [ril] Make RIL_REQUEST_RADIO_POWER blocking. JB#38998 2017-07-12 15:38:46 +03:00
Slava Monich
ee3323e98b [ril] Block requests while UICC subscription is in progress. JB#38998
Only allow GET_SIM_STATUS. This should make RIL happier.
2017-07-12 15:38:46 +03:00
Slava Monich
9200e387e1 [ril] Serialize requests at startup. JB#38998
Slowing things down at startup seems to make RIL happier.
2017-07-12 15:38:46 +03:00
Slava Monich
2bc58a7f6f Merge branch 'ussd' into 'master'
Switch USSD state from USER_ACTION to IDLE when a notification is received

See merge request !129
2017-06-22 07:40:18 +00:00
Slava Monich
35079b11fe [ofono] Switch USSD state from USER_ACTION to IDLE. Fixes JB#38992
When a USSD notification is received in the USER_ACTION state,
the state needs to be switched to IDLE. Some networks send 0
(no further user action required) after the response timeout
expires. That should result in the user input form getting
removed from the screen.
2017-06-21 14:57:11 +03:00
Slava Monich
955d5882b2 Merge branch 'octal' into 'master'
Workaround for broken MMS proxy IP address

See merge request !128
2017-06-20 08:14:28 +00:00
Slava Monich
2583fa99ce [ofono] Workaround for broken MMS proxy IP address. JB#38990
Some operators provide IP address of the MMS proxy
prepending zeros to each number shorter then 3 digits,
e.g. "192.168.094.023" instead of "192.168.94.23".
That may look nicer but it's actually wrong because
the numbers starting with zeros are interpreted as
octal numbers. In the example above 023 actually means
16 and 094 is not a valid number at all.

In addition to publishing these broken settings on their
web sites, some of the operators send them over the air,
in which case we can't even blame the user for entering
an invalid IP address. We better be prepared to deal with
those.

Since nobody in the world seems to be actually using the
octal notation to write an IP address, let's remove the
leading zeros if we find them in the host part of the MMS
proxy URL.
2017-06-19 18:47:20 +03:00
Slava Monich
b8bb15ce9c [ril] Fixed voicecall problem introduced by commit 351ac1e9. JB#38105 2017-06-17 18:53:16 +03:00
Slava Monich
cbf24c7b08 Merge branch 'auth_method' into 'master'
Add ANY and NONE authentication methods

See merge request !126
2017-06-17 14:13:16 +00:00
Slava Monich
a4c4d1526e [ofono] Reset authentication method together with other context settings. JB#38972 2017-06-16 17:38:32 +03:00
Slava Monich
18d1a8834a [rpm] Require mobile-broadband-provider-info at runtime
Even though it's not really required at build time anymore, let's still
keep it there because this requirement is hardcoded in configure.ac which
we pull from upstream.
2017-06-16 17:05:33 +03:00
Slava Monich
8343d96db5 [test] Improved provisioning test coverage
It no longer requires mobile-broadband-provider-info package to run
2017-06-16 17:04:28 +03:00
Slava Monich
415fce9368 [ofono] Allow to compile unit tests with coverage enabled
... and added unit/coverage script which runs the tests and
generates html report.

Code coverage has to be enabled with --enable-test-coverage
configure switch
2017-06-16 17:04:28 +03:00
Slava Monich
33257a139d [ril] Respect the authentication algorithm option. JB#38972 2017-06-16 17:04:28 +03:00
Slava Monich
f580867c12 [ofono] Added ANY and NONE authentication methods. JB#38972
ANY is supposed to allow either PAP or CHAP to be performed at plugin's
discretion. This is now the default (rather than CHAP)

NONE disables the authentication alltogether.
2017-06-16 17:03:40 +03:00
Slava Monich
edaba80ad1 Merge branch 'imeisv' into 'master'
Expose IMEI SV via org.nemomobile.ofono.ModemManager

See merge request !127
2017-06-16 09:07:49 +00:00
Slava Monich
e68314b07d [ofono] Expose IMEI SV via org.nemomobile.ofono.ModemManager. JB#38973
Unlike org.ofono.Modem properties, it's always going to be available
even for the slots that are disabled.
2017-06-15 15:30:03 +03:00
Slava Monich
d13e48b638 Merge branch 'radio_caps' into 'master'
Start using RIL_REQUEST_SET_RADIO_CAPABILITY

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Added ofono_voicecall_find_call API instead

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

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

See merge request !102
2017-01-11 11:58:42 +00:00
Slava Monich
357c5db580 [ril] Count rild crashes. Contributes to JB#35780
org.nemomobile.ofono.ModemManager.ModemError signal is emitted
when rild crash is detected. Also, the new GetModemErrors method
allows to query how many times which instance of rild has crashed
since ofono was (re)started.
2017-01-11 13:24:23 +02:00
98 changed files with 14996 additions and 5417 deletions

19
ofono/.gitignore vendored
View File

@@ -42,13 +42,32 @@ unit/test-mux
unit/test-caif
unit/test-stkutil
unit/test-cdmasms
unit/test-ril_util
unit/test-rilmodem-cb
unit/test-rilmodem-cs
unit/test-rilmodem-gprs
unit/test-rilmodem-sms
unit/test-sailfish_cell_info
unit/test-sailfish_manager
unit/test-sailfish_sim_info
unit/test-*.log
unit/test-*.trs
unit/test-grilreply
unit/test-grilrequest
unit/test-grilunsol
unit/test-provision
unit/html
plugins/sailfish_manager/*.gcda
plugins/sailfish_manager/*.gcno
drivers/*/*.gcda
drivers/*/*.gcno
drivers/*/*.gcov
*/*.gcda
*/*.gcno
*/*.gcov
tools/huawei-audio
tools/auto-enable
tools/get-location

View File

@@ -27,6 +27,11 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
nodist_pkginclude_HEADERS = include/version.h
if SAILFISH_MANAGER
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
include/sailfish_manager.h include/sailfish_watch.h
endif
local_headers = $(foreach file,$(pkginclude_HEADERS) \
$(nodist_pkginclude_HEADERS), \
include/ofono/$(notdir $(file)))
@@ -116,8 +121,19 @@ builtin_modules += udevng
builtin_sources += plugins/udevng.c
endif
if SAILFISH_MANAGER
builtin_modules += sailfish_manager
builtin_sources += plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
plugins/sailfish_manager/sailfish_manager.c \
plugins/sailfish_manager/sailfish_manager_dbus.c \
plugins/sailfish_manager/sailfish_sim_info.c \
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
plugins/sailfish_manager/sailfish_watch.c
endif
if RILMODEM
if JOLLA_RILMODEM
if SAILFISH_RILMODEM
builtin_modules += ril
builtin_sources += drivers/ril/ril_call_barring.c \
@@ -125,7 +141,6 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_call_settings.c \
drivers/ril/ril_call_volume.c \
drivers/ril/ril_cell_info.c \
drivers/ril/ril_cell_info_dbus.c \
drivers/ril/ril_config.c \
drivers/ril/ril_cbs.c \
drivers/ril/ril_data.c \
@@ -134,20 +149,17 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_gprs.c \
drivers/ril/ril_gprs_context.c \
drivers/ril/ril_modem.c \
drivers/ril/ril_mtu.c \
drivers/ril/ril_netmon.c \
drivers/ril/ril_netreg.c \
drivers/ril/ril_network.c \
drivers/ril/ril_oem_raw.c \
drivers/ril/ril_phonebook.c \
drivers/ril/ril_plugin.c \
drivers/ril/ril_plugin_dbus.c \
drivers/ril/ril_radio.c \
drivers/ril/ril_radio_caps.c \
drivers/ril/ril_radio_settings.c \
drivers/ril/ril_sim.c \
drivers/ril/ril_sim_card.c \
drivers/ril/ril_sim_info.c \
drivers/ril/ril_sim_info_dbus.c \
drivers/ril/ril_sim_settings.c \
drivers/ril/ril_sms.c \
drivers/ril/ril_stk.c \
@@ -575,6 +587,11 @@ builtin_sources += plugins/bluez5.c plugins/bluez5.h
builtin_modules += hfp_ag_bluez5
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
if SAILFISH_BT
builtin_modules += sfos_bt
builtin_sources += plugins/sailfish_bt.c
endif
endif
if UPOWER
@@ -588,11 +605,25 @@ builtin_modules += nettime
builtin_sources += plugins/nettime.c
endif
if SAILFISH_DEBUGLOG
builtin_modules += debuglog
builtin_sources += plugins/sailfish_debuglog.c
endif
if SAILFISH_PROVISION
builtin_sources += plugins/sailfish_provision.c
PROVISION = 1
else
if PROVISION
builtin_sources += plugins/provision.c
endif
endif
if PROVISION
builtin_sources += plugins/mbpi.h plugins/mbpi.c
builtin_modules += provision
builtin_sources += plugins/provision.h plugins/provision.c
builtin_sources += plugins/provision.h
builtin_modules += cdma_provision
builtin_sources += plugins/cdma-provision.c
@@ -630,16 +661,9 @@ builtin_sources += plugins/smart-messaging.c
builtin_modules += push_notification
builtin_sources += plugins/push-notification.c
if PUSHFORWARDER
builtin_modules += push_forwarder
builtin_sources += plugins/push-forwarder.c
builtin_cflags += @WSPCODEC_CFLAGS@
builtin_libadd += @WSPCODEC_LIBS@
endif
if DEBUGLOG
builtin_modules += debuglog
builtin_sources += plugins/debuglog.c
if SAILFISH_PUSHFORWARDER
builtin_modules += pushforwarder
builtin_sources += plugins/sailfish_pushforwarder.c
endif
builtin_modules += sms_history
@@ -651,6 +675,7 @@ builtin_sources += plugins/allowed-apns.c
sbin_PROGRAMS = src/ofonod
src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/mtu-watch.c \
src/main.c src/ofono.h src/log.c src/plugin.c \
src/modem.c src/common.h src/common.c \
src/manager.c src/dbus.c src/util.h src/util.c \
@@ -844,6 +869,9 @@ EXTRA_DIST = src/genbuiltin plugins/ofono.rules plugins/ofono-speedup.rules \
dist_man_MANS = doc/ofonod.8
if TEST_COVERAGE
COVERAGE_OPT = --coverage
endif
unit_objects =
@@ -852,9 +880,51 @@ unit_tests = unit/test-common unit/test-util unit/test-idmap \
unit/test-sms unit/test-cdmasms \
unit/test-provision
if RILMODEM
if JOLLA_RILMODEM
if SAILFISH_MANAGER
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-Iplugins/sailfish_cell_info
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
unit_tests += unit/test-sailfish_cell_info
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
unit/fake_sailfish_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
src/storage.c src/watch.c src/log.c
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
unit_tests += unit/test-sailfish_sim_info
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
unit/fake_sailfish_watch.c \
plugins/sailfish_manager/sailfish_manager.c \
plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_sim_info.c \
src/storage.c src/log.c
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
unit_tests += unit/test-sailfish_manager
endif
if RILMODEM
if SAILFISH_RILMODEM
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)
unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_util_OBJECTS)
unit_tests += unit/test-ril_util
else
unit_tests += unit/test-rilmodem-cs \
unit/test-rilmodem-cs \
unit/test-rilmodem-sms \
@@ -868,19 +938,23 @@ noinst_PROGRAMS = $(unit_tests) \
unit/test-sms-root unit/test-mux unit/test-caif
unit_test_common_SOURCES = unit/test-common.c src/common.c src/util.c
unit_test_common_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_common_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_common_OBJECTS)
unit_test_util_SOURCES = unit/test-util.c src/util.c
unit_test_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_util_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_utils_OBJECTS)
unit_test_idmap_SOURCES = unit/test-idmap.c src/idmap.c
unit_test_idmap_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_idmap_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_idmap_OBJECTS)
unit_test_simutil_SOURCES = unit/test-simutil.c src/util.c \
src/simutil.c src/smsutil.c src/storage.c
unit_test_simutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_simutil_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_simutil_OBJECTS)
@@ -888,19 +962,23 @@ unit_test_stkutil_SOURCES = unit/test-stkutil.c unit/stk-test-data.h \
src/util.c \
src/storage.c src/smsutil.c \
src/simutil.c src/stkutil.c
unit_test_stkutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_stkutil_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_stkutil_OBJECTS)
unit_test_sms_SOURCES = unit/test-sms.c src/util.c src/smsutil.c src/storage.c
unit_test_sms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_sms_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_sms_OBJECTS)
unit_test_cdmasms_SOURCES = unit/test-cdmasms.c src/cdma-smsutil.c
unit_test_cdmasms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_cdmasms_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_cdmasms_OBJECTS)
unit_test_sms_root_SOURCES = unit/test-sms-root.c \
src/util.c src/smsutil.c src/storage.c
unit_test_sms_root_CFLAGS = -DSTORAGEDIR='"/tmp/ofono"' $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_sms_root_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_sms_root_OBJECTS)
@@ -911,13 +989,15 @@ unit_objects += $(unit_test_mux_OBJECTS)
unit_test_caif_SOURCES = unit/test-caif.c $(gatchat_sources) \
drivers/stemodem/caif_socket.h \
drivers/stemodem/if_caif.h
unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_caif_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_caif_OBJECTS)
unit_test_provision_SOURCES = unit/test-provision.c \
plugins/provision.h plugins/provision.c \
plugins/mbpi.c src/gprs-provision.c \
src/log.c
plugins/provision.h plugins/mbpi.c \
plugins/sailfish_provision.c \
src/gprs-provision.c src/log.c
unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_provision_OBJECTS)

View File

@@ -69,6 +69,16 @@ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32, dummy=yes,
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
PKG_CHECK_MODULES(GOBJECT, gobject-2.0, dummy=yes,
AC_MSG_ERROR(GObject is required))
GLIB_CFLAGS="$GLIB_CFLAGS $GOBJECT_CFLAGS"
GLIB_LIBS="$GLIB_LIBS $GOBJECT_LIBS"
PKG_CHECK_MODULES(GIO, gio-2.0, dummy=yes,
AC_MSG_ERROR(GIO is required))
GLIB_CFLAGS="$GLIB_CFLAGS $GIO_CFLAGS"
GLIB_LIBS="$GLIB_LIBS $GIO_LIBS"
if (test "${enable_threads}" = "yes"); then
AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
@@ -167,22 +177,44 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
[enable_rilmodem=${enableval}])
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
AC_ARG_ENABLE(jolla-rilmodem,
AC_HELP_STRING([--enable-jolla-rilmodem], [enable Jolla RIL modem]),
[enable_jolla_rilmodem=${enableval}], [enable_jolla_rilmodem="no"])
AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_rilmodem}" != "no")
AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
[enable Sailfish RIL modem]),
[enable_sailfish_rilmodem=${enableval}],
[enable_sailfish_rilmodem="no"])
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
if (test "${enable_jolla_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.6, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.6 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.5, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.5 is required))
if (test "${enable_sailfish_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.18, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.18 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
PKG_CHECK_MODULES(LIBMCE, libmce-glib, dummy=yes,
AC_MSG_ERROR(libmce-glib is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS $LIBMCE_CFLAGS"
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS $LIBMCE_LIBS"
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
enable_sailfish_manager=yes
need_glibutil=yes
fi
AC_ARG_ENABLE(sailfish-manager,
AC_HELP_STRING([--enable-sailfish-manager],
[enable Sailfish OS modem manager plugin]),
[enable_sailfish_manager=${enableval}])
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
[don't allow to add or remove connection context over D-Bus]), [
if (test "${enableval}" = "no"); then
CFLAGS="$CFLAGS -DDISABLE_ADD_REMOVE_CONTEXT"
fi
])
AC_ARG_ENABLE(test-coverage,
AC_HELP_STRING([--enable-test-coverage], [enable test code coverage]),
[enable_test_coverage=${enableval}],
[enable_test_coverage="no"])
AM_CONDITIONAL(TEST_COVERAGE, test "${enable_test_coverage}" != "no")
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
[disable Qualcomm QMI modem support]),
[enable_qmimodem=${enableval}])
@@ -206,6 +238,16 @@ fi
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
AC_ARG_ENABLE(sailfish-bt, AC_HELP_STRING([--enable-sailfish-bt],
[enable Sailfish OS Bluetooth plugin]),
[enable_sailfish_bt=${enableval}])
AM_CONDITIONAL(SAILFISH_BT, test "${enable_sailfish_bt}" = "yes")
AC_ARG_ENABLE(sailfish-provision, AC_HELP_STRING([--enable-sailfish-provision],
[enable Sailfish OS provisioning plugin]),
[enable_sailfish_provision=${enableval}])
AM_CONDITIONAL(SAILFISH_PROVISION, test "${enable_sailfish_provision=$}" = "yes")
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
[disable Nettime plugin]),
[enable_nettime=${enableval}])
@@ -248,28 +290,38 @@ AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
[enable_datafiles=${enableval}])
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
AC_ARG_ENABLE(pushforwarder, AC_HELP_STRING([--disable-pushforwarder],
[disable Push Forwarder plugin]),
[enable_pushforwarder=${enableval}])
AM_CONDITIONAL(PUSHFORWARDER, test "${enable_pushforwarder}" != "no")
if (test "${enable_pushforwarder}" != "no"); then
AC_ARG_ENABLE(sailfish-pushforwarder, AC_HELP_STRING([--enable-sailfish-pushforwarder],
[enable Sailfish OS push forwarder plugin]),
[enable_sailfish_pushforwarder=${enableval}],
[enable_sailfish_pushforwarder="no"])
AM_CONDITIONAL(SAILFISH_PUSHFORWARDER, test "${enable_sailfish_pushforwarder}" != "no")
if (test "${enable_sailfish_pushforwarder}" != "no"); then
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.15, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.15 is required))
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
AC_MSG_ERROR(WSP decoder is required))
AC_SUBST(WSPCODEC_CFLAGS)
AC_SUBST(WSPCODEC_LIBS)
AC_MSG_ERROR(WSP decoder is required))
CFLAGS="$CFLAGS $WSPCODEC_CFLAGS"
LIBS="$LIBS $WSPCODEC_LIBS"
need_glibutil=yes
fi
AC_ARG_ENABLE(debuglog,
AC_HELP_STRING([--enable-debuglog], [enable log control plugin]),
[enable_debuglog=${enableval}], [enable_debuglog="no"])
AM_CONDITIONAL(DEBUGLOG, test "${enable_debuglog}" != "no")
if (test "${enable_debuglog}" = "yes"); then
AC_ARG_ENABLE(sailfish-debuglog, AC_HELP_STRING([--enable-sailfish-debuglog],
[enable Sailfish OS debug log plugin]),
[enable_sailfish_debuglog=${enableval}],
[enable_sailfish_debuglog="no"])
AM_CONDITIONAL(SAILFISH_DEBUGLOG, test "${enable_sailfish_debuglog}" != "no")
if (test "${enable_sailfish_debuglog}" = "yes"); then
PKG_CHECK_MODULES(DBUSLOG, libdbuslogserver-dbus, dummy=yes,
AC_MSG_ERROR(libdbuslogserver-dbus is required))
CFLAGS="$CFLAGS $DBUSLOG_CFLAGS"
LIBS="$LIBS $DBUSLOG_LIBS"
fi
if (test "${need_glibutil}" = "yes"); then
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
LIBS="$LIBS $GLIBUTIL_LIBS"
fi
if (test "${prefix}" = "NONE"); then
dnl no prefix and no localstatedir, so default to /var
if (test "$localstatedir" = '${prefix}/var'); then
@@ -284,7 +336,7 @@ if (test "$localstatedir" = '${prefix}/var'); then
else
storagedir="${localstatedir}/lib/ofono"
fi
AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}",
AC_DEFINE_UNQUOTED(DEFAULT_STORAGEDIR, "${storagedir}",
[Directory for the storage files])
if (test "$sysconfdir" = '${prefix}/etc'); then

View File

@@ -247,6 +247,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
/* We only support CHAP and PAP */
switch (ctx->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
case OFONO_GPRS_AUTH_METHOD_NONE:
case OFONO_GPRS_AUTH_METHOD_CHAP:
gcd->auth_method = G_AT_PPP_AUTH_METHOD_CHAP;
break;
@@ -294,6 +296,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
* prefix, this is the least invasive place to set it.
*/
switch (ctx->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
case OFONO_GPRS_AUTH_METHOD_NONE:
case OFONO_GPRS_AUTH_METHOD_CHAP:
snprintf(buf + len, sizeof(buf) - len - 3,
",\"CHAP:%s\"", ctx->apn);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "common.h"

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "common.h"

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "common.h"

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
struct ril_call_volume {
struct ofono_call_volume *v;

View File

@@ -184,11 +184,14 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
cd->q = grilio_queue_new(cd->io);
/*
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup.
* We may have to retry a few times.
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup
* especially if other RIL requests are running in parallel. We may
* have to retry a few times. Also, make it blocking in order to
* improve the chance of success.
*/
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
RIL_CBS_CHECK_RETRY_COUNT);
grilio_request_set_blocking(req, TRUE);
grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
ril_cbs_probe_done_cb, NULL, cd);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -31,7 +31,9 @@
typedef GObjectClass RilCellInfoClass;
typedef struct ril_cell_info RilCellInfo;
struct ril_cell_info_priv {
struct ril_cell_info {
GObject object;
struct sailfish_cell_info info;
GRilIoChannel *io;
MceDisplay *display;
struct ril_radio *radio;
@@ -60,63 +62,22 @@ G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
RIL_CELL_INFO_TYPE, RilCellInfo))
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
gint ril_cell_compare_location(const struct ril_cell *c1,
const struct ril_cell *c2)
static inline void ril_cell_free(struct sailfish_cell *cell)
{
if (c1 && c2) {
if (c1->type != c2->type) {
return c1->type - c2->type;
} else if (c1->type == RIL_CELL_INFO_TYPE_GSM) {
const struct ril_cell_info_gsm *g1 = &c1->info.gsm;
const struct ril_cell_info_gsm *g2 = &c2->info.gsm;
if (g1->lac != g2->lac) {
return g1->lac - g2->lac;
} else {
return g1->cid - g2->cid;
}
} else if (c2->type == RIL_CELL_INFO_TYPE_WCDMA) {
const struct ril_cell_info_wcdma *w1 = &c1->info.wcdma;
const struct ril_cell_info_wcdma *w2 = &c2->info.wcdma;
if (w1->lac != w2->lac) {
return w1->lac - w2->lac;
} else {
return w1->cid - w2->cid;
}
} else {
const struct ril_cell_info_lte *l1 = &c1->info.lte;
const struct ril_cell_info_lte *l2 = &c2->info.lte;
GASSERT(c1->type == RIL_CELL_INFO_TYPE_LTE);
if (l1->ci != l2->ci) {
return l1->ci - l2->ci;
} else if (l1->pci != l2->pci) {
return l1->pci - l2->pci;
} else {
return l1->tac - l2->tac;
}
}
} else if (c1) {
return 1;
} else if (c2) {
return -1;
} else {
return 0;
}
g_slice_free(struct sailfish_cell, cell);
}
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2)
static void ril_cell_free1(gpointer cell)
{
return ril_cell_compare_location(v1, v2);
ril_cell_free(cell);
}
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
{
while (l1 && l2) {
if (memcmp(l1->data, l2->data, sizeof(struct ril_cell))) {
if (memcmp(l1->data, l2->data, sizeof(struct sailfish_cell))) {
return FALSE;
}
l1 = l1->next;
@@ -127,80 +88,101 @@ static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
{
if (!ril_cell_info_list_identical(self->cells, l)) {
g_slist_free_full(self->cells, g_free);
self->cells = l;
g_signal_emit(self, ril_cell_info_signals[
SIGNAL_CELLS_CHANGED], 0);
if (!ril_cell_info_list_identical(self->info.cells, l)) {
g_slist_free_full(self->info.cells, ril_cell_free1);
self->info.cells = l;
g_signal_emit(self, ril_cell_info_signals
[SIGNAL_CELLS_CHANGED], 0);
} else {
g_slist_free_full(l, g_free);
g_slist_free_full(l, ril_cell_free1);
}
}
static struct ril_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
gboolean registered)
static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
guint version, gboolean registered)
{
struct ril_cell *cell = g_new0(struct ril_cell, 1);
struct ril_cell_info_gsm *gsm = &cell->info.gsm;
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
/* Optional RIL_CellIdentityGsm_v12 part */
gsm->arfcn = INT_MAX;
gsm->bsic = INT_MAX;
/* Optional RIL_GSM_SignalStrength_v12 part */
gsm->timingAdvance = INT_MAX;
/* RIL_CellIdentityGsm */
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
grilio_parser_get_int32(rilp, &gsm->mnc) &&
grilio_parser_get_int32(rilp, &gsm->lac) &&
grilio_parser_get_int32(rilp, &gsm->cid) &&
(version < 12 || /* RIL_CellIdentityGsm_v12 part */
(grilio_parser_get_int32(rilp, &gsm->arfcn) &&
grilio_parser_get_int32(rilp, &gsm->bsic))) &&
/* RIL_GW_SignalStrength */
grilio_parser_get_int32(rilp, &gsm->signalStrength) &&
grilio_parser_get_int32(rilp, &gsm->bitErrorRate)) {
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,"
"strength=%d,err=%d", registered, gsm->mcc, gsm->mnc,
gsm->lac, gsm->cid, gsm->signalStrength,
gsm->bitErrorRate);
cell->type = RIL_CELL_INFO_TYPE_GSM;
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);
cell->type = SAILFISH_CELL_TYPE_GSM;
cell->registered = registered;
return cell;
}
ofono_error("failed to parse GSM cell info");
g_free(cell);
ril_cell_free(cell);
return NULL;
}
static struct ril_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
gboolean registered)
static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
guint version, gboolean registered)
{
struct ril_cell *cell = g_new0(struct ril_cell, 1);
struct ril_cell_info_wcdma *wcdma = &cell->info.wcdma;
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
/* Optional RIL_CellIdentityWcdma_v12 part */
wcdma->uarfcn = INT_MAX;
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
grilio_parser_get_int32(rilp, &wcdma->lac) &&
grilio_parser_get_int32(rilp, &wcdma->cid) &&
grilio_parser_get_int32(rilp, &wcdma->psc) &&
(version < 12 || /* RIL_CellIdentityWcdma_v12 part */
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);
cell->type = RIL_CELL_INFO_TYPE_WCDMA;
cell->type = SAILFISH_CELL_TYPE_WCDMA;
cell->registered = registered;
return cell;
}
ofono_error("failed to parse WCDMA cell info");
g_free(cell);
ril_cell_free(cell);
return NULL;
}
static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
gboolean registered)
static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
guint version, gboolean registered)
{
struct ril_cell *cell = g_new0(struct ril_cell, 1);
struct ril_cell_info_lte *lte = &cell->info.lte;
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
struct sailfish_cell_info_lte *lte = &cell->info.lte;
/* Optional RIL_CellIdentityLte_v12 part */
lte->earfcn = INT_MAX;
if (grilio_parser_get_int32(rilp, &lte->mcc) &&
grilio_parser_get_int32(rilp, &lte->mnc) &&
grilio_parser_get_int32(rilp, &lte->ci) &&
grilio_parser_get_int32(rilp, &lte->pci) &&
grilio_parser_get_int32(rilp, &lte->tac) &&
(version < 12 || /* RIL_CellIdentityLte_v12 part */
grilio_parser_get_int32(rilp, &lte->earfcn)) &&
grilio_parser_get_int32(rilp, &lte->signalStrength) &&
grilio_parser_get_int32(rilp, &lte->rsrp) &&
grilio_parser_get_int32(rilp, &lte->rsrq) &&
@@ -208,40 +190,44 @@ static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
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=0x%x,rssnr=0x%x,cqi=%d,"
"strength=%d,rsrp=%d,rsrq=%d,rssnr=%d,cqi=%d,"
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
cell->type = RIL_CELL_INFO_TYPE_LTE;
cell->type = SAILFISH_CELL_TYPE_LTE;
cell->registered = registered;
return cell;
}
ofono_error("failed to parse LTE cell info");
g_free(cell);
ril_cell_free(cell);
return NULL;
}
static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
struct ril_cell **cell_ptr)
static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
struct sailfish_cell **cell_ptr)
{
int type, reg;
if (grilio_parser_get_int32(rilp, &type) &&
grilio_parser_get_int32(rilp, &reg) &&
/* Skip timestamp */
grilio_parser_get_int32_array(rilp, NULL, 3)) {
int skip = 0;
struct ril_cell *cell = NULL;
struct sailfish_cell *cell = NULL;
/* Normalize the boolean value */
reg = (reg != FALSE);
switch (type) {
case RIL_CELL_INFO_TYPE_GSM:
cell = ril_cell_info_parse_cell_gsm(rilp, reg);
cell = ril_cell_info_parse_cell_gsm(rilp, v, reg);
break;
case RIL_CELL_INFO_TYPE_WCDMA:
cell = ril_cell_info_parse_cell_wcdma(rilp, reg);
cell = ril_cell_info_parse_cell_wcdma(rilp, v, reg);
break;
case RIL_CELL_INFO_TYPE_LTE:
cell = ril_cell_info_parse_cell_lte(rilp, reg);
cell = ril_cell_info_parse_cell_lte(rilp, v, reg);
break;
case RIL_CELL_INFO_TYPE_CDMA:
skip = 10;
@@ -256,20 +242,20 @@ static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
if (cell) {
*cell_ptr = cell;
return type;
return TRUE;
}
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
*cell_ptr = NULL;
return type;
return TRUE;
}
}
*cell_ptr = NULL;
return RIL_CELL_INFO_TYPE_NONE;
return FALSE;
}
static GSList *ril_cell_info_parse_list(const void *data, guint len)
static GSList *ril_cell_info_parse_list(guint v, const void *data, guint len)
{
GSList *l = NULL;
GRilIoParser rilp;
@@ -277,17 +263,18 @@ static GSList *ril_cell_info_parse_list(const void *data, guint len)
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
struct ril_cell *c;
struct sailfish_cell *c;
DBG("%d cell(s):", n);
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, &c); i++) {
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
if (c) {
l = g_slist_insert_sorted(l, c,
ril_cell_compare_func);
sailfish_cell_compare_func);
}
}
}
GASSERT(grilio_parser_at_end(&rilp));
return l;
}
@@ -297,40 +284,39 @@ static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
DBG_(self, "");
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
ril_cell_info_update_cells(self, ril_cell_info_parse_list
(io->ril_version, data, len));
}
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
struct ril_cell_info_priv *priv = self->priv;
DBG_(self, "");
GASSERT(priv->query_id);
priv->query_id = 0;
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
GASSERT(self->query_id);
self->query_id = 0;
ril_cell_info_update_cells(self, ril_cell_info_parse_list
(io->ril_version, data, len));
}
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
struct ril_cell_info_priv *priv = self->priv;
DBG_(self, "");
GASSERT(priv->set_rate_id);
priv->set_rate_id = 0;
GASSERT(self->set_rate_id);
self->set_rate_id = 0;
}
static void ril_cell_info_query(struct ril_cell_info *self)
{
struct ril_cell_info_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
priv->query_id = grilio_channel_send_request_full(priv->io, req,
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
self->query_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
NULL, self);
grilio_request_unref(req);
@@ -338,14 +324,13 @@ static void ril_cell_info_query(struct ril_cell_info *self)
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
{
struct ril_cell_info_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, ms);
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_channel_cancel_request(priv->io, priv->set_rate_id, FALSE);
priv->set_rate_id = grilio_channel_send_request_full(priv->io, req,
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
ril_cell_info_set_rate_cb, NULL, self);
grilio_request_unref(req);
@@ -353,29 +338,24 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
static void ril_cell_info_update_rate(struct ril_cell_info *self)
{
struct ril_cell_info_priv *priv = self->priv;
ril_cell_info_set_rate(self,
(priv->display->state == MCE_DISPLAY_STATE_OFF) ?
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
}
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
{
struct ril_cell_info *self = RIL_CELL_INFO(arg);
struct ril_cell_info_priv *priv = self->priv;
if (priv->sim_card_ready) {
if (self->sim_card_ready) {
ril_cell_info_update_rate(self);
}
}
static void ril_cell_info_refresh(struct ril_cell_info *self)
{
struct ril_cell_info_priv *priv = self->priv;
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
if (priv->radio->state == RADIO_STATE_ON && priv->sim_card_ready) {
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
ril_cell_info_query(self);
} else {
ril_cell_info_update_cells(self, NULL);
@@ -393,124 +373,160 @@ static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
{
struct ril_cell_info *self = RIL_CELL_INFO(arg);
struct ril_cell_info_priv *priv = self->priv;
const gboolean sim_card_was_ready = priv->sim_card_ready;
const gboolean sim_card_was_ready = self->sim_card_ready;
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
priv->sim_card_ready = ril_sim_card_ready(sim);
if (priv->sim_card_ready != sim_card_was_ready) {
self->sim_card_ready = ril_sim_card_ready(sim);
if (self->sim_card_ready != sim_card_was_ready) {
ril_cell_info_refresh(self);
if (priv->sim_card_ready) {
if (self->sim_card_ready) {
ril_cell_info_update_rate(self);
}
}
}
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *self,
ril_cell_info_cb_t cb, void *arg)
/* sailfish_cell_info interface callbacks */
struct ril_cell_info_signal_data {
sailfish_cell_info_cb_t cb;
void *arg;
};
static inline struct ril_cell_info *ril_cell_info_cast
(struct sailfish_cell_info *info)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_CELLS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
return G_CAST(info, struct ril_cell_info, info);
}
void ril_cell_info_remove_handler(struct ril_cell_info *self, gulong id)
static void ril_cell_info_ref_proc(struct sailfish_cell_info *info)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
g_object_ref(ril_cell_info_cast(info));
}
static void ril_cell_info_unref_proc(struct sailfish_cell_info *info)
{
g_object_unref(ril_cell_info_cast(info));
}
static void ril_cell_info_cells_changed_cb(struct ril_cell_info *self,
void *user_data)
{
struct ril_cell_info_signal_data *data = user_data;
data->cb(&self->info, data->arg);
}
static void ril_cell_info_cells_disconnect_notify(gpointer data,
GClosure *closure)
{
g_slice_free1(sizeof(struct ril_cell_info_signal_data), data);
}
static gulong ril_cell_info_add_cells_changed_handler_proc
(struct sailfish_cell_info *info,
sailfish_cell_info_cb_t cb, void *arg)
{
if (cb) {
struct ril_cell_info_signal_data *data =
g_slice_new(struct ril_cell_info_signal_data);
data->cb = cb;
data->arg = arg;
return g_signal_connect_data(ril_cell_info_cast(info),
SIGNAL_CELLS_CHANGED_NAME,
G_CALLBACK(ril_cell_info_cells_changed_cb),
data, ril_cell_info_cells_disconnect_notify,
G_CONNECT_AFTER);
} else {
return 0;
}
}
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
gulong id)
{
if (G_LIKELY(id)) {
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
}
}
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, MceDisplay *display,
struct ril_radio *radio, struct ril_sim_card *sim_card)
{
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
struct ril_cell_info_priv *priv = self->priv;
static const struct sailfish_cell_info_proc ril_cell_info_proc = {
ril_cell_info_ref_proc,
ril_cell_info_unref_proc,
ril_cell_info_add_cells_changed_handler_proc,
ril_cell_info_remove_handler_proc
};
priv->io = grilio_channel_ref(io);
priv->display = mce_display_ref(display);
priv->radio = ril_radio_ref(radio);
priv->sim_card = ril_sim_card_ref(sim_card);
priv->log_prefix = (log_prefix && log_prefix[0]) ?
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
self->info.proc = &ril_cell_info_proc;
self->io = grilio_channel_ref(io);
self->display = mce_display_ref(display);
self->radio = ril_radio_ref(radio);
self->sim_card = ril_sim_card_ref(sim_card);
self->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
DBG_(self, "");
priv->event_id = grilio_channel_add_unsol_event_handler(priv->io,
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
priv->display_state_event_id =
self->display_state_event_id =
mce_display_add_state_changed_handler(display,
ril_cell_info_display_state_cb, self);
priv->radio_state_event_id =
self->radio_state_event_id =
ril_radio_add_state_changed_handler(radio,
ril_cell_info_radio_state_cb, self);
priv->sim_status_event_id =
ril_sim_card_add_status_changed_handler(priv->sim_card,
self->sim_status_event_id =
ril_sim_card_add_status_changed_handler(self->sim_card,
ril_cell_info_sim_status_cb, self);
priv->sim_card_ready = ril_sim_card_ready(sim_card);
if (priv->sim_card_ready) {
self->sim_card_ready = ril_sim_card_ready(sim_card);
if (self->sim_card_ready) {
ril_cell_info_query(self);
ril_cell_info_update_rate(self);
}
return self;
}
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_CELL_INFO(self));
return self;
} else {
return NULL;
}
}
void ril_cell_info_unref(struct ril_cell_info *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_CELL_INFO(self));
}
return &self->info;
}
static void ril_cell_info_init(struct ril_cell_info *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_CELL_INFO_TYPE,
struct ril_cell_info_priv);
}
static void ril_cell_info_dispose(GObject *object)
{
struct ril_cell_info *self = RIL_CELL_INFO(object);
struct ril_cell_info_priv *priv = self->priv;
grilio_channel_remove_handlers(priv->io, &priv->event_id, 1);
if (priv->query_id) {
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
priv->query_id = 0;
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
if (self->query_id) {
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
self->query_id = 0;
}
if (priv->set_rate_id) {
grilio_channel_cancel_request(priv->io, priv->set_rate_id,
if (self->set_rate_id) {
grilio_channel_cancel_request(self->io, self->set_rate_id,
FALSE);
priv->set_rate_id = 0;
self->set_rate_id = 0;
}
gutil_disconnect_handlers(priv->display,
&priv->display_state_event_id, 1);
ril_radio_remove_handlers(priv->radio, &priv->radio_state_event_id, 1);
ril_sim_card_remove_handlers(priv->sim_card,
&priv->sim_status_event_id, 1);
gutil_disconnect_handlers(self->display,
&self->display_state_event_id, 1);
ril_radio_remove_handlers(self->radio, &self->radio_state_event_id, 1);
ril_sim_card_remove_handlers(self->sim_card,
&self->sim_status_event_id, 1);
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
}
static void ril_cell_info_finalize(GObject *object)
{
struct ril_cell_info *self = RIL_CELL_INFO(object);
struct ril_cell_info_priv *priv = self->priv;
DBG_(self, "");
g_free(priv->log_prefix);
grilio_channel_unref(priv->io);
mce_display_unref(priv->display);
ril_radio_unref(priv->radio);
ril_sim_card_unref(priv->sim_card);
g_slist_free_full(self->cells, g_free);
g_free(self->log_prefix);
grilio_channel_unref(self->io);
mce_display_unref(self->display);
ril_radio_unref(self->radio);
ril_sim_card_unref(self->sim_card);
g_slist_free_full(self->info.cells, ril_cell_free1);
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
}
@@ -520,7 +536,6 @@ static void ril_cell_info_class_init(RilCellInfoClass *klass)
object_class->dispose = ril_cell_info_dispose;
object_class->finalize = ril_cell_info_finalize;
g_type_class_add_private(klass, sizeof(struct ril_cell_info_priv));
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,40 +18,11 @@
#include "ril_types.h"
#include <mce_display.h>
#include <sailfish_cell_info.h>
struct ril_cell {
enum ril_cell_info_type type;
gboolean registered;
union {
struct ril_cell_info_gsm gsm;
struct ril_cell_info_wcdma wcdma;
struct ril_cell_info_lte lte;
} info;
};
struct ril_cell_info_priv;
struct ril_cell_info {
GObject object;
struct ril_cell_info_priv *priv;
GSList *cells;
};
typedef void (*ril_cell_info_cb_t)(struct ril_cell_info *info, void *arg);
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2);
gint ril_cell_compare_location(const struct ril_cell *c1,
const struct ril_cell *c2);
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, MceDisplay *display,
struct ril_radio *radio, struct ril_sim_card *sim_card);
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *info);
void ril_cell_info_unref(struct ril_cell_info *info);
struct ril_cell *ril_cell_find_cell(struct ril_cell_info *info,
const struct ril_cell *cell);
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *info,
ril_cell_info_cb_t cb, void *arg);
void ril_cell_info_remove_handler(struct ril_cell_info *info, gulong id);
#endif /* RIL_CELL_INFO_H */

View File

@@ -1,586 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_cell_info.h"
#include "ril_log.h"
#include <ofono/dbus.h>
#include <gdbus.h>
struct ril_cell_entry {
guint cell_id;
char *path;
struct ril_cell cell;
};
struct ril_cell_info_dbus {
struct ril_modem *md;
struct ril_cell_info *info;
DBusConnection *conn;
char *path;
gulong handler_id;
guint next_cell_id;
GSList *entries;
};
#define RIL_CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
#define RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
#define RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
#define RIL_CELL_DBUS_INTERFACE_VERSION (1)
#define RIL_CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
#define RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL "RegisteredChanged"
#define RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
#define RIL_CELL_DBUS_REMOVED_SIGNAL "Removed"
struct ril_cell_property {
const char *name;
glong off;
int flag;
};
#define RIL_CELL_GSM_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_gsm,name), value }
#define RIL_CELL_WCDMA_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_wcdma,name), value }
#define RIL_CELL_LTE_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_lte,name), value }
static const struct ril_cell_property ril_cell_gsm_properties [] = {
RIL_CELL_GSM_PROPERTY(0x01,mcc),
RIL_CELL_GSM_PROPERTY(0x02,mnc),
RIL_CELL_GSM_PROPERTY(0x04,lac),
RIL_CELL_GSM_PROPERTY(0x08,cid),
RIL_CELL_GSM_PROPERTY(0x10,signalStrength),
RIL_CELL_GSM_PROPERTY(0x20,bitErrorRate)
};
static const struct ril_cell_property ril_cell_wcdma_properties [] = {
RIL_CELL_WCDMA_PROPERTY(0x01,mcc),
RIL_CELL_WCDMA_PROPERTY(0x02,mnc),
RIL_CELL_WCDMA_PROPERTY(0x04,lac),
RIL_CELL_WCDMA_PROPERTY(0x08,cid),
RIL_CELL_WCDMA_PROPERTY(0x10,psc),
RIL_CELL_WCDMA_PROPERTY(0x20,signalStrength),
RIL_CELL_WCDMA_PROPERTY(0x40,bitErrorRate)
};
static const struct ril_cell_property ril_cell_lte_properties [] = {
RIL_CELL_LTE_PROPERTY(0x001,mcc),
RIL_CELL_LTE_PROPERTY(0x002,mnc),
RIL_CELL_LTE_PROPERTY(0x004,ci),
RIL_CELL_LTE_PROPERTY(0x008,pci),
RIL_CELL_LTE_PROPERTY(0x010,tac),
RIL_CELL_LTE_PROPERTY(0x020,signalStrength),
RIL_CELL_LTE_PROPERTY(0x040,rsrp),
RIL_CELL_LTE_PROPERTY(0x080,rsrq),
RIL_CELL_LTE_PROPERTY(0x100,rssnr),
RIL_CELL_LTE_PROPERTY(0x200,cqi),
RIL_CELL_LTE_PROPERTY(0x400,timingAdvance)
};
#define RIL_CELL_PROPERTY_REGISTERED 0x1000
typedef void (*ril_cell_info_dbus_append_fn)(DBusMessageIter *it,
const struct ril_cell_entry *entry);
static const char *ril_cell_info_dbus_cell_type_str(enum ril_cell_info_type t)
{
switch (t) {
case RIL_CELL_INFO_TYPE_GSM:
return "gsm";
case RIL_CELL_INFO_TYPE_CDMA:
return "cdma";
case RIL_CELL_INFO_TYPE_LTE:
return "lte";
case RIL_CELL_INFO_TYPE_WCDMA:
return "wcdma";
case RIL_CELL_INFO_TYPE_TD_SCDMA:
return "tdscdma";
case RIL_CELL_INFO_TYPE_NONE:
default:
return "unknown";
}
};
static const struct ril_cell_property *ril_cell_info_dbus_cell_properties(
enum ril_cell_info_type type, int *count)
{
switch (type) {
case RIL_CELL_INFO_TYPE_GSM:
*count = G_N_ELEMENTS(ril_cell_gsm_properties);
return ril_cell_gsm_properties;
case RIL_CELL_INFO_TYPE_WCDMA:
*count = G_N_ELEMENTS(ril_cell_wcdma_properties);
return ril_cell_wcdma_properties;
case RIL_CELL_INFO_TYPE_LTE:
*count = G_N_ELEMENTS(ril_cell_lte_properties);
return ril_cell_lte_properties;
default:
*count = 0;
return NULL;
}
};
static void ril_cell_info_destroy_entry(struct ril_cell_entry *entry)
{
if (entry) {
g_free(entry->path);
g_free(entry);
}
}
static DBusMessage *ril_cell_info_dbus_reply(DBusMessage *msg,
const struct ril_cell_entry *entry,
ril_cell_info_dbus_append_fn append)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it;
dbus_message_iter_init_append(reply, &it);
append(&it, entry);
return reply;
}
static void ril_cell_info_dbus_append_version(DBusMessageIter *it,
const struct ril_cell_entry *entry)
{
dbus_int32_t version = RIL_CELL_DBUS_INTERFACE_VERSION;
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
}
static void ril_cell_info_dbus_append_type(DBusMessageIter *it,
const struct ril_cell_entry *entry)
{
const char *type = ril_cell_info_dbus_cell_type_str(entry->cell.type);
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &type);
}
static void ril_cell_info_dbus_append_registered(DBusMessageIter *it,
const struct ril_cell_entry *entry)
{
dbus_bool_t registered = entry->cell.registered;
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &registered);
}
static void ril_cell_info_dbus_append_properties(DBusMessageIter *it,
const struct ril_cell_entry *entry)
{
int i, n;
DBusMessageIter dict;
const struct ril_cell *cell = &entry->cell;
const struct ril_cell_property *prop =
ril_cell_info_dbus_cell_properties(cell->type, &n);
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &dict);
for (i = 0; i < n; i++) {
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
if (value != INT_MAX) {
ofono_dbus_dict_append(&dict, prop[i].name,
DBUS_TYPE_INT32, &value);
}
}
dbus_message_iter_close_container(it, &dict);
}
static void ril_cell_info_dbus_append_all(DBusMessageIter *it,
const struct ril_cell_entry *entry)
{
ril_cell_info_dbus_append_version(it, entry);
ril_cell_info_dbus_append_type(it, entry);
ril_cell_info_dbus_append_registered(it, entry);
ril_cell_info_dbus_append_properties(it, entry);
}
static DBusMessage *ril_cell_info_dbus_cell_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
ril_cell_info_dbus_append_all);
}
static DBusMessage *ril_cell_info_dbus_cell_get_version(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
ril_cell_info_dbus_append_version);
}
static DBusMessage *ril_cell_info_dbus_cell_get_type(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
ril_cell_info_dbus_append_type);
}
static DBusMessage *ril_cell_info_dbus_cell_get_registered(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
ril_cell_info_dbus_append_registered);
}
static DBusMessage *ril_cell_info_dbus_cell_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
ril_cell_info_dbus_append_properties);
}
static const GDBusMethodTable ril_cell_info_dbus_cell_methods[] = {
{ GDBUS_METHOD("GetAll", NULL,
GDBUS_ARGS({ "version", "i" },
{ "type", "s" },
{ "registered", "b" },
{ "properties", "a{sv}" }),
ril_cell_info_dbus_cell_get_all) },
{ GDBUS_METHOD("GetInterfaceVersion", NULL,
GDBUS_ARGS({ "version", "i" }),
ril_cell_info_dbus_cell_get_version) },
{ GDBUS_METHOD("GetType", NULL,
GDBUS_ARGS({ "type", "s" }),
ril_cell_info_dbus_cell_get_type) },
{ GDBUS_METHOD("GetRegistered", NULL,
GDBUS_ARGS({ "registered", "b" }),
ril_cell_info_dbus_cell_get_registered) },
{ GDBUS_METHOD("GetProperties", NULL,
GDBUS_ARGS({ "properties", "a{sv}" }),
ril_cell_info_dbus_cell_get_properties) },
{ }
};
static const GDBusSignalTable ril_cell_info_dbus_cell_signals[] = {
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
GDBUS_ARGS({ "registered", "b" })) },
{ GDBUS_SIGNAL(RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL,
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REMOVED_SIGNAL,
GDBUS_ARGS({})) },
{ }
};
static struct ril_cell_entry *ril_cell_info_dbus_find_id(
struct ril_cell_info_dbus *dbus, guint id)
{
GSList *l;
for (l = dbus->entries; l; l = l->next) {
struct ril_cell_entry *entry = l->data;
if (entry->cell_id == id) {
return entry;
}
}
return NULL;
}
static guint ril_cell_info_dbus_next_cell_id(struct ril_cell_info_dbus *dbus)
{
while (ril_cell_info_dbus_find_id(dbus, dbus->next_cell_id)) {
dbus->next_cell_id++;
}
return dbus->next_cell_id++;
}
static struct ril_cell_entry *ril_cell_info_dbus_find_cell(
struct ril_cell_info_dbus *dbus, const struct ril_cell *cell)
{
if (cell) {
GSList *l;
for (l = dbus->entries; l; l = l->next) {
struct ril_cell_entry *entry = l->data;
if (!ril_cell_compare_location(&entry->cell, cell)) {
return entry;
}
}
}
return NULL;
}
static void ril_cell_info_dbus_emit_path_list(struct ril_cell_info_dbus *dbus,
const char *name, GPtrArray *list)
{
guint i;
DBusMessageIter it, array;
DBusMessage *signal = dbus_message_new_signal(dbus->path,
RIL_CELL_INFO_DBUS_INTERFACE, name);
dbus_message_iter_init_append(signal, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
for (i = 0; i < list->len; i++) {
const char* path = list->pdata[i];
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
&path);
}
dbus_message_iter_close_container(&it, &array);
g_dbus_send_message(dbus->conn, signal);
}
static int ril_cell_info_dbus_compare(const struct ril_cell *c1,
const struct ril_cell *c2)
{
if (c1->type == c2->type) {
int i, n, mask = 0;
const struct ril_cell_property *prop =
ril_cell_info_dbus_cell_properties(c1->type, &n);
if (c1->registered != c2->registered) {
mask |= RIL_CELL_PROPERTY_REGISTERED;
}
for (i = 0; i < n; i++) {
const glong offset = prop[i].off;
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
if (v1 != v2) {
mask |= prop[i].flag;
}
}
return mask;
} else {
return -1;
}
}
static void ril_cell_info_dbus_property_changed(struct ril_cell_info_dbus *dbus,
const struct ril_cell_entry *entry, int mask)
{
int i, n;
const struct ril_cell *cell = &entry->cell;
const struct ril_cell_property *prop =
ril_cell_info_dbus_cell_properties(cell->type, &n);
if (mask & RIL_CELL_PROPERTY_REGISTERED) {
dbus_bool_t registered = cell->registered;
g_dbus_emit_signal(dbus->conn, entry->path,
RIL_CELL_DBUS_INTERFACE,
RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
DBUS_TYPE_BOOLEAN, &registered, DBUS_TYPE_INVALID);
mask &= ~RIL_CELL_PROPERTY_REGISTERED;
}
for (i = 0; i < n && mask; i++) {
if (mask & prop[i].flag) {
ofono_dbus_signal_property_changed(dbus->conn,
entry->path, RIL_CELL_DBUS_INTERFACE,
prop[i].name, DBUS_TYPE_INT32,
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
mask &= ~prop[i].flag;
}
}
}
static void ril_cell_info_dbus_update_entries(struct ril_cell_info_dbus *dbus,
gboolean emit_signals)
{
GSList *l;
GPtrArray* added = NULL;
GPtrArray* removed = NULL;
/* Remove non-existent cells */
l = dbus->entries;
while (l) {
GSList *next = l->next;
struct ril_cell_entry *entry = l->data;
if (!g_slist_find_custom(dbus->info->cells, &entry->cell,
ril_cell_compare_func)) {
DBG("%s removed", entry->path);
dbus->entries = g_slist_delete_link(dbus->entries, l);
g_dbus_emit_signal(dbus->conn, entry->path,
RIL_CELL_DBUS_INTERFACE,
RIL_CELL_DBUS_REMOVED_SIGNAL,
DBUS_TYPE_INVALID);
g_dbus_unregister_interface(dbus->conn, entry->path,
RIL_CELL_DBUS_INTERFACE);
if (emit_signals) {
if (!removed) {
removed =
g_ptr_array_new_with_free_func(
g_free);
}
/* Steal the path */
g_ptr_array_add(removed, entry->path);
entry->path = NULL;
}
ril_cell_info_destroy_entry(entry);
}
l = next;
}
/* Add new cells */
for (l = dbus->info->cells; l; l = l->next) {
const struct ril_cell *cell = l->data;
struct ril_cell_entry *entry =
ril_cell_info_dbus_find_cell(dbus, cell);
if (entry) {
if (emit_signals) {
int diff = ril_cell_info_dbus_compare(cell,
&entry->cell);
entry->cell = *cell;
ril_cell_info_dbus_property_changed(dbus,
entry, diff);
} else {
entry->cell = *cell;
}
} else {
entry = g_new0(struct ril_cell_entry, 1);
entry->cell = *cell;
entry->cell_id = ril_cell_info_dbus_next_cell_id(dbus);
entry->path = g_strdup_printf("%s/cell_%u", dbus->path,
entry->cell_id);
dbus->entries = g_slist_append(dbus->entries, entry);
DBG("%s added", entry->path);
g_dbus_register_interface(dbus->conn, entry->path,
RIL_CELL_DBUS_INTERFACE,
ril_cell_info_dbus_cell_methods,
ril_cell_info_dbus_cell_signals, NULL,
entry, NULL);
if (emit_signals) {
if (!added) {
added = g_ptr_array_new();
}
g_ptr_array_add(added, entry->path);
}
}
}
if (removed) {
ril_cell_info_dbus_emit_path_list(dbus,
RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL, removed);
g_ptr_array_free(removed, TRUE);
}
if (added) {
ril_cell_info_dbus_emit_path_list(dbus,
RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL, added);
g_ptr_array_free(added, TRUE);
}
}
static void ril_cell_info_dbus_cells_changed_cb(struct ril_cell_info *info,
void *arg)
{
DBG("");
ril_cell_info_dbus_update_entries((struct ril_cell_info_dbus *)arg,
TRUE);
}
static DBusMessage *ril_cell_info_dbus_get_cells(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_cell_info_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it, array;
GSList *l;
dbus_message_iter_init_append(reply, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
for (l = dbus->entries; l; l = l->next) {
const struct ril_cell_entry *entry = l->data;
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
&entry->path);
}
dbus_message_iter_close_container(&it, &array);
return reply;
}
static const GDBusMethodTable ril_cell_info_dbus_methods[] = {
{ GDBUS_METHOD("GetCells", NULL,
GDBUS_ARGS({ "paths", "ao" }),
ril_cell_info_dbus_get_cells) },
{ }
};
static const GDBusSignalTable ril_cell_info_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL,
GDBUS_ARGS({ "paths", "ao" })) },
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
GDBUS_ARGS({ "paths", "ao" })) },
{ }
};
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
struct ril_cell_info *info)
{
struct ril_cell_info_dbus *dbus = g_new0(struct ril_cell_info_dbus, 1);
DBG("%s", ril_modem_get_path(md));
dbus->md = md;
dbus->path = g_strdup(ril_modem_get_path(md));
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
dbus->info = ril_cell_info_ref(info);
dbus->handler_id = ril_cell_info_add_cells_changed_handler(info,
ril_cell_info_dbus_cells_changed_cb, dbus);
/* Register D-Bus interface */
if (g_dbus_register_interface(dbus->conn, dbus->path,
RIL_CELL_INFO_DBUS_INTERFACE, ril_cell_info_dbus_methods,
ril_cell_info_dbus_signals, NULL, dbus, NULL)) {
ofono_modem_add_interface(md->ofono,
RIL_CELL_INFO_DBUS_INTERFACE);
ril_cell_info_dbus_update_entries(dbus, FALSE);
return dbus;
} else {
ofono_error("RIL D-Bus register failed");
ril_cell_info_dbus_free(dbus);
return NULL;
}
}
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus)
{
if (dbus) {
GSList *l;
DBG("%s", dbus->path);
g_dbus_unregister_interface(dbus->conn, dbus->path,
RIL_CELL_INFO_DBUS_INTERFACE);
ofono_modem_remove_interface(dbus->md->ofono,
RIL_CELL_INFO_DBUS_INTERFACE);
/* Unregister cells */
l = dbus->entries;
while (l) {
struct ril_cell_entry *entry = l->data;
g_dbus_unregister_interface(dbus->conn, entry->path,
RIL_CELL_DBUS_INTERFACE);
ril_cell_info_destroy_entry(entry);
l = l->next;
}
g_slist_free(dbus->entries);
dbus_connection_unref(dbus->conn);
ril_cell_info_remove_handler(dbus->info, dbus->handler_id);
ril_cell_info_unref(dbus->info);
g_free(dbus->path);
g_free(dbus);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

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

View File

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

View File

@@ -1,11 +1,10 @@
/*
*
* RIL constants adopted from AOSP's header:
*
* /hardware/ril/reference_ril/ril.h
*
* Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2013-2016 Jolla Ltd.
* Copyright (C) 2013-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,37 +19,70 @@
#ifndef __RIL_CONSTANTS_H
#define __RIL_CONSTANTS_H 1
#define RIL_MAX_UUID_LENGTH 64
/* Error Codes */
#define RIL_E_SUCCESS 0
#define RIL_E_RADIO_NOT_AVAILABLE 1
#define RIL_E_GENERIC_FAILURE 2
#define RIL_E_PASSWORD_INCORRECT 3
#define RIL_E_SIM_PIN2 4
#define RIL_E_SIM_PUK2 5
#define RIL_E_REQUEST_NOT_SUPPORTED 6
#define RIL_E_CANCELLED 7
#define RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL 8
#define RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW 9
#define RIL_E_SMS_SEND_FAIL_RETRY 10
#define RIL_E_SIM_ABSENT 11
#define RIL_E_SUBSCRIPTION_NOT_AVAILABLE 12
#define RIL_E_MODE_NOT_SUPPORTED 13
#define RIL_E_FDN_CHECK_FAILURE 14
#define RIL_E_ILLEGAL_SIM_OR_ME 15
#define RIL_E_UNUSED 16
#define RIL_E_DIAL_MODIFIED_TO_USSD 17
#define RIL_E_DIAL_MODIFIED_TO_SS 18
#define RIL_E_DIAL_MODIFIED_TO_DIAL 19
#define RIL_E_USSD_MODIFIED_TO_DIAL 20
#define RIL_E_USSD_MODIFIED_TO_SS 21
#define RIL_E_USSD_MODIFIED_TO_USSD 22
#define RIL_E_SS_MODIFIED_TO_DIAL 23
#define RIL_E_SS_MODIFIED_TO_USSD 24
#define RIL_E_SS_MODIFIED_TO_SS 25
#define RIL_E_SUBSCRIPTION_NOT_SUPPORTED 26
#define RIL_E_MISSING_RESOURCE 27
#define RIL_E_NO_SUCH_ELEMENT 28
#define RIL_E_INVALID_PARAMETER 29
enum ril_status {
RIL_E_SUCCESS = 0,
RIL_E_RADIO_NOT_AVAILABLE = 1,
RIL_E_GENERIC_FAILURE = 2,
RIL_E_PASSWORD_INCORRECT = 3,
RIL_E_SIM_PIN2 = 4,
RIL_E_SIM_PUK2 = 5,
RIL_E_REQUEST_NOT_SUPPORTED = 6,
RIL_E_CANCELLED = 7,
RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
RIL_E_SMS_SEND_FAIL_RETRY = 10,
RIL_E_SIM_ABSENT = 11,
RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
RIL_E_MODE_NOT_SUPPORTED = 13,
RIL_E_FDN_CHECK_FAILURE = 14,
RIL_E_ILLEGAL_SIM_OR_ME = 15,
RIL_E_MISSING_RESOURCE = 16,
RIL_E_NO_SUCH_ELEMENT = 17,
RIL_E_DIAL_MODIFIED_TO_USSD = 18,
RIL_E_DIAL_MODIFIED_TO_SS = 19,
RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
RIL_E_USSD_MODIFIED_TO_DIAL = 21,
RIL_E_USSD_MODIFIED_TO_SS = 22,
RIL_E_USSD_MODIFIED_TO_USSD = 23,
RIL_E_SS_MODIFIED_TO_DIAL = 24,
RIL_E_SS_MODIFIED_TO_USSD = 25,
RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
RIL_E_SS_MODIFIED_TO_SS = 27,
RIL_E_LCE_NOT_SUPPORTED = 36,
RIL_E_NO_MEMORY = 37,
RIL_E_INTERNAL_ERR = 38,
RIL_E_SYSTEM_ERR = 39,
RIL_E_MODEM_ERR = 40,
RIL_E_INVALID_STATE = 41,
RIL_E_NO_RESOURCES = 42,
RIL_E_SIM_ERR = 43,
RIL_E_INVALID_ARGUMENTS = 44,
RIL_E_INVALID_SIM_STATE = 45,
RIL_E_INVALID_MODEM_STATE = 46,
RIL_E_INVALID_CALL_ID = 47,
RIL_E_NO_SMS_TO_ACK = 48,
RIL_E_NETWORK_ERR = 49,
RIL_E_REQUEST_RATE_LIMITED = 50,
RIL_E_SIM_BUSY = 51,
RIL_E_SIM_FULL = 52,
RIL_E_NETWORK_REJECT = 53,
RIL_E_OPERATION_NOT_ALLOWED = 54,
RIL_E_EMPTY_RECORD = 55,
RIL_E_INVALID_SMS_FORMAT = 56,
RIL_E_ENCODING_ERR = 57,
RIL_E_INVALID_SMSC_ADDRESS = 58,
RIL_E_NO_SUCH_ENTRY = 59,
RIL_E_NETWORK_NOT_READY = 60,
RIL_E_NOT_PROVISIONED = 61,
RIL_E_NO_SUBSCRIPTION = 62,
RIL_E_NO_NETWORK_FOUND = 63,
RIL_E_DEVICE_IN_USE = 64,
RIL_E_ABORTED = 65,
RIL_E_INVALID_RESPONSE = 66
};
/* call states */
enum ril_call_state {
@@ -114,49 +146,125 @@ enum ril_radio_tech {
RADIO_TECH_HSPAP = 15,
RADIO_TECH_GSM = 16,
RADIO_TECH_TD_SCDMA = 17,
RADIO_TECH_IWLAN = 18
RADIO_TECH_IWLAN = 18,
RADIO_TECH_LTE_CA = 19
};
/* Radio capabilities */
enum ril_radio_access_family {
RAF_GPRS = (1 << RADIO_TECH_GPRS),
RAF_EDGE = (1 << RADIO_TECH_EDGE),
RAF_UMTS = (1 << RADIO_TECH_UMTS),
RAF_IS95A = (1 << RADIO_TECH_IS95A),
RAF_IS95B = (1 << RADIO_TECH_IS95B),
RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
RAF_HSPA = (1 << RADIO_TECH_HSPA),
RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
RAF_LTE = (1 << RADIO_TECH_LTE),
RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
RAF_GSM = (1 << RADIO_TECH_GSM),
RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
};
enum ril_radio_capability_phase {
RC_PHASE_CONFIGURED = 0,
RC_PHASE_START = 1,
RC_PHASE_APPLY = 2,
RC_PHASE_UNSOL_RSP = 3,
RC_PHASE_FINISH = 4
};
enum ril_radio_capability_status {
RC_STATUS_NONE = 0,
RC_STATUS_SUCCESS = 1,
RC_STATUS_FAIL = 2
};
#define RIL_RADIO_CAPABILITY_VERSION 1
struct ril_radio_capability {
int version;
int session;
enum ril_radio_capability_phase phase;
enum ril_radio_access_family rat;
char logicalModemUuid[RIL_MAX_UUID_LENGTH];
int status;
};
enum ril_uicc_subscription_action {
RIL_UICC_SUBSCRIPTION_DEACTIVATE = 0,
RIL_UICC_SUBSCRIPTION_ACTIVATE = 1
};
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
#define CALL_FAIL_UNOBTAINABLE_NUMBER 1
#define CALL_FAIL_NORMAL 16
#define CALL_FAIL_BUSY 17
#define CALL_FAIL_CONGESTION 34
#define CALL_FAIL_ACM_LIMIT_EXCEEDED 68
#define CALL_FAIL_CALL_BARRED 240
#define CALL_FAIL_FDN_BLOCKED 241
#define CALL_FAIL_IMSI_UNKNOWN_IN_VLR 242
#define CALL_FAIL_IMEI_NOT_ACCEPTED 243
#define CALL_FAIL_DIAL_MODIFIED_TO_USSD 244
#define CALL_FAIL_DIAL_MODIFIED_TO_SS 245
#define CALL_FAIL_DIAL_MODIFIED_TO_DIAL 246
#define CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE 1000
#define CALL_FAIL_CDMA_DROP 1001
#define CALL_FAIL_CDMA_INTERCEPT 1002
#define CALL_FAIL_CDMA_REORDER 1003
#define CALL_FAIL_CDMA_SO_REJECT 1004
#define CALL_FAIL_CDMA_RETRY_ORDER 1005
#define CALL_FAIL_CDMA_ACCESS_FAILURE 1006
#define CALL_FAIL_CDMA_PREEMPTED 1007
#define CALL_FAIL_CDMA_NOT_EMERGENCY 1008
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
enum ril_call_fail_cause {
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
CALL_FAIL_NORMAL = 16,
CALL_FAIL_BUSY = 17,
CALL_FAIL_NO_USER_RESPONDING = 18,
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
CALL_FAIL_CALL_REJECTED = 21,
CALL_FAIL_NUMBER_CHANGED = 22,
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
CALL_FAIL_FACILITY_REJECTED = 29,
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
CALL_FAIL_CONGESTION = 34,
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
CALL_FAIL_TEMPORARY_FAILURE = 41,
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
CALL_FAIL_QOS_UNAVAILABLE = 49,
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
CALL_FAIL_CALL_BARRED = 240,
CALL_FAIL_FDN_BLOCKED = 241,
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
/* Not defined in ril.h but valid 3GPP specific cause values
* for call control. See 3GPP TS 24.008 Annex H. */
#define CALL_FAIL_NO_ROUTE_TO_DESTINATION 3
#define CALL_FAIL_CHANNEL_UNACCEPTABLE 6
#define CALL_FAIL_OPERATOR_DETERMINED_BARRING 8
#define CALL_FAIL_NO_USER_RESPONDING 18
#define CALL_FAIL_USER_ALERTING_NO_ANSWER 19
#define CALL_FAIL_CALL_REJECTED 21
#define CALL_FAIL_NUMBER_CHANGED 22
#define CALL_FAIL_ANONYMOUS_CALL_REJECTION 24
#define CALL_FAIL_PRE_EMPTION 25
#define CALL_FAIL_DESTINATION_OUT_OF_ORDER 27
#define CALL_FAIL_INCOMPLETE_NUMBER 28
#define CALL_FAIL_FACILITY_REJECTED 29
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
CALL_FAIL_PRE_EMPTION = 25
};
enum ril_data_call_fail_cause {
PDP_FAIL_NONE = 0,
@@ -287,40 +395,7 @@ enum ril_cell_info_type {
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
};
struct ril_cell_info_gsm {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int lac; /* Location Area Code (0..65535) */
int cid; /* GSM Cell Identity (0..65535) TS 27.007 */
int signalStrength; /* (0-31, 99) TS 27.007 */
int bitErrorRate; /* (0-7, 99) TS 27.007 */
};
struct ril_cell_info_wcdma {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int lac; /* Location Area Code (0..65535) */
int cid; /* UMTS Cell Identity (0..268435455) TS 25.331 */
int psc; /* Primary Scrambling Code (0..511) TS 25.331) */
int signalStrength; /* (0-31, 99) TS 27.007 */
int bitErrorRate; /* (0-7, 99) TS 27.007 */
};
struct ril_cell_info_lte {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int ci; /* Cell Identity */
int pci; /* Physical cell id (0..503) */
int tac; /* Tracking area code */
int signalStrength; /* (0-31, 99) TS 27.007 8.5 */
int rsrp; /* Reference Signal Receive Power TS 36.133 */
int rsrq; /* Reference Signal Receive Quality TS 36.133 */
int rssnr; /* Reference Signal-to-Noise Ratio TS 36.101*/
int cqi; /* Channel Quality Indicator TS 36.101 */
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
};
/* RIL Request Messages */
/* 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
@@ -455,7 +530,7 @@ struct ril_cell_info_lte {
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
/* RIL Unsolicited Messages */
/* 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
@@ -503,6 +578,9 @@ struct ril_cell_info_lte {
#define RIL_UNSOL_ON_SS 1043
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
/* A special request, ofono -> rild */
#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
/* Suplementary services Service class*/
#define SERVICE_CLASS_NONE 0

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -27,9 +27,7 @@
#include <grilio_parser.h>
#include <grilio_request.h>
#define SETUP_DATA_CALL_PARAMS 7
#define DATA_PROFILE_DEFAULT_STR "0"
#define DEACTIVATE_DATA_CALL_PARAMS 2
#define PROTO_IP_STR "IP"
#define PROTO_IPV6_STR "IPV6"
@@ -170,9 +168,9 @@ struct ril_data_request_deact {
int cid;
};
struct ril_data_request_2g {
struct ril_data_request_allow_data {
struct ril_data_request req;
gulong handler_id;
gboolean allow;
};
static void ril_data_manager_check_data(struct ril_data_manager *dm);
@@ -184,6 +182,26 @@ static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
g_signal_emit(self, ril_data_signals[id], 0);
}
/*==========================================================================*
* RIL requests
*==========================================================================*/
GRilIoRequest *ril_request_allow_data_new(gboolean allow)
{
return grilio_request_array_int32_new(1, allow);
}
GRilIoRequest *ril_request_deactivate_data_call_new(int cid)
{
GRilIoRequest *req = grilio_request_new();
grilio_request_append_int32(req, 2 /* Parameter count */);
grilio_request_append_format(req, "%d", cid);
grilio_request_append_format(req, "%d",
RIL_DEACTIVATE_DATA_CALL_NO_REASON);
return req;
}
/*==========================================================================*
* ril_data_call
*==========================================================================*/
@@ -787,8 +805,8 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
G_CAST(req, struct ril_data_request_setup, req);
struct ril_data_priv *priv = req->data->priv;
const char *proto_str = ril_data_ofono_protocol_to_ril(setup->proto);
GRilIoRequest* ioreq;
int tech, auth;
GRilIoRequest *ioreq;
int tech, auth = RIL_AUTH_NONE;
GASSERT(proto_str);
@@ -811,21 +829,29 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
tech = RADIO_TECH_HSPA;
}
/*
* We do the same as in $AOSP/frameworks/opt/telephony/src/java/com/
* android/internal/telephony/dataconnection/DataConnection.java,
* onConnect(), and use authentication or not depending on whether
* the user field is empty or not.
*/
auth = (setup->username && setup->username[0]) ?
RIL_AUTH_BOTH : RIL_AUTH_NONE;
if (setup->username && setup->username[0]) {
switch (setup->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
auth = RIL_AUTH_BOTH;
break;
case OFONO_GPRS_AUTH_METHOD_NONE:
auth = RIL_AUTH_NONE;
break;
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = RIL_AUTH_CHAP;
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = RIL_AUTH_PAP;
break;
}
}
/*
* TODO: add comments about tethering, other non-public
* profiles...
*/
ioreq = grilio_request_new();
grilio_request_append_int32(ioreq, SETUP_DATA_CALL_PARAMS);
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
grilio_request_append_format(ioreq, "%d", tech);
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
grilio_request_append_utf8(ioreq, setup->apn);
@@ -924,6 +950,10 @@ static void ril_data_call_deact_cb(GRilIoChannel *io, int ril_status,
ril_data_call_free(call);
ril_data_signal_emit(data, SIGNAL_CALLS_CHANGED);
}
} else {
/* Something seems to be slightly broken, request the
* current state */
ril_data_poll_call_state(data);
}
if (req->cb.deact) {
@@ -938,12 +968,8 @@ static gboolean ril_data_call_deact_submit(struct ril_data_request *req)
struct ril_data_request_deact *deact =
G_CAST(req, struct ril_data_request_deact, req);
struct ril_data_priv *priv = req->data->priv;
GRilIoRequest* ioreq = grilio_request_new();
grilio_request_append_int32(ioreq, DEACTIVATE_DATA_CALL_PARAMS);
grilio_request_append_format(ioreq, "%d", deact->cid);
grilio_request_append_format(ioreq, "%d",
RIL_DEACTIVATE_DATA_CALL_NO_REASON);
GRilIoRequest *ioreq =
ril_request_deactivate_data_call_new(deact->cid);
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
RIL_REQUEST_DEACTIVATE_DATA_CALL,
@@ -975,15 +1001,6 @@ static struct ril_data_request *ril_data_call_deact_new(struct ril_data *data,
* ril_data_allow_request
*==========================================================================*/
static GRilIoRequest *ril_data_allow_req(gboolean allow)
{
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, allow != FALSE);
return req;
}
static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
const void *req_data, guint len, void *user_data)
{
@@ -993,13 +1010,22 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
ril_data_request_completed(req);
if (ril_status == RIL_E_SUCCESS &&
(priv->flags & RIL_DATA_FLAG_ALLOWED)) {
GASSERT(!ril_data_allowed(data));
priv->flags |= RIL_DATA_FLAG_ON;
GASSERT(ril_data_allowed(data));
DBG_(data, "data on");
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
if (ril_status == RIL_E_SUCCESS) {
const gboolean was_allowed = ril_data_allowed(data);
struct ril_data_request_allow_data *ad =
G_CAST(req, struct ril_data_request_allow_data, req);
if (ad->allow) {
priv->flags |= RIL_DATA_FLAG_ON;
DBG_(data, "data on");
} else {
priv->flags &= ~RIL_DATA_FLAG_ON;
DBG_(data, "data off");
}
if (ril_data_allowed(data) != was_allowed) {
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
}
}
ril_data_request_finish(req);
@@ -1007,25 +1033,32 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
static gboolean ril_data_allow_submit(struct ril_data_request *req)
{
GRilIoRequest *ioreq = ril_data_allow_req(TRUE);
struct ril_data_request_allow_data *ad =
G_CAST(req, struct ril_data_request_allow_data, req);
GRilIoRequest *ioreq = ril_request_allow_data_new(ad->allow);
struct ril_data_priv *priv = req->data->priv;
grilio_request_set_retry(ioreq, RIL_RETRY_SECS*1000, -1);
grilio_request_set_blocking(ioreq, TRUE);
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
RIL_REQUEST_ALLOW_DATA, ril_data_allow_cb, NULL, req);
grilio_request_unref(ioreq);
return TRUE;
}
static struct ril_data_request *ril_data_allow_new(struct ril_data *data)
static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
gboolean allow)
{
struct ril_data_request *req = g_new0(struct ril_data_request, 1);
struct ril_data_request_allow_data *ad =
g_new0(struct ril_data_request_allow_data, 1);
struct ril_data_request *req = &ad->req;
req->name = "ALLOW_DATA";
req->data = data;
req->submit = ril_data_allow_submit;
req->cancel = ril_data_request_cancel_io;
req->flags = DATA_REQUEST_FLAG_CANCEL_WHEN_DISALLOWED;
ad->allow = allow;
return req;
}
@@ -1080,12 +1113,11 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_data *self = g_object_new(RIL_DATA_TYPE, NULL);
struct ril_data_priv *priv = self->priv;
struct ril_sim_settings *settings = network->settings;
GRilIoRequest *req = grilio_request_new();
priv->options = *options;
switch (priv->options.allow_data) {
case RIL_ALLOW_DATA_ON:
case RIL_ALLOW_DATA_OFF:
case RIL_ALLOW_DATA_ENABLED:
case RIL_ALLOW_DATA_DISABLED:
break;
default:
/*
@@ -1093,7 +1125,8 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
* RIL_VERSION was 10
*/
priv->options.allow_data = (io->ril_version > 10) ?
RIL_ALLOW_DATA_ON : RIL_ALLOW_DATA_OFF;
RIL_ALLOW_DATA_ENABLED :
RIL_ALLOW_DATA_DISABLED;
break;
}
@@ -1118,12 +1151,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
ril_data_settings_changed, self);
/* Request the current state */
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
priv->query_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_DATA_CALL_LIST,
ril_data_query_data_calls_cb,
NULL, self);
grilio_request_unref(req);
ril_data_poll_call_state(self);
/* Order data contexts according to slot numbers */
dm->data_list = g_slist_insert_sorted(dm->data_list, self,
@@ -1134,6 +1162,25 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
return NULL;
}
void ril_data_poll_call_state(struct ril_data *self)
{
if (G_LIKELY(self)) {
struct ril_data_priv *priv = self->priv;
if (!priv->query_id) {
GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
priv->query_id =
grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_DATA_CALL_LIST,
ril_data_query_data_calls_cb,
NULL, self);
grilio_request_unref(req);
}
}
}
struct ril_data *ril_data_ref(struct ril_data *self)
{
if (G_LIKELY(self)) {
@@ -1180,8 +1227,7 @@ static void ril_data_power_update(struct ril_data *self)
{
struct ril_data_priv *priv = self->priv;
if (priv->pending_req || priv->req_queue ||
(priv->flags & RIL_DATA_FLAG_ALLOWED)) {
if (priv->pending_req || priv->req_queue) {
ril_radio_power_on(priv->radio, self);
} else {
ril_radio_power_off(priv->radio, self);
@@ -1211,10 +1257,11 @@ static void ril_data_cancel_requests(struct ril_data *self,
static void ril_data_disallow(struct ril_data *self)
{
struct ril_data_priv *priv = self->priv;
const gboolean was_allowed = ril_data_allowed(self);
DBG_(self, "disallowed");
GASSERT(priv->flags & RIL_DATA_FLAG_ALLOWED);
priv->flags &= ~(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
priv->flags &= ~RIL_DATA_FLAG_ALLOWED;
/*
* Cancel all requests that can be canceled.
@@ -1227,7 +1274,20 @@ static void ril_data_disallow(struct ril_data *self)
* requests are already pending? That's quite unlikely though)
*/
ril_data_deactivate_all(self);
ril_data_power_update(self);
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
/* Tell rild that the data is now disabled */
ril_data_request_queue(ril_data_allow_new(self, FALSE));
} else {
priv->flags &= ~RIL_DATA_FLAG_ON;
GASSERT(!ril_data_allowed(self));
DBG_(self, "data off");
ril_data_power_update(self);
}
if (ril_data_allowed(self) != was_allowed) {
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
}
}
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
@@ -1244,12 +1304,7 @@ static void ril_data_disallow_cb(gpointer data_ptr, gpointer allowed)
struct ril_data *data = data_ptr;
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
const gboolean was_allowed = ril_data_allowed(data);
ril_data_disallow(data);
if (was_allowed) {
ril_data_signal_emit(data,
SIGNAL_ALLOW_CHANGED);
}
}
}
}
@@ -1303,13 +1358,7 @@ void ril_data_allow(struct ril_data *self, enum ril_data_role role)
}
} else {
if (priv->flags & RIL_DATA_FLAG_ALLOWED) {
gboolean was_allowed = ril_data_allowed(self);
ril_data_disallow(self);
if (was_allowed) {
ril_data_signal_emit(self,
SIGNAL_ALLOW_CHANGED);
}
ril_data_manager_check_data(dm);
}
}
@@ -1538,9 +1587,8 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
}
if (priv->options.allow_data == RIL_ALLOW_DATA_ON) {
ril_data_request_queue(ril_data_allow_new(data));
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
ril_data_request_queue(ril_data_allow_new(data, TRUE));
} else {
priv->flags |= RIL_DATA_FLAG_ON;
GASSERT(ril_data_allowed(data));
@@ -1563,6 +1611,16 @@ static void ril_data_manager_check_data(struct ril_data_manager *self)
}
}
void ril_data_manager_assert_data_on(struct ril_data_manager *self)
{
if (self) {
struct ril_data *data = ril_data_manager_allowed(self);
if (data) {
ril_data_request_queue(ril_data_allow_new(data, TRUE));
}
}
}
/*
* Local Variables:
* mode: C

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -56,8 +56,8 @@ enum ril_data_manager_flags {
enum ril_data_allow_data_opt {
RIL_ALLOW_DATA_AUTO,
RIL_ALLOW_DATA_ON,
RIL_ALLOW_DATA_OFF
RIL_ALLOW_DATA_ENABLED,
RIL_ALLOW_DATA_DISABLED
};
enum ril_data_call_format {
@@ -84,6 +84,7 @@ struct ril_data_manager;
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
void ril_data_manager_unref(struct ril_data_manager *dm);
void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
@@ -99,6 +100,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
gboolean ril_data_allowed(struct ril_data *data);
void ril_data_poll_call_state(struct ril_data *data);
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
ril_data_cb_t cb, void *arg);
@@ -122,6 +124,10 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
int cid);
/* Constructors of various kinds of RIL requests */
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
#endif /* RIL_DATA_H */
/*

View File

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

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,6 @@
#include "ril_network.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_mtu.h"
#include "ril_log.h"
#include <gutil_strv.h>
@@ -25,6 +24,7 @@
#include <arpa/inet.h>
#include "common.h"
#include "mtu-watch.h"
#define CTX_ID_NONE ((unsigned int)(-1))
@@ -43,7 +43,7 @@ struct ril_gprs_context {
struct ril_data *data;
guint active_ctx_cid;
gulong calls_changed_id;
struct ril_mtu_watch *mtu_watch;
struct mtu_watch *mtu_watch;
struct ril_data_call *active_call;
struct ril_gprs_context_call activate;
struct ril_gprs_context_call deactivate;
@@ -95,7 +95,7 @@ static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
gcd->calls_changed_id = 0;
}
if (gcd->mtu_watch) {
ril_mtu_watch_free(gcd->mtu_watch);
mtu_watch_free(gcd->mtu_watch);
gcd->mtu_watch = NULL;
}
}
@@ -107,9 +107,9 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
ril_data_call_free(gcd->active_call);
gcd->active_call = ril_data_call_dup(call);
if (!gcd->mtu_watch) {
gcd->mtu_watch = ril_mtu_watch_new(MAX_MTU);
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
}
ril_mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
} else {
ril_gprs_context_free_active_call(gcd);
}
@@ -575,7 +575,7 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
ril_data_unref(gcd->data);
ril_network_unref(gcd->network);
ril_data_call_free(gcd->active_call);
ril_mtu_watch_free(gcd->mtu_watch);
mtu_watch_free(gcd->mtu_watch);
g_free(gcd);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -25,6 +25,8 @@
#include "ofono.h"
#include "sailfish_watch.h"
#define MAX_PDP_CONTEXTS (2)
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
@@ -50,24 +52,20 @@ struct ril_modem_online_request {
struct ril_modem_data {
struct ril_modem modem;
struct sailfish_watch *watch;
GRilIoQueue *q;
char *log_prefix;
char *imeisv;
char *imei;
char *ecclist_file;
gboolean pre_sim_done;
gboolean allow_data;
gulong sim_imsi_event_id;
gulong imsi_event_id;
guint online_check_id;
enum ril_modem_power_state power_state;
gulong radio_state_event_id;
ril_modem_cb_t removed_cb;
void *removed_cb_data;
ril_modem_online_cb_t online_cb;
void *online_cb_data;
struct ril_modem_online_request set_online;
struct ril_modem_online_request set_offline;
};
@@ -83,11 +81,6 @@ static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
return md;
}
static struct ril_modem_data *ril_modem_data_from_modem(struct ril_modem *m)
{
return m ? G_CAST(m, struct ril_modem_data, modem) : NULL;
}
static void *ril_modem_get_atom_data(struct ril_modem *modem,
enum ofono_atom_type type)
{
@@ -131,24 +124,6 @@ void ril_modem_delete(struct ril_modem *md)
}
}
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
void *data)
{
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
md->removed_cb = cb;
md->removed_cb_data = data;
}
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
void *data)
{
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
md->online_cb = cb;
md->online_cb_data = data;
}
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
{
if (req->timeout_id) {
@@ -233,7 +208,7 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
{
struct ril_modem *m = &md->modem;
if (m->radio->state == RADIO_STATE_ON && m->sim_settings->imsi) {
if (m->radio->state == RADIO_STATE_ON && md->watch->imsi) {
/* radio-settings.c assumes that IMSI is available */
if (!ril_modem_radio_settings(m)) {
DBG_(md, "initializing radio settings interface");
@@ -261,11 +236,11 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
ril_modem_update_online_state(md);
}
static void ril_modem_imsi_cb(struct ril_sim_settings *settings, void *data)
static void ril_modem_imsi_cb(struct sailfish_watch *watch, void *data)
{
struct ril_modem_data *md = data;
GASSERT(md->modem.sim_settings == settings);
GASSERT(md->watch == watch);
ril_modem_update_radio_settings(md);
}
@@ -277,7 +252,9 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
md->pre_sim_done = TRUE;
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
if (md->modem.config.enable_voicecall) {
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
}
if (!md->radio_state_event_id) {
md->radio_state_event_id =
ril_radio_add_state_changed_handler(md->modem.radio,
@@ -331,20 +308,18 @@ static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
ofono_modem_online_cb_t cb, void *data)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
struct ril_radio *radio = md->modem.radio;
struct ril_modem_online_request *req;
DBG("%s going %sline", ofono_modem_get_path(modem),
online ? "on" : "off");
if (md->online_cb) {
md->online_cb(&md->modem, online, md->online_cb_data);
}
ril_radio_set_online(radio, online);
if (online) {
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
ril_radio_power_on(radio, RADIO_POWER_TAG(md));
req = &md->set_online;
} else {
ril_radio_power_off(md->modem.radio, RADIO_POWER_TAG(md));
ril_radio_power_off(radio, RADIO_POWER_TAG(md));
req = &md->set_offline;
}
@@ -393,25 +368,16 @@ static void ril_modem_remove(struct ofono_modem *ofono)
struct ril_modem *modem = &md->modem;
DBG("%s", ril_modem_get_path(modem));
if (md->removed_cb) {
ril_modem_cb_t cb = md->removed_cb;
void *data = md->removed_cb_data;
md->removed_cb = NULL;
md->removed_cb_data = NULL;
cb(modem, data);
}
ofono_modem_set_data(ofono, NULL);
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
ril_radio_unref(modem->radio);
ril_sim_settings_remove_handler(modem->sim_settings,
md->sim_imsi_event_id);
ril_sim_settings_unref(modem->sim_settings);
sailfish_watch_remove_handler(md->watch, md->imsi_event_id);
sailfish_watch_unref(md->watch);
if (md->online_check_id) {
g_source_remove(md->online_check_id);
}
@@ -426,25 +392,28 @@ static void ril_modem_remove(struct ofono_modem *ofono)
ril_network_unref(modem->network);
ril_sim_card_unref(modem->sim_card);
ril_cell_info_unref(modem->cell_info);
ril_data_unref(modem->data);
sailfish_cell_info_unref(modem->cell_info);
grilio_channel_unref(modem->io);
grilio_queue_cancel_all(md->q, FALSE);
grilio_queue_unref(md->q);
g_free(md->ecclist_file);
g_free(md->log_prefix);
g_free(md->imeisv);
g_free(md->imei);
g_free(md);
}
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,
struct ril_network *network, struct ril_sim_card *card,
struct ril_data *data, struct ril_sim_settings *settings,
struct ril_cell_info *cell_info)
const char *path, const char *imei, const char *imeisv,
const char *ecclist_file, const struct ril_slot_config *config,
struct ril_radio *radio, struct ril_network *network,
struct ril_sim_card *card, struct ril_data *data,
struct ril_sim_settings *settings,
struct sailfish_cell_info *cell_info)
{
/* Skip the slash from the path, it looks like "/ril_0" */
struct ofono_modem *ofono = ofono_modem_create(slot->path + 1,
struct ofono_modem *ofono = ofono_modem_create(path + 1,
RILMODEM_DRIVER);
if (ofono) {
int err;
@@ -455,14 +424,14 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
* ril_plugin.c must wait until IMEI becomes known before
* creating the modem
*/
GASSERT(slot->imei);
GASSERT(imei);
/* Copy config */
modem->config = *slot->config;
modem->imei = md->imei = g_strdup(slot->imei);
modem->log_prefix = log_prefix;
modem->ecclist_file =
md->ecclist_file = g_strdup(slot->ecclist_file);
modem->config = *config;
modem->imei = md->imei = g_strdup(imei);
modem->imeisv = md->imeisv = g_strdup(imeisv);
modem->log_prefix = log_prefix; /* No need to strdup */
modem->ecclist_file = ecclist_file; /* No need to strdup */
md->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
@@ -471,18 +440,14 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
modem->network = ril_network_ref(network);
modem->sim_card = ril_sim_card_ref(card);
modem->sim_settings = ril_sim_settings_ref(settings);
modem->cell_info = ril_cell_info_ref(cell_info);
modem->cell_info = sailfish_cell_info_ref(cell_info);
modem->data = ril_data_ref(data);
modem->io = grilio_channel_ref(io);
md->q = grilio_queue_new(io);
md->watch = sailfish_watch_new(path);
/*
* modem->sim_settings->imsi follows IMSI known to the ofono
* core, unlike ril_sim_info->imsi which may point to the
* cached IMSI even before the PIN code is entered.
*/
md->sim_imsi_event_id =
ril_sim_settings_add_imsi_changed_handler(settings,
md->imsi_event_id =
sailfish_watch_add_imsi_changed_handler(md->watch,
ril_modem_imsi_cb, md);
md->set_online.md = md;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,15 +14,16 @@
*/
#include "ril_plugin.h"
#include "ril_cell_info.h"
#include "ril_util.h"
#include "ril_log.h"
#include <sailfish_cell_info.h>
#include "ofono.h"
struct ril_netmon {
struct ofono_netmon *netmon;
struct ril_cell_info *cell_info;
struct sailfish_cell_info *cell_info;
guint register_id;
};
@@ -50,7 +51,7 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
}
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
const struct ril_cell_info_gsm *gsm)
const struct sailfish_cell_info_gsm *gsm)
{
char mcc[OFONO_MAX_MCC_LENGTH + 1];
char mnc[OFONO_MAX_MNC_LENGTH + 1];
@@ -68,7 +69,7 @@ static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
}
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
const struct ril_cell_info_wcdma *wcdma)
const struct sailfish_cell_info_wcdma *wcdma)
{
char mcc[OFONO_MAX_MCC_LENGTH + 1];
char mnc[OFONO_MAX_MNC_LENGTH + 1];
@@ -87,7 +88,7 @@ static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
}
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
const struct ril_cell_info_lte *lte)
const struct sailfish_cell_info_lte *lte)
{
char mcc[OFONO_MAX_MCC_LENGTH + 1];
char mnc[OFONO_MAX_MNC_LENGTH + 1];
@@ -111,19 +112,19 @@ static void ril_netmon_request_update(struct ofono_netmon *netmon,
GSList *l;
for (l = nm->cell_info->cells; l; l = l->next) {
const struct ril_cell *cell = l->data;
const struct sailfish_cell *cell = l->data;
if (cell->registered) {
switch (cell->type) {
case RIL_CELL_INFO_TYPE_GSM:
case SAILFISH_CELL_TYPE_GSM:
ril_netmon_notify_gsm(netmon,
&cell->info.gsm);
break;
case RIL_CELL_INFO_TYPE_WCDMA:
case SAILFISH_CELL_TYPE_WCDMA:
ril_netmon_notify_wcdma(netmon,
&cell->info.wcdma);
break;
case RIL_CELL_INFO_TYPE_LTE:
case SAILFISH_CELL_TYPE_LTE:
ril_netmon_notify_lte(netmon,
&cell->info.lte);
break;
@@ -156,7 +157,7 @@ static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor,
if (modem->cell_info) {
struct ril_netmon *nm = g_slice_new0(struct ril_netmon);
nm->cell_info = ril_cell_info_ref(modem->cell_info);
nm->cell_info = sailfish_cell_info_ref(modem->cell_info);
nm->netmon = netmon;
ofono_netmon_set_data(netmon, nm);
@@ -182,7 +183,7 @@ static void ril_netmon_remove(struct ofono_netmon *netmon)
g_source_remove(nm->register_id);
}
ril_cell_info_unref(nm->cell_info);
sailfish_cell_info_unref(nm->cell_info);
g_slice_free(struct ril_netmon, nm);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -47,12 +47,17 @@ enum ril_network_radio_event {
RADIO_EVENT_COUNT
};
enum ril_network_unsol_event {
UNSOL_EVENT_NETWORK_STATE,
UNSOL_EVENT_RADIO_CAPABILITY,
UNSOL_EVENT_COUNT
};
struct ril_network_priv {
GRilIoChannel *io;
GRilIoQueue *q;
struct ril_radio *radio;
struct ril_sim_card *sim_card;
enum ofono_radio_access_mode max_pref_mode;
int rat;
char *log_prefix;
guint operator_poll_id;
@@ -61,11 +66,12 @@ struct ril_network_priv {
guint timer[TIMER_COUNT];
gulong query_rat_id;
gulong set_rat_id;
gulong ril_event_id;
gulong unsol_event_id[UNSOL_EVENT_COUNT];
gulong settings_event_id;
gulong sim_status_event_id;
gulong radio_event_id[RADIO_EVENT_COUNT];
struct ofono_network_operator operator;
gboolean assert_rat;
};
enum ril_network_signal {
@@ -73,13 +79,15 @@ enum ril_network_signal {
SIGNAL_VOICE_STATE_CHANGED,
SIGNAL_DATA_STATE_CHANGED,
SIGNAL_PREF_MODE_CHANGED,
SIGNAL_MAX_PREF_MODE_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
#define SIGNAL_MAX_PREF_MODE_CHANGED_NAME "ril-network-max-pref-mode-changed"
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
@@ -200,8 +208,14 @@ static gboolean ril_network_parse_response(struct ril_network *self,
reg->max_calls = 2;
}
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
if (!ril_parse_int(slac, 16, &reg->lac)) {
reg->lac = -1;
}
if (!ril_parse_int(sci, 16, &reg->ci)) {
reg->ci = -1;
}
reg->access_tech = ril_parse_tech(stech, &reg->ril_tech);
DBG_(self, "%s,%s,%s,%d,%s,%s,%s",
@@ -420,13 +434,16 @@ static int ril_network_mode_to_rat(struct ril_network *self,
switch (mode) {
case OFONO_RADIO_ACCESS_MODE_ANY:
case OFONO_RADIO_ACCESS_MODE_LTE:
if (self->settings->enable_4g) {
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
return PREF_NET_TYPE_LTE_GSM_WCDMA;
}
/* no break */
default:
case OFONO_RADIO_ACCESS_MODE_UMTS:
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_UMTS) {
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
}
/* no break */
case OFONO_RADIO_ACCESS_MODE_GSM:
return PREF_NET_TYPE_GSM_ONLY;
}
@@ -447,7 +464,7 @@ static int ril_network_pref_mode_expected(struct ril_network *self)
* it becomes necessary.
*/
const enum ofono_radio_access_mode max_pref_mode =
(priv->radio->state == RADIO_STATE_ON) ? priv->max_pref_mode :
(priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
OFONO_RADIO_ACCESS_MODE_GSM;
/*
@@ -486,7 +503,7 @@ static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
* and SIM card state change callbacks will schedule a new check
* when it's appropriate.
*/
if (priv->rat != rat) {
if (priv->rat != rat || priv->assert_rat) {
if (ril_network_can_set_pref_mode(self)) {
ril_network_set_pref_mode(self, rat);
} else {
@@ -527,6 +544,9 @@ static void ril_network_set_pref_mode(struct ril_network *self, int rat)
ril_network_set_pref_mode_cb, NULL, self);
grilio_request_unref(req);
/* We have submitted the request, clear the assertion flag */
priv->assert_rat = FALSE;
/* Don't do it too often */
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
priv->timer[TIMER_SET_RAT_HOLDOFF] =
@@ -554,8 +574,7 @@ static void ril_network_check_pref_mode(struct ril_network *self,
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
}
if (priv->rat != rat) {
/* Something isn't right, we need to fix it */
if (priv->rat != rat || priv->assert_rat) {
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
ril_network_set_pref_mode(self, rat);
} else {
@@ -644,17 +663,25 @@ void ril_network_set_max_pref_mode(struct ril_network *self,
enum ofono_radio_access_mode max_mode,
gboolean force_check)
{
if (G_LIKELY(self)) {
struct ril_network_priv *priv = self->priv;
if (priv->max_pref_mode != max_mode || force_check) {
if (self && (self->max_pref_mode != max_mode || force_check)) {
if (self->max_pref_mode != max_mode) {
DBG_(self, "rat mode %d (%s)", max_mode,
ofono_radio_access_mode_to_string(max_mode));
priv->max_pref_mode = max_mode;
ril_network_check_pref_mode(self, TRUE);
self->max_pref_mode = max_mode;
ril_network_emit(self, SIGNAL_MAX_PREF_MODE_CHANGED);
}
ril_network_check_pref_mode(self, TRUE);
}
}
void ril_network_assert_pref_mode(struct ril_network *self, gboolean immediate)
{
struct ril_network_priv *priv = self->priv;
priv->assert_rat = TRUE;
ril_network_check_pref_mode(self, immediate);
}
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
@@ -683,6 +710,13 @@ gulong ril_network_add_pref_mode_changed_handler(struct ril_network *self,
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_MAX_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_network_remove_handler(struct ril_network *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
@@ -695,7 +729,7 @@ void ril_network_remove_handlers(struct ril_network *self, gulong *ids, int n)
gutil_disconnect_handlers(self, ids, n);
}
static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
static void ril_network_state_changed_cb(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
@@ -705,6 +739,16 @@ static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
ril_network_poll_state(self);
}
static void ril_network_radio_capability_changed_cb(GRilIoChannel *io,
guint code, const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
DBG_(self, "");
GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
ril_network_assert_pref_mode(self, FALSE);
}
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
{
struct ril_network *self = RIL_NETWORK(data);
@@ -767,8 +811,9 @@ static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
}
}
struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
struct ril_radio *radio, struct ril_sim_card *sim_card,
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_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
@@ -782,9 +827,14 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
priv->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
DBG_(self, "");
priv->ril_event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_network_voice_state_changed_cb,
priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
grilio_channel_add_unsol_event_handler(priv->io,
ril_network_state_changed_cb,
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
priv->unsol_event_id[UNSOL_EVENT_RADIO_CAPABILITY] =
grilio_channel_add_unsol_event_handler(priv->io,
ril_network_radio_capability_changed_cb,
RIL_UNSOL_RADIO_CAPABILITY, self);
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
ril_radio_add_state_changed_handler(priv->radio,
ril_network_radio_state_cb, self);
@@ -840,57 +890,45 @@ static void ril_network_init(struct ril_network *self)
priv->rat = -1;
}
static void ril_network_dispose(GObject *object)
static void ril_network_finalize(GObject *object)
{
struct ril_network *self = RIL_NETWORK(object);
struct ril_network_priv *priv = self->priv;
enum ril_network_timer tid;
grilio_channel_remove_handlers(priv->io, &priv->ril_event_id, 1);
ril_radio_remove_handlers(priv->radio, priv->radio_event_id,
G_N_ELEMENTS(priv->radio_event_id));
ril_sim_settings_remove_handlers(self->settings,
&priv->settings_event_id, 1);
ril_sim_card_remove_handlers(priv->sim_card,
&priv->sim_status_event_id, 1);
DBG_(self, "");
for (tid=0; tid<TIMER_COUNT; tid++) {
ril_network_stop_timer(self, tid);
}
grilio_queue_cancel_all(priv->q, FALSE);
priv->set_rat_id = 0;
priv->query_rat_id = 0;
grilio_channel_remove_handlers(priv->io, priv->unsol_event_id,
G_N_ELEMENTS(priv->unsol_event_id));
G_OBJECT_CLASS(ril_network_parent_class)->dispose(object);
}
static void ril_network_finalize(GObject *object)
{
struct ril_network *self = RIL_NETWORK(object);
struct ril_network_priv *priv = self->priv;
DBG_(self, "");
g_free(priv->log_prefix);
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_settings_remove_handler(self->settings,
priv->settings_event_id);
ril_sim_settings_unref(self->settings);
g_free(priv->log_prefix);
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
}
static void ril_network_class_init(RilNetworkClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_network_dispose;
object_class->finalize = ril_network_finalize;
G_OBJECT_CLASS(klass)->finalize = ril_network_finalize;
g_type_class_add_private(klass, sizeof(struct ril_network_priv));
RIL_NETWORK_SIGNAL(klass, OPERATOR);
RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
RIL_NETWORK_SIGNAL(klass, DATA_STATE);
RIL_NETWORK_SIGNAL(klass, PREF_MODE);
RIL_NETWORK_SIGNAL(klass, MAX_PREF_MODE);
}
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,8 +18,6 @@
#include "ril_types.h"
#include <ofono/radio-settings.h>
struct ofono_network_operator;
struct ril_registration_state {
@@ -38,14 +36,16 @@ struct ril_network {
struct ril_registration_state data;
const struct ofono_network_operator *operator;
enum ofono_radio_access_mode pref_mode;
enum ofono_radio_access_mode max_pref_mode;
struct ril_sim_settings *settings;
};
struct ofono_sim;
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
struct ril_radio *radio, struct ril_sim_card *sim_card,
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_network *ril_network_ref(struct ril_network *net);
void ril_network_unref(struct ril_network *net);
@@ -53,6 +53,7 @@ void ril_network_unref(struct ril_network *net);
void ril_network_set_max_pref_mode(struct ril_network *net,
enum ofono_radio_access_mode max_pref_mode,
gboolean force_check);
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
@@ -61,6 +62,8 @@ gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
void ril_network_remove_handler(struct ril_network *net, gulong id);
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,7 +24,6 @@
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
struct ril_oem_raw {
struct ril_modem *modem;
GRilIoQueue *q;
DBusConnection *conn;
char *path;
@@ -118,7 +117,6 @@ struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
struct ril_oem_raw *oem = g_new0(struct ril_oem_raw, 1);
DBG("%s", ril_modem_get_path(modem));
oem->modem = modem;
oem->path = g_strdup(ril_modem_get_path(modem));
oem->conn = dbus_connection_ref(ofono_dbus_get_connection());
oem->q = grilio_queue_new(ril_modem_io(modem));
@@ -144,8 +142,6 @@ void ril_oem_raw_free(struct ril_oem_raw *oem)
DBG("%s", oem->path);
g_dbus_unregister_interface(oem->conn, oem->path,
RIL_OEM_RAW_INTERFACE);
ofono_modem_remove_interface(oem->modem->ofono,
RIL_OEM_RAW_INTERFACE);
dbus_connection_unref(oem->conn);
grilio_queue_cancel_all(oem->q, TRUE);

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
#define RIL_PLUGIN_H
#include "ril_types.h"
#include "sailfish_manager.h"
#include <ofono/modem.h>
#include <ofono/call-barring.h>
@@ -43,100 +44,38 @@
#define RILMODEM_DRIVER "ril"
typedef struct ril_slot_info const *ril_slot_info_ptr;
struct ril_slot_info {
const char *path;
const char *imei;
const char *ecclist_file;
gboolean enabled;
gboolean sim_present;
const struct ril_slot_config *config;
};
struct ril_plugin {
const char *mms_imsi;
const char *mms_path;
const char *default_voice_imsi;
const char *default_data_imsi;
const char *default_voice_path;
const char *default_data_path;
const ril_slot_info_ptr *slots;
gboolean ready;
};
struct ril_modem {
GRilIoChannel *io;
const char *imei;
const char *imeisv;
const char *log_prefix;
const char *ecclist_file;
struct ofono_modem *ofono;
struct sailfish_cell_info *cell_info;
struct ril_radio *radio;
struct ril_data *data;
struct ril_network *network;
struct ril_sim_card *sim_card;
struct ril_sim_settings *sim_settings;
struct ril_cell_info *cell_info;
struct ril_slot_config config;
};
#define RIL_PLUGIN_SIGNAL_VOICE_IMSI (0x01)
#define RIL_PLUGIN_SIGNAL_DATA_IMSI (0x02)
#define RIL_PLUGIN_SIGNAL_VOICE_PATH (0x04)
#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x08)
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x10)
#define RIL_PLUGIN_SIGNAL_MMS_IMSI (0x20)
#define RIL_PLUGIN_SIGNAL_MMS_PATH (0x40)
#define RIL_PLUGIN_SIGNAL_READY (0x80)
typedef void (*ril_modem_cb_t)(struct ril_modem *modem, void *data);
typedef void (*ril_modem_online_cb_t)(struct ril_modem *modem, gboolean online,
void *data);
void ril_plugin_set_enabled_slots(struct ril_plugin *plugin, char **slots);
gboolean ril_plugin_set_mms_imsi(struct ril_plugin *plugin, const char *imsi);
void ril_plugin_set_default_voice_imsi(struct ril_plugin *plugin,
const char *imsi);
void ril_plugin_set_default_data_imsi(struct ril_plugin *plugin,
const char *imsi);
struct ril_oem_raw;
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *md,
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
const char *log_prefix);
void ril_oem_raw_free(struct ril_oem_raw *raw);
struct ril_sim_info_dbus;
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
struct ril_sim_info *info);
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus);
struct ril_cell_info_dbus;
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
struct ril_cell_info *info);
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus);
struct ril_plugin_dbus;
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin);
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus);
void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
gboolean clock);
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
gboolean present);
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,
struct ril_network *network, struct ril_sim_card *card,
struct ril_data *data, struct ril_sim_settings *settings,
struct ril_cell_info *cell_info);
const char *path, const char *imei, const char *imeisv,
const char *ecclist_file, const struct ril_slot_config *config,
struct ril_radio *radio, struct ril_network *network,
struct ril_sim_card *card, struct ril_data *data,
struct ril_sim_settings *settings,
struct sailfish_cell_info *cell_info);
void ril_modem_delete(struct ril_modem *modem);
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
void *data);
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
void *data);
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
@@ -144,7 +83,7 @@ void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
#define ril_modem_io(modem) ((modem)->io)
int ril_sim_app_type(struct ofono_sim *sim);
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
int ril_netreg_check_if_really_roaming(struct ofono_netreg *reg, gint status);
extern const struct ofono_call_barring_driver ril_call_barring_driver;
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;

View File

@@ -1,851 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include <ofono/log.h>
#include <ofono/dbus.h>
#include <gutil_strv.h>
#include <gutil_log.h>
#include <gdbus.h>
#include "ofono.h"
typedef void (*ril_plugin_dbus_append_fn)(DBusMessageIter *it,
struct ril_plugin_dbus *dbus);
typedef gboolean (*ril_plugin_dbus_slot_select_fn)
(const struct ril_slot_info *slot);
typedef const char *(*ril_plugin_dbus_slot_string_fn)
(const struct ril_slot_info *slot);
struct ril_plugin_dbus_request {
DBusMessage *msg;
ril_plugin_dbus_append_fn fn;
};
struct ril_plugin_dbus {
struct ril_plugin *plugin;
DBusConnection *conn;
gboolean block_imei_req;
GSList *blocked_imei_req;
guint mms_watch;
};
#define RIL_DBUS_PATH "/"
#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
#define RIL_DBUS_INTERFACE_VERSION (5)
#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED "DefaultVoiceSimChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED "DefaultDataSimChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED "DefaultVoiceModemChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED "DefaultDataModemChanged"
#define RIL_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
#define RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
#define RIL_DBUS_SIGNAL_READY_CHANGED "ReadyChanged"
#define RIL_DBUS_IMSI_AUTO "auto"
static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
{
return slot->enabled;
}
static gboolean ril_plugin_dbus_present(const struct ril_slot_info *slot)
{
return slot->sim_present;
}
static const char *ril_plugin_dbus_imei(const struct ril_slot_info *slot)
{
return slot->imei;
}
static void ril_plugin_dbus_append_path_array(DBusMessageIter *it,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn selector)
{
DBusMessageIter array;
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
while (*ptr) {
const struct ril_slot_info *slot = *ptr++;
if (!selector || selector(slot)) {
const char *path = slot->path;
dbus_message_iter_append_basic(&array,
DBUS_TYPE_OBJECT_PATH, &path);
}
}
dbus_message_iter_close_container(it, &array);
}
static void ril_plugin_dbus_append_string_array(DBusMessageIter *it,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_string_fn fn)
{
DBusMessageIter array;
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING, &array);
while (*ptr) {
const struct ril_slot_info *slot = *ptr++;
const char *str = fn(slot);
if (!str) str = "";
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &str);
}
dbus_message_iter_close_container(it, &array);
}
static void ril_plugin_dbus_append_boolean_array(DBusMessageIter *it,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn value)
{
DBusMessageIter array;
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
DBUS_TYPE_BOOLEAN_AS_STRING, &array);
while (*ptr) {
const struct ril_slot_info *slot = *ptr++;
dbus_bool_t b = value(slot);
dbus_message_iter_append_basic(&array, DBUS_TYPE_BOOLEAN, &b);
}
dbus_message_iter_close_container(it, &array);
}
static void ril_plugin_dbus_append_boolean(DBusMessageIter *it, dbus_bool_t b)
{
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &b);
}
static void ril_plugin_dbus_append_string(DBusMessageIter *it, const char *str)
{
if (!str) str = "";
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
}
static void ril_plugin_dbus_append_imsi(DBusMessageIter *it, const char *imsi)
{
if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &imsi);
}
static void ril_plugin_dbus_append_path(DBusMessageIter *it, const char *path)
{
if (!path) path = "";
/* It's DBUS_TYPE_STRING because DBUS_TYPE_OBJECT_PATH can't be empty */
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &path);
}
static void ril_plugin_dbus_message_append_path_array(DBusMessage *msg,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
{
DBusMessageIter iter;
dbus_message_iter_init_append(msg, &iter);
ril_plugin_dbus_append_path_array(&iter, dbus, fn);
}
static void ril_plugin_dbus_signal_path_array(struct ril_plugin_dbus *dbus,
const char *name, ril_plugin_dbus_slot_select_fn fn)
{
DBusMessage *signal = dbus_message_new_signal(RIL_DBUS_PATH,
RIL_DBUS_INTERFACE, name);
ril_plugin_dbus_message_append_path_array(signal, dbus, fn);
g_dbus_send_message(dbus->conn, signal);
}
static inline void ril_plugin_dbus_signal_imsi(struct ril_plugin_dbus *dbus,
const char *name, const char *imsi)
{
if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
name, DBUS_TYPE_STRING, &imsi, DBUS_TYPE_INVALID);
}
static inline void ril_plugin_dbus_signal_string(struct ril_plugin_dbus *dbus,
const char *name, const char *str)
{
if (!str) str = "";
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
name, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
}
static inline void ril_plugin_dbus_signal_boolean(struct ril_plugin_dbus *dbus,
const char *name, dbus_bool_t value)
{
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
name, DBUS_TYPE_BOOLEAN, &value, DBUS_TYPE_INVALID);
}
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask)
{
if (dbus) {
if (mask & RIL_PLUGIN_SIGNAL_VOICE_IMSI) {
ril_plugin_dbus_signal_imsi(dbus,
RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
dbus->plugin->default_voice_imsi);
}
if (mask & RIL_PLUGIN_SIGNAL_DATA_IMSI) {
ril_plugin_dbus_signal_imsi(dbus,
RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
dbus->plugin->default_data_imsi);
}
if (mask & RIL_PLUGIN_SIGNAL_MMS_IMSI) {
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
dbus->plugin->mms_imsi);
}
if (mask & RIL_PLUGIN_SIGNAL_ENABLED_SLOTS) {
ril_plugin_dbus_signal_path_array(dbus,
RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
ril_plugin_dbus_enabled);
}
if (mask & RIL_PLUGIN_SIGNAL_VOICE_PATH) {
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
dbus->plugin->default_voice_path);
}
if (mask & RIL_PLUGIN_SIGNAL_DATA_PATH) {
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
dbus->plugin->default_data_path);
}
if (mask & RIL_PLUGIN_SIGNAL_MMS_PATH) {
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
dbus->plugin->mms_path);
}
if (mask & RIL_PLUGIN_SIGNAL_READY) {
ril_plugin_dbus_signal_boolean(dbus,
RIL_DBUS_SIGNAL_READY_CHANGED,
dbus->plugin->ready);
}
}
}
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
gboolean present)
{
dbus_bool_t value = present;
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
DBUS_TYPE_INT32, &index,
DBUS_TYPE_BOOLEAN, &value,
DBUS_TYPE_INVALID);
}
static DBusMessage *ril_plugin_dbus_reply_with_path_array(DBusMessage *msg,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
ril_plugin_dbus_message_append_path_array(reply, dbus, fn);
return reply;
}
static DBusMessage *ril_plugin_dbus_reply(DBusMessage *msg,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_append_fn append)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
append(&iter, dbus);
return reply;
}
static void ril_plugin_dbus_unblock_request(gpointer data, gpointer user_data)
{
struct ril_plugin_dbus_request *req = data;
DBG("unblocking IMEI request %p", req);
__ofono_dbus_pending_reply(&req->msg, ril_plugin_dbus_reply(req->msg,
(struct ril_plugin_dbus *)user_data, req->fn));
g_free(req);
}
static void ril_plugin_dbus_cancel_request(gpointer data)
{
struct ril_plugin_dbus_request *req = data;
DBG("canceling IMEI request %p", req);
__ofono_dbus_pending_reply(&req->msg, __ofono_error_canceled(req->msg));
g_free(req);
}
void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
gboolean block)
{
dbus->block_imei_req = block;
if (!block && dbus->blocked_imei_req) {
g_slist_foreach(dbus->blocked_imei_req,
ril_plugin_dbus_unblock_request, dbus);
g_slist_free(dbus->blocked_imei_req);
dbus->blocked_imei_req = NULL;
}
}
static DBusMessage *ril_plugin_dbus_imei_reply(DBusMessage *msg,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_append_fn fn)
{
if (dbus->block_imei_req) {
struct ril_plugin_dbus_request *req =
g_new(struct ril_plugin_dbus_request, 1);
req->msg = dbus_message_ref(msg);
req->fn = fn;
dbus->blocked_imei_req = g_slist_append(dbus->blocked_imei_req,
req);
DBG("blocking IMEI request %p", req);
return NULL;
} else {
return ril_plugin_dbus_reply(msg, dbus, fn);
}
}
static void ril_plugin_dbus_append_version(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
dbus_int32_t version = RIL_DBUS_INTERFACE_VERSION;
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
}
static void ril_plugin_dbus_append_all(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_version(it, dbus);
ril_plugin_dbus_append_path_array(it, dbus, NULL);
ril_plugin_dbus_append_path_array(it, dbus, ril_plugin_dbus_enabled);
ril_plugin_dbus_append_imsi(it, dbus->plugin->default_data_imsi);
ril_plugin_dbus_append_imsi(it, dbus->plugin->default_voice_imsi);
ril_plugin_dbus_append_path(it, dbus->plugin->default_data_path);
ril_plugin_dbus_append_path(it, dbus->plugin->default_voice_path);
}
static void ril_plugin_dbus_append_all2(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all(it, dbus);
ril_plugin_dbus_append_boolean_array(it, dbus, ril_plugin_dbus_present);
}
static void ril_plugin_dbus_append_all3(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all2(it, dbus);
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
}
static void ril_plugin_dbus_append_all4(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all3(it, dbus);
ril_plugin_dbus_append_string(it, dbus->plugin->mms_imsi);
ril_plugin_dbus_append_path(it, dbus->plugin->mms_path);
}
static void ril_plugin_dbus_append_all5(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all4(it, dbus);
ril_plugin_dbus_append_boolean(it, dbus->plugin->ready);
}
static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all);
}
static DBusMessage *ril_plugin_dbus_get_all2(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all2);
}
static DBusMessage *ril_plugin_dbus_get_all3(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all3);
}
static DBusMessage *ril_plugin_dbus_get_all4(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all4);
}
static DBusMessage *ril_plugin_dbus_get_all5(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all5);
}
static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_version);
}
static DBusMessage *ril_plugin_dbus_get_available_modems(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_reply_with_path_array(msg,
(struct ril_plugin_dbus *)data, NULL);
}
static DBusMessage *ril_plugin_dbus_get_enabled_modems(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_reply_with_path_array(msg,
(struct ril_plugin_dbus *)data, ril_plugin_dbus_enabled);
}
static void ril_plugin_dbus_append_present_sims(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_boolean_array(it, dbus, ril_plugin_dbus_present);
}
static DBusMessage *ril_plugin_dbus_get_present_sims(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_present_sims);
}
static void ril_plugin_dbus_append_imei_array(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
}
static DBusMessage *ril_plugin_dbus_get_imei(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_imei_array);
}
static DBusMessage *ril_plugin_dbus_reply_with_string(DBusMessage *msg,
const char *str)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
ril_plugin_dbus_append_string(&iter, str);
return reply;
}
static DBusMessage *ril_plugin_dbus_reply_with_imsi(DBusMessage *msg,
const char *imsi)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
ril_plugin_dbus_append_imsi(&iter, imsi);
return reply;
}
static DBusMessage *ril_plugin_dbus_get_default_data_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_imsi(msg,
dbus->plugin->default_data_imsi);
}
static DBusMessage *ril_plugin_dbus_get_default_voice_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_imsi(msg,
dbus->plugin->default_voice_imsi);
}
static DBusMessage *ril_plugin_dbus_get_mms_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_string(msg, dbus->plugin->mms_imsi);
}
static DBusMessage *ril_plugin_dbus_reply_with_path(DBusMessage *msg,
const char *path)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
ril_plugin_dbus_append_path(&iter, path);
return reply;
}
static DBusMessage *ril_plugin_dbus_get_default_data_modem(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_path(msg,
dbus->plugin->default_data_path);
}
static DBusMessage *ril_plugin_dbus_get_default_voice_modem(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_path(msg,
dbus->plugin->default_voice_path);
}
static DBusMessage *ril_plugin_dbus_get_mms_modem(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_path(msg, dbus->plugin->mms_path);
}
static DBusMessage *ril_plugin_dbus_get_ready(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it;
dbus_message_iter_init_append(reply, &it);
ril_plugin_dbus_append_boolean(&it, dbus->plugin->ready);
return reply;
}
static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
DBusMessageIter iter;
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
char **paths = NULL;
DBusMessageIter array;
dbus_message_iter_recurse(&iter, &array);
while (dbus_message_iter_get_arg_type(&array) ==
DBUS_TYPE_OBJECT_PATH) {
DBusBasicValue value;
dbus_message_iter_get_basic(&array, &value);
paths = gutil_strv_add(paths, value.str);
dbus_message_iter_next(&array);
}
ril_plugin_set_enabled_slots(dbus->plugin, paths);
g_strfreev(paths);
return dbus_message_new_method_return(msg);
} else {
return __ofono_error_invalid_args(msg);
}
}
static DBusMessage *ril_plugin_dbus_set_imsi(struct ril_plugin_dbus *dbus,
DBusMessage *msg, void (*apply)(struct ril_plugin *plugin,
const char *imsi))
{
DBusMessageIter iter;
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
DBusBasicValue value;
const char *imsi;
dbus_message_iter_get_basic(&iter, &value);
imsi = value.str;
if (!g_strcmp0(imsi, RIL_DBUS_IMSI_AUTO)) imsi = NULL;
apply(dbus->plugin, imsi);
return dbus_message_new_method_return(msg);
} else {
return __ofono_error_invalid_args(msg);
}
}
static DBusMessage *ril_plugin_dbus_set_default_voice_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
GASSERT(conn == dbus->conn);
return ril_plugin_dbus_set_imsi(dbus, msg,
ril_plugin_set_default_voice_imsi);
}
static DBusMessage *ril_plugin_dbus_set_default_data_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
GASSERT(conn == dbus->conn);
return ril_plugin_dbus_set_imsi(dbus, msg,
ril_plugin_set_default_data_imsi);
}
static void ril_plugin_dbus_mms_disconnect(DBusConnection *conn, void *data)
{
struct ril_plugin_dbus *dbus = data;
dbus->mms_watch = 0;
if (dbus->plugin->mms_imsi) {
DBG("MMS client is gone");
ril_plugin_set_mms_imsi(dbus->plugin, NULL);
}
}
static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessageIter iter;
struct ril_plugin_dbus *dbus = data;
GASSERT(conn == dbus->conn);
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
DBusBasicValue value;
const char *imsi;
dbus_message_iter_get_basic(&iter, &value);
imsi = value.str;
/*
* MMS IMSI is not persistent and has to be eventually
* reset by the client or cleaned up if the client
* unexpectedly disappears.
*/
if (ril_plugin_set_mms_imsi(dbus->plugin, imsi)) {
/*
* Clear the previous MMS owner
*/
if (dbus->mms_watch) {
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
dbus->mms_watch = 0;
}
if (dbus->plugin->mms_imsi &&
dbus->plugin->mms_imsi[0]) {
/*
* This client becomes the owner
*/
DBG("Owner: %s", dbus_message_get_sender(msg));
dbus->mms_watch =
g_dbus_add_disconnect_watch(dbus->conn,
dbus_message_get_sender(msg),
ril_plugin_dbus_mms_disconnect,
dbus, NULL);
}
return ril_plugin_dbus_reply_with_string(msg,
dbus->plugin->mms_path);
} else {
return __ofono_error_not_available(msg);
}
} else {
return __ofono_error_invalid_args(msg);
}
}
/*
* The client can call GetInterfaceVersion followed by the appropriate
* GetAllx call to get all settings in two steps. Alternatively, it can
* call GetAll followed by GetAllx based on the interface version returned
* by GetAll. In either case, two D-Bus calls are required, unless the
* client is willing to make the assumption about the ofono version it's
* talking to.
*/
#define RIL_DBUS_GET_ALL_ARGS \
{"version", "i" }, \
{"availableModems", "ao" }, \
{"enabledModems", "ao" }, \
{"defaultDataSim", "s" }, \
{"defaultVoiceSim", "s" }, \
{"defaultDataModem", "s" }, \
{"defaultVoiceModem" , "s"}
#define RIL_DBUS_GET_ALL2_ARGS \
RIL_DBUS_GET_ALL_ARGS, \
{"presentSims" , "ab"}
#define RIL_DBUS_GET_ALL3_ARGS \
RIL_DBUS_GET_ALL2_ARGS, \
{"imei" , "as"}
#define RIL_DBUS_GET_ALL4_ARGS \
RIL_DBUS_GET_ALL3_ARGS, \
{"mmsSim", "s" }, \
{"mmsModem" , "s"}
#define RIL_DBUS_GET_ALL5_ARGS \
RIL_DBUS_GET_ALL4_ARGS, \
{"ready" , "b"}
static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
ril_plugin_dbus_get_all) },
{ GDBUS_METHOD("GetAll2",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL2_ARGS),
ril_plugin_dbus_get_all2) },
{ GDBUS_ASYNC_METHOD("GetAll3",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL3_ARGS),
ril_plugin_dbus_get_all3) },
{ GDBUS_ASYNC_METHOD("GetAll4",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL4_ARGS),
ril_plugin_dbus_get_all4) },
{ GDBUS_ASYNC_METHOD("GetAll5",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL5_ARGS),
ril_plugin_dbus_get_all5) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
ril_plugin_dbus_get_interface_version) },
{ GDBUS_METHOD("GetAvailableModems",
NULL, GDBUS_ARGS({ "modems", "ao" }),
ril_plugin_dbus_get_available_modems) },
{ GDBUS_METHOD("GetEnabledModems",
NULL, GDBUS_ARGS({ "modems", "ao" }),
ril_plugin_dbus_get_enabled_modems) },
{ GDBUS_METHOD("GetPresentSims",
NULL, GDBUS_ARGS({ "presentSims", "ab" }),
ril_plugin_dbus_get_present_sims) },
{ GDBUS_ASYNC_METHOD("GetIMEI",
NULL, GDBUS_ARGS({ "imei", "as" }),
ril_plugin_dbus_get_imei) },
{ GDBUS_METHOD("GetDefaultDataSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
ril_plugin_dbus_get_default_data_sim) },
{ GDBUS_METHOD("GetDefaultVoiceSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
ril_plugin_dbus_get_default_voice_sim) },
{ GDBUS_METHOD("GetMmsSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
ril_plugin_dbus_get_mms_sim) },
{ GDBUS_METHOD("GetDefaultDataModem",
NULL, GDBUS_ARGS({ "path", "s" }),
ril_plugin_dbus_get_default_data_modem) },
{ GDBUS_METHOD("GetDefaultVoiceModem",
NULL, GDBUS_ARGS({ "path", "s" }),
ril_plugin_dbus_get_default_voice_modem) },
{ GDBUS_METHOD("GetMmsModem",
NULL, GDBUS_ARGS({ "path", "s" }),
ril_plugin_dbus_get_mms_modem) },
{ GDBUS_METHOD("GetReady",
NULL, GDBUS_ARGS({ "ready", "b" }),
ril_plugin_dbus_get_ready) },
{ GDBUS_METHOD("SetEnabledModems",
GDBUS_ARGS({ "modems", "ao" }), NULL,
ril_plugin_dbus_set_enabled_modems) },
{ GDBUS_METHOD("SetDefaultDataSim",
GDBUS_ARGS({ "imsi", "s" }), NULL,
ril_plugin_dbus_set_default_data_sim) },
{ GDBUS_METHOD("SetDefaultVoiceSim",
GDBUS_ARGS({ "imsi", "s" }), NULL,
ril_plugin_dbus_set_default_voice_sim) },
{ GDBUS_METHOD("SetMmsSim",
GDBUS_ARGS({ "imsi", "s" }), NULL,
ril_plugin_dbus_set_mms_sim) },
{ }
};
static const GDBusSignalTable ril_plugin_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
GDBUS_ARGS({ "modems", "ao" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
GDBUS_ARGS({"index", "i" },
{"present" , "b"})) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_READY_CHANGED,
GDBUS_ARGS({ "ready", "b" })) },
{ }
};
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin)
{
struct ril_plugin_dbus *dbus = g_new0(struct ril_plugin_dbus, 1);
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
dbus->plugin = plugin;
if (g_dbus_register_interface(dbus->conn, RIL_DBUS_PATH,
RIL_DBUS_INTERFACE, ril_plugin_dbus_methods,
ril_plugin_dbus_signals, NULL, dbus, NULL)) {
return dbus;
} else {
ofono_error("RIL D-Bus register failed");
ril_plugin_dbus_free(dbus);
return NULL;
}
}
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus)
{
if (dbus) {
if (dbus->mms_watch) {
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
}
g_slist_free_full(dbus->blocked_imei_req,
ril_plugin_dbus_cancel_request);
g_dbus_unregister_interface(dbus->conn, RIL_DBUS_PATH,
RIL_DBUS_INTERFACE);
dbus_connection_unref(dbus->conn);
g_free(dbus);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -99,13 +99,14 @@ static inline void ril_radio_emit_signal(struct ril_radio *self,
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
{
struct ril_radio *self = user_data;
struct ril_radio *self = RIL_RADIO(user_data);
struct ril_radio_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
GASSERT(priv->retry_id);
priv->retry_id = 0;
ril_radio_submit_power_request(self, ril_radio_power_should_be_on(self));
ril_radio_submit_power_request(self,
ril_radio_power_should_be_on(self));
return G_SOURCE_REMOVE;
}
@@ -126,7 +127,7 @@ static void ril_radio_check_state(struct ril_radio *self)
struct ril_radio_priv *priv = self->priv;
if (!priv->pending_id) {
const gboolean should_be_on = ril_radio_power_should_be_on(self);
gboolean should_be_on = ril_radio_power_should_be_on(self);
if (ril_radio_state_on(self->priv->last_known_state) ==
should_be_on) {
@@ -157,7 +158,7 @@ static void ril_radio_check_state(struct ril_radio *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 = user_data;
struct ril_radio *self = RIL_RADIO(user_data);
struct ril_radio_priv *priv = self->priv;
GASSERT(priv->pending_id);
@@ -177,11 +178,17 @@ static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
{
/*
* RIL_REQUEST_RADIO_POWER
*
* "data" is int *
* ((int *)data)[0] is > 0 for "Radio On"
* ((int *)data)[0] is == 0 for "Radio Off"
*
* "response" is NULL
**/
GRilIoRequest *req = grilio_request_array_int32_new(1, on);
struct ril_radio_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, on); /* Radio ON=1, OFF=0 */
priv->next_state_valid = FALSE;
priv->next_state = on;
@@ -189,8 +196,10 @@ static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
ril_radio_cancel_retry(self);
GASSERT(!priv->pending_id);
grilio_request_set_blocking(req, TRUE);
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb, NULL, self);
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb,
NULL, self);
grilio_request_unref(req);
}
@@ -330,7 +339,7 @@ enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_radio *self = user_data;
struct ril_radio *self = RIL_RADIO(user_data);
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -44,6 +44,9 @@ void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
void ril_radio_remove_handlers(struct ril_radio *radio, gulong *ids, int n);
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
#define ril_radio_remove_all_handlers(r,ids) \
ril_radio_remove_handlers(r, ids, G_N_ELEMENTS(ids))
#endif /* RIL_RADIO_H */
/*

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -40,13 +40,6 @@
/* FID/path of SIM/USIM root directory */
#define ROOTMF "3F00"
/* RIL_Request* parameter counts */
#define GET_IMSI_NUM_PARAMS 1
#define ENTER_SIM_PIN_PARAMS 2
#define SET_FACILITY_LOCK_PARAMS 5
#define ENTER_SIM_PUK_PARAMS 3
#define CHANGE_SIM_PIN_PARAMS 3
/* P2 coding (modes) for READ RECORD and UPDATE RECORD (see TS 102.221) */
#define MODE_SELECTED (0x00) /* Currently selected EF */
#define MODE_CURRENT (0x04) /* P1='00' denotes the current record */
@@ -65,6 +58,13 @@
*
* The same applies to the app_type.
*/
enum ril_sim_card_event {
SIM_CARD_STATUS_EVENT,
SIM_CARD_APP_EVENT,
SIM_CARD_EVENT_COUNT
};
struct ril_sim {
GRilIoChannel *io;
GRilIoQueue *q;
@@ -76,7 +76,8 @@ struct ril_sim {
gboolean empty_pin_query_allowed;
gboolean inserted;
guint idle_id;
gulong card_status_id;
gulong card_event_id[SIM_CARD_EVENT_COUNT];
guint query_pin_retries_id;
const char *log_prefix;
char *allocated_log_prefix;
@@ -85,6 +86,7 @@ struct ril_sim {
ofono_sim_passwd_cb_t query_passwd_state_cb;
void *query_passwd_state_cb_data;
guint query_passwd_state_timeout_id;
gulong query_passwd_state_sim_status_refresh_id;
};
struct ril_sim_io_response {
@@ -100,11 +102,11 @@ struct ril_sim_cbd {
ofono_sim_read_cb_t read;
ofono_sim_write_cb_t write;
ofono_sim_imsi_cb_t imsi;
ofono_sim_pin_retries_cb_t retries;
ofono_query_facility_lock_cb_t query_facility_lock;
gpointer ptr;
} cb;
gpointer data;
guint req_id;
};
struct ril_sim_pin_cbd {
@@ -119,6 +121,49 @@ struct ril_sim_pin_cbd {
gulong card_status_id;
};
struct ril_sim_retry_query_cbd {
struct ril_sim *sd;
ofono_sim_pin_retries_cb_t cb;
void *data;
guint query_index;
};
struct ril_sim_retry_query {
const char *name;
enum ofono_sim_password_type passwd_type;
guint req_code;
GRilIoRequest *(*new_req)(struct ril_sim *sd);
};
static GRilIoRequest *ril_sim_empty_sim_pin_req(struct ril_sim *sd);
static GRilIoRequest *ril_sim_empty_sim_puk_req(struct ril_sim *sd);
static void ril_sim_query_retry_count_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data);
static const struct ril_sim_retry_query ril_sim_retry_query_types[] = {
{
"pin",
OFONO_SIM_PASSWORD_SIM_PIN,
RIL_REQUEST_ENTER_SIM_PIN,
ril_sim_empty_sim_pin_req
},{
"pin2",
OFONO_SIM_PASSWORD_SIM_PIN2,
RIL_REQUEST_ENTER_SIM_PIN2,
ril_sim_empty_sim_pin_req
},{
"puk",
OFONO_SIM_PASSWORD_SIM_PUK,
RIL_REQUEST_ENTER_SIM_PUK,
ril_sim_empty_sim_puk_req
},{
"puk2",
OFONO_SIM_PASSWORD_SIM_PUK2,
RIL_REQUEST_ENTER_SIM_PUK2,
ril_sim_empty_sim_puk_req
}
};
#define DBG_(sd,fmt,args...) DBG("%s" fmt, (sd)->log_prefix, ##args)
#define ril_sim_cbd_free g_free
@@ -378,6 +423,7 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
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);
@@ -438,8 +484,10 @@ static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
grilio_request_append_utf8(req, NULL); /* pin2; only for writes */
grilio_request_append_utf8(req, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_SIM_IO,
cb, ril_sim_cbd_free, cbd);
grilio_request_set_blocking(req, TRUE);
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SIM_IO, cb, ril_sim_cbd_free, cbd);
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
grilio_request_unref(req);
}
@@ -461,6 +509,8 @@ static void ril_sim_read_cb(GRilIoChannel *io, int status,
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) {
cb(ril_error_ok(&err), res->data, res->data_len, cbd->data);
@@ -514,6 +564,8 @@ static void ril_sim_write_cb(GRilIoChannel *io, int status,
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) {
cb(ril_error_ok(&err), cbd->data);
@@ -574,6 +626,8 @@ static void ril_sim_get_imsi_cb(GRilIoChannel *io, int status,
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;
@@ -598,11 +652,11 @@ 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);
GRilIoRequest *req = grilio_request_sized_new(60);
const char *app_id = ril_sim_app_id(sd);
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
GRilIoRequest *req = grilio_request_array_utf8_new(1, app_id);
DBG_(sd, "%s", ril_sim_app_id(sd));
grilio_request_append_int32(req, GET_IMSI_NUM_PARAMS);
grilio_request_append_utf8(req, ril_sim_app_id(sd));
DBG_(sd, "%s", app_id);
/*
* If we fail the .read_imsi call, ofono gets into "Unable to
@@ -610,9 +664,11 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
* on failure.
*/
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_GET_IMSI,
ril_sim_get_imsi_cb, ril_sim_cbd_free,
ril_sim_cbd_new(sd, cb, data));
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);
grilio_request_unref(req);
}
@@ -691,6 +747,12 @@ static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
sd->query_passwd_state_timeout_id = 0;
}
if (sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
sd->query_passwd_state_sim_status_refresh_id = 0;
}
if (sd->query_passwd_state_cb) {
ofono_sim_passwd_cb_t cb = sd->query_passwd_state_cb;
void *data = sd->query_passwd_state_cb_data;
@@ -709,6 +771,34 @@ static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
}
}
static void ril_sim_check_perm_lock(struct ril_sim *sd)
{
struct ril_sim_card *sc = sd->card;
/*
* Zero number of retries in the PUK state indicates to the ofono
* client that the card is permanently locked. This is different
* from the case when the number of retries is negative (which
* means that PUK is required but the number of remaining attempts
* is not available).
*/
if (sc->app && sc->app->app_state == RIL_APPSTATE_PUK &&
sc->app->pin1_state == RIL_PINSTATE_ENABLED_PERM_BLOCKED) {
/*
* It makes no sense for RIL to return non-zero number of
* remaining attempts in PERM_LOCKED state. So when we get
* here, the number of retries has to be negative (unknown)
* or zero. Otherwise, something must be broken.
*/
GASSERT(sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] <= 0);
if (sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] < 0) {
sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = 0;
DBG_(sd, "SIM card is locked");
}
}
}
static void ril_sim_invalidate_passwd_state(struct ril_sim *sd)
{
guint i;
@@ -718,10 +808,16 @@ static void ril_sim_invalidate_passwd_state(struct ril_sim *sd)
sd->retries[i] = -1;
}
ril_sim_check_perm_lock(sd);
ril_sim_finish_passwd_state_query(sd, OFONO_SIM_PASSWORD_INVALID);
}
static void ril_sim_status_cb(struct ril_sim_card *sc, void *user_data)
static void ril_sim_app_changed_cb(struct ril_sim_card *sc, void *user_data)
{
ril_sim_check_perm_lock((struct ril_sim *)user_data);
}
static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
{
struct ril_sim *sd = user_data;
@@ -730,6 +826,7 @@ static void ril_sim_status_cb(struct ril_sim_card *sc, void *user_data)
if (sc->app) {
enum ofono_sim_password_type ps;
ril_sim_check_perm_lock(sd);
if (!sd->inserted) {
sd->inserted = TRUE;
ofono_info("SIM card OK");
@@ -764,14 +861,28 @@ static int ril_sim_parse_retry_count(const void *data, guint len)
return retry_count;
}
static GRilIoRequest *ril_sim_enter_sim_req(struct ril_sim *sd, const char *pw)
static GRilIoRequest *ril_sim_enter_sim_pin_req(struct ril_sim *sd,
const char *pin)
{
const char *app_id = ril_sim_app_id(sd);
if (app_id) {
GRilIoRequest *req = grilio_request_new();
grilio_request_append_int32(req, ENTER_SIM_PIN_PARAMS);
grilio_request_append_utf8(req, pw);
grilio_request_append_utf8(req, app_id);
GRilIoRequest *req = grilio_request_array_utf8_new(2,
pin, app_id);
grilio_request_set_blocking(req, TRUE);
return req;
}
return NULL;
}
static GRilIoRequest *ril_sim_enter_sim_puk_req(struct ril_sim *sd,
const char *puk, const char *pin)
{
const char *app_id = ril_sim_app_id(sd);
if (app_id) {
GRilIoRequest *req = grilio_request_array_utf8_new(3,
puk, pin, app_id);
grilio_request_set_blocking(req, TRUE);
return req;
}
return NULL;
@@ -781,63 +892,90 @@ static GRilIoRequest *ril_sim_enter_sim_req(struct ril_sim *sd, const char *pw)
* Some RIL implementations allow to query the retry count
* by sending the empty pin in any state.
*/
static void ril_sim_query_pin2_retries_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
static GRilIoRequest *ril_sim_empty_sim_pin_req(struct ril_sim *sd)
{
struct ril_sim_cbd *cbd = user_data;
struct ril_sim *sd = cbd->sd;
ofono_sim_pin_retries_cb_t cb = cbd->cb.retries;
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
const int retry_count = ril_sim_parse_retry_count(data, len);
DBG_(sd, "pin2 retry_count=%d", retry_count);
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = retry_count;
} else {
ofono_error("pin2 retry query is not supported");
sd->empty_pin_query_allowed = FALSE;
}
cb(ril_error_ok(&error), sd->retries, cbd->data);
return ril_sim_enter_sim_pin_req(sd, "");
}
static gboolean ril_sim_query_pin2_retry_count(struct ril_sim *sd,
static GRilIoRequest *ril_sim_empty_sim_puk_req(struct ril_sim *sd)
{
return ril_sim_enter_sim_puk_req(sd, "", "");
}
static struct ril_sim_retry_query_cbd *ril_sim_retry_query_cbd_new(
struct ril_sim *sd, guint query_index,
ofono_sim_pin_retries_cb_t cb, void *data)
{
if (sd->empty_pin_query_allowed &&
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN2] < 0) {
GRilIoRequest *req = ril_sim_enter_sim_req(sd, "");
if (req) {
DBG_(sd, "querying pin2 retry count...");
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PIN2,
ril_sim_query_pin2_retries_cb,
ril_sim_cbd_free,
ril_sim_cbd_new(sd, cb, data));
grilio_request_unref(req);
return TRUE;
}
}
return FALSE;
struct ril_sim_retry_query_cbd *cbd =
g_new(struct ril_sim_retry_query_cbd, 1);
cbd->sd = sd;
cbd->cb = cb;
cbd->data = data;
cbd->query_index = query_index;
return cbd;
}
static void ril_sim_query_pin_retries_cb(GRilIoChannel *io, int status,
static gboolean ril_sim_query_retry_count(struct ril_sim *sd,
guint start_index, ofono_sim_pin_retries_cb_t cb, void *data)
{
guint id = 0;
if (sd->empty_pin_query_allowed) {
guint i = start_index;
/* Find the first unknown retry count that we can query. */
while (i < G_N_ELEMENTS(ril_sim_retry_query_types)) {
const struct ril_sim_retry_query *query =
ril_sim_retry_query_types + i;
if (sd->retries[query->passwd_type] < 0) {
GRilIoRequest *req = query->new_req(sd);
if (req) {
DBG_(sd, "querying %s retry count...",
query->name);
id = grilio_queue_send_request_full(
sd->q, req, query->req_code,
ril_sim_query_retry_count_cb,
g_free,
ril_sim_retry_query_cbd_new(
sd, i, cb, data));
grilio_request_unref(req);
}
break;
}
i++;
}
}
return id;
}
static void ril_sim_query_retry_count_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd *cbd = user_data;
struct ril_sim_retry_query_cbd *cbd = user_data;
struct ril_sim *sd = cbd->sd;
ofono_sim_pin_retries_cb_t cb = cbd->cb.retries;
struct ofono_error error;
GASSERT(sd->query_pin_retries_id);
sd->query_pin_retries_id = 0;
if (status == RIL_E_SUCCESS) {
const int retry_count = ril_sim_parse_retry_count(data, len);
DBG_(sd, "pin retry_count=%d", retry_count);
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] = retry_count;
if (ril_sim_query_pin2_retry_count(sd, cb, cbd->data)) {
/*
* ril_sim_query_pin2_retries_cb will invoke
* the completion callback
*/
const struct ril_sim_retry_query *query =
ril_sim_retry_query_types + cbd->query_index;
DBG_(sd, "%s retry_count=%d", query->name, retry_count);
sd->retries[query->passwd_type] = retry_count;
/* Submit the next request */
if ((sd->query_pin_retries_id =
ril_sim_query_retry_count(sd, cbd->query_index + 1,
cbd->cb, cbd->data)) != 0) {
/* The next request is pending */
return;
}
} else {
@@ -845,43 +983,32 @@ static void ril_sim_query_pin_retries_cb(GRilIoChannel *io, int status,
sd->empty_pin_query_allowed = FALSE;
}
cb(ril_error_ok(&error), sd->retries, cbd->data);
}
static gboolean ril_sim_query_pin_retry_count(struct ril_sim *sd,
ofono_sim_pin_retries_cb_t cb, void *data)
{
if (sd->empty_pin_query_allowed &&
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] < 0) {
GRilIoRequest *req = ril_sim_enter_sim_req(sd, "");
if (req) {
DBG_(sd, "querying pin retry count...");
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PIN,
ril_sim_query_pin_retries_cb,
ril_sim_cbd_free,
ril_sim_cbd_new(sd, cb, data));
grilio_request_unref(req);
return TRUE;
}
}
return FALSE;
cbd->cb(ril_error_ok(&error), sd->retries, cbd->data);
}
static void ril_sim_query_pin_retries(struct ofono_sim *sim,
ofono_sim_pin_retries_cb_t cb, void *data)
{
struct ofono_error error;
struct ril_sim *sd = ril_sim_get_data(sim);
DBG_(sd, "");
if (ril_sim_query_pin_retry_count(sd, cb, data) ||
ril_sim_query_pin2_retry_count(sd, cb, data)) {
/* Wait for completion of PIN and then PIN2 query */
return;
}
grilio_queue_cancel_request(sd->q, sd->query_pin_retries_id, FALSE);
sd->query_pin_retries_id = ril_sim_query_retry_count(sd, 0, cb, data);
if (!sd->query_pin_retries_id) {
struct ofono_error error;
cb(ril_error_ok(&error), sd->retries, data);
/* Nothing to wait for */
cb(ril_error_ok(&error), sd->retries, data);
}
}
static void ril_sim_query_passwd_state_complete_cb(struct ril_sim_card *sc,
void *user_data)
{
struct ril_sim *sd = user_data;
GASSERT(sd->query_passwd_state_sim_status_refresh_id);
ril_sim_finish_passwd_state_query(sd, ril_sim_passwd_state(sd));
}
static gboolean ril_sim_query_passwd_state_timeout_cb(gpointer user_data)
@@ -899,29 +1026,41 @@ static void ril_sim_query_passwd_state(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
enum ofono_sim_password_type passwd_state = ril_sim_passwd_state(sd);
struct ofono_error error;
if (sd->query_passwd_state_timeout_id) {
g_source_remove(sd->query_passwd_state_timeout_id);
sd->query_passwd_state_timeout_id = 0;
}
if (passwd_state != OFONO_SIM_PASSWORD_INVALID) {
DBG_(sd, "%d", passwd_state);
sd->query_passwd_state_cb = NULL;
sd->query_passwd_state_cb_data = NULL;
sd->ofono_passwd_state = passwd_state;
cb(ril_error_ok(&error), passwd_state, data);
if (!sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
sd->query_passwd_state_sim_status_refresh_id = 0;
}
/* Always request fresh status, just in case. */
ril_sim_card_request_status(sd->card);
sd->query_passwd_state_cb = cb;
sd->query_passwd_state_cb_data = data;
if (ril_sim_passwd_state(sd) != OFONO_SIM_PASSWORD_INVALID) {
/* Just wait for GET_SIM_STATUS completion */
DBG_(sd, "waiting for SIM status query to complete");
sd->query_passwd_state_sim_status_refresh_id =
ril_sim_card_add_status_received_handler(sd->card,
ril_sim_query_passwd_state_complete_cb, sd);
} else {
/* Wait for the state to change */
DBG_(sd, "waiting for the SIM state to change");
sd->query_passwd_state_cb = cb;
sd->query_passwd_state_cb_data = data;
sd->query_passwd_state_timeout_id =
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
ril_sim_query_passwd_state_timeout_cb, sd);
}
/*
* We still need to complete the request somehow, even if
* GET_STATUS never completes or SIM status never changes.
*/
sd->query_passwd_state_timeout_id =
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
ril_sim_query_passwd_state_timeout_cb, sd);
}
static gboolean ril_sim_pin_change_state_timeout_cb(gpointer user_data)
@@ -971,20 +1110,30 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
struct ril_sim_pin_cbd *cbd = user_data;
struct ril_sim *sd = cbd->sd;
const int retry_count = ril_sim_parse_retry_count(data, len);
enum ofono_sim_password_type type = cbd->passwd_type;
DBG_(sd, "result=%d passwd_type=%d retry_count=%d",
ril_status, cbd->passwd_type, retry_count);
if (ril_status == RIL_E_SUCCESS && retry_count == 0 &&
sd->empty_pin_query_allowed &&
(cbd->passwd_type == OFONO_SIM_PASSWORD_SIM_PIN ||
cbd->passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)) {
/* Will query it */
sd->retries[cbd->passwd_type] = -1;
if (ril_status == RIL_E_SUCCESS && retry_count == 0) {
enum ofono_sim_password_type associated_pin =
__ofono_sim_puk2pin(type);
/*
* If PIN/PUK request has succeeded, zero retry count
* makes no sense, we have to assume that it's unknown.
* If it can be queried, it will be queried later. If
* it can't be queried it will remain unknown.
*/
sd->retries[type] = -1;
if (associated_pin != OFONO_SIM_PASSWORD_INVALID) {
/* Successful PUK requests affect PIN retry count */
sd->retries[associated_pin] = -1;
}
} else {
sd->retries[cbd->passwd_type] = retry_count;
sd->retries[type] = retry_count;
}
ril_sim_check_perm_lock(sd);
cbd->ril_status = ril_status;
if (cbd->card_status_id && (!cbd->state_event_count ||
ril_sim_app_in_transient_state(sd))) {
@@ -1014,6 +1163,13 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
} else {
cbd->cb(ril_error_failure(&error), cbd->data);
}
/* To avoid assert in ril_sim_pin_req_done: */
if (cbd->card_status_id) {
ril_sim_card_remove_handler(cbd->card,
cbd->card_status_id);
cbd->card_status_id = 0;
}
}
}
@@ -1021,18 +1177,21 @@ static void ril_sim_pin_send(struct ofono_sim *sim, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
GRilIoRequest *req = grilio_request_new();
GRilIoRequest *req = ril_sim_enter_sim_pin_req(sd, passwd);
grilio_request_append_int32(req, ENTER_SIM_PIN_PARAMS);
grilio_request_append_utf8(req, passwd);
grilio_request_append_utf8(req, ril_sim_app_id(sd));
if (req) {
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PIN, ril_sim_pin_change_state_cb,
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
OFONO_SIM_PASSWORD_SIM_PIN, TRUE, cb, data));
grilio_request_unref(req);
} else {
struct ofono_error error;
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PIN,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PIN,
TRUE, cb, data));
grilio_request_unref(req);
DBG_(sd, "sorry");
cb(ril_error_failure(&error), data);
}
}
static guint ril_perso_change_state(struct ofono_sim *sim,
@@ -1100,26 +1259,23 @@ 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);
struct ofono_error error;
const char *app_id = ril_sim_app_id(sd);
const char *type_str = ril_sim_facility_code(passwd_type);
struct ofono_error error;
guint id = 0;
DBG_(sd, "%d,%s,%d,%s,0,aid=%s", passwd_type, type_str, enable, passwd,
ril_sim_app_id(sd));
DBG_(sd, "%d,%s,%d,%s,0,aid=%s", passwd_type, type_str,
enable, passwd, app_id);
if (passwd_type == OFONO_SIM_PASSWORD_PHNET_PIN) {
id = ril_perso_change_state(sim, passwd_type, enable, passwd,
cb, data);
} else if (type_str) {
GRilIoRequest *req = grilio_request_new();
grilio_request_append_int32(req, SET_FACILITY_LOCK_PARAMS);
grilio_request_append_utf8(req, type_str);
grilio_request_append_utf8(req, enable ?
RIL_FACILITY_LOCK : RIL_FACILITY_UNLOCK);
grilio_request_append_utf8(req, passwd);
grilio_request_append_utf8(req, "0"); /* class */
grilio_request_append_utf8(req, ril_sim_app_id(sd));
GRilIoRequest *req = grilio_request_array_utf8_new(5, type_str,
enable ? RIL_FACILITY_LOCK : RIL_FACILITY_UNLOCK,
passwd, "0" /* class */, app_id);
grilio_request_set_blocking(req, TRUE);
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,
@@ -1137,19 +1293,22 @@ static void ril_sim_pin_send_puk(struct ofono_sim *sim,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
GRilIoRequest *req = grilio_request_sized_new(60);
GRilIoRequest *req = ril_sim_enter_sim_puk_req(sd, puk, passwd);
grilio_request_append_int32(req, ENTER_SIM_PUK_PARAMS);
grilio_request_append_utf8(req, puk);
grilio_request_append_utf8(req, passwd);
grilio_request_append_utf8(req, ril_sim_app_id(sd));
if (req) {
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd,
ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PUK, ril_sim_pin_change_state_cb,
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
OFONO_SIM_PASSWORD_SIM_PUK, TRUE, cb, data));
grilio_request_unref(req);
} else {
struct ofono_error error;
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PUK,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PUK,
TRUE, cb, data));
grilio_request_unref(req);
DBG_(sd, "sorry");
cb(ril_error_failure(&error), data);
}
}
static void ril_sim_change_passwd(struct ofono_sim *sim,
@@ -1158,15 +1317,12 @@ 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);
GRilIoRequest *req = grilio_request_sized_new(60);
const char *app_id = ril_sim_app_id(sd);
GRilIoRequest *req = grilio_request_array_utf8_new(3,
old_passwd, new_passwd, app_id);
grilio_request_append_int32(req, CHANGE_SIM_PIN_PARAMS);
grilio_request_append_utf8(req, old_passwd);
grilio_request_append_utf8(req, new_passwd);
grilio_request_append_utf8(req, ril_sim_app_id(sd));
DBG_(sd, "old=%s,new=%s,aid=%s", old_passwd, new_passwd,
ril_sim_app_id(sd));
DBG_(sd, "old=%s,new=%s,aid=%s", old_passwd, new_passwd, app_id);
grilio_request_set_blocking(req, TRUE);
grilio_queue_send_request_full(sd->q, req,
(passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2) ?
RIL_REQUEST_CHANGE_SIM_PIN2 : RIL_REQUEST_CHANGE_SIM_PIN,
@@ -1182,6 +1338,8 @@ static void ril_sim_query_facility_lock_cb(GRilIoChannel *io, int status,
struct ril_sim_cbd *cbd = user_data;
ofono_query_facility_lock_cb_t cb = cbd->cb.query_facility_lock;
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
if (status == RIL_E_SUCCESS) {
int locked = 0;
GRilIoParser rilp;
@@ -1203,18 +1361,16 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
ofono_query_facility_lock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
GRilIoRequest *req = grilio_request_new();
const char *type_str = ril_sim_facility_code(type);
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
GRilIoRequest *req = grilio_request_array_utf8_new(4,
type_str, "", "0" /* class */, ril_sim_app_id(sd));
DBG_(sd, "%s", type_str);
grilio_request_append_int32(req, 4);
grilio_request_append_utf8(req, type_str);
grilio_request_append_utf8(req, "");
grilio_request_append_utf8(req, "0"); /* class */
grilio_request_append_utf8(req, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req,
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, ril_sim_cbd_new(sd, cb, data));
ril_sim_cbd_free, cbd);
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
grilio_request_unref(req);
}
@@ -1229,11 +1385,15 @@ static gboolean ril_sim_register(gpointer user)
ofono_sim_register(sd->sim);
/* Register for change notifications */
sd->card_status_id = ril_sim_card_add_status_changed_handler(sd->card,
ril_sim_status_cb, sd);
sd->card_event_id[SIM_CARD_STATUS_EVENT] =
ril_sim_card_add_status_changed_handler(sd->card,
ril_sim_status_changed_cb, sd);
sd->card_event_id[SIM_CARD_APP_EVENT] =
ril_sim_card_add_app_changed_handler(sd->card,
ril_sim_app_changed_cb, sd);
/* Check the current state */
ril_sim_status_cb(sd->card, sd);
ril_sim_status_changed_cb(sd->card, sd);
return FALSE;
}
@@ -1280,7 +1440,13 @@ static void ril_sim_remove(struct ofono_sim *sim)
g_source_remove(sd->query_passwd_state_timeout_id);
}
ril_sim_card_remove_handler(sd->card, sd->card_status_id);
if (sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
}
ril_sim_card_remove_handlers(sd->card, sd->card_event_id,
G_N_ELEMENTS(sd->card_event_id));
ril_sim_card_unref(sd->card);
grilio_channel_unref(sd->io);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,15 @@
#include <gutil_misc.h>
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
/* SIM I/O idle timeout is measured in the number of idle loops.
* When active SIM I/O is going on, the idle loop count very rarely
* exceeds 1 between the requests, so 10 is more than enough. Idle
* loop is actually more accurate criteria than a timeout because
* it doesn't depend that much on the system load. */
#define SIM_IO_IDLE_LOOPS (10)
typedef GObjectClass RilSimCardClass;
typedef struct ril_sim_card RilSimCard;
@@ -38,7 +47,11 @@ struct ril_sim_card_priv {
GRilIoQueue *q;
int flags;
guint status_req_id;
guint sub_req_id;
gulong event_id[EVENT_COUNT];
guint sim_io_idle_id;
guint sim_io_idle_count;
GHashTable* sim_io_pending;
};
enum ril_sim_card_signal {
@@ -46,13 +59,15 @@ enum ril_sim_card_signal {
SIGNAL_STATUS_CHANGED,
SIGNAL_STATE_CHANGED,
SIGNAL_APP_CHANGED,
SIGNAL_SIM_IO_ACTIVE_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
#define SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME "ril-simcard-sim-io-active-changed"
static guint ril_sim_card_signals[SIGNAL_COUNT] = { 0 };
@@ -61,11 +76,16 @@ G_DEFINE_TYPE(RilSimCard, ril_sim_card, G_TYPE_OBJECT)
#define RIL_SIMCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_SIMCARD_TYPE, RilSimCard))
#define NEW_SIGNAL(klass,name) NEW_SIGNAL_(klass,name##_CHANGED)
#define NEW_SIGNAL_(klass,name) \
ril_sim_card_signals[SIGNAL_##name] = \
g_signal_new(SIGNAL_##name##_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
#define RIL_SIMCARD_STATE_CHANGED (0x01)
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
static void ril_sim_card_request_status(struct ril_sim_card *self);
static gboolean ril_sim_card_app_equal(const struct ril_sim_card_app *a1,
const struct ril_sim_card_app *a2)
{
@@ -137,22 +157,65 @@ static void ril_sim_card_status_free(struct ril_sim_card_status *status)
}
}
static void ril_sim_card_subscribe(struct ril_sim_card *self,
int app_index, int sub_status)
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
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
* removed from the list of pending requests) */
grilio_channel_drop_request(priv->io, priv->sub_req_id);
priv->sub_req_id = 0;
}
grilio_queue_transaction_finish(priv->q);
}
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
const void* data, guint len, void* user_data)
{
struct ril_sim_card *self = RIL_SIMCARD(user_data);
struct ril_sim_card_priv *priv = self->priv;
GASSERT(status == GRILIO_STATUS_OK);
GASSERT(priv->sub_req_id);
priv->sub_req_id = 0;
DBG("UICC subscription OK for slot %u", self->slot);
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)
{
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_status);
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_action);
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_status);
grilio_queue_send_request(priv->q, req, (priv->io->ril_version <= 9 &&
grilio_request_append_int32(req, sub_action);
grilio_request_set_retry(req, 0, -1);
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
code = (priv->io->ril_version <= 9 &&
(priv->flags & RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND)) ?
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
RIL_REQUEST_SET_UICC_SUBSCRIPTION);
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
RIL_REQUEST_SET_UICC_SUBSCRIPTION;
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
* removed from the list of pending requests) */
grilio_channel_drop_request(priv->io, priv->sub_req_id);
}
/* Don't allow any requests other that GET_SIM_STATUS until
* we are done with the subscription */
grilio_queue_transaction_start(priv->q);
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
req, code, ril_sim_card_subscribe_cb, NULL, self);
grilio_request_unref(req);
}
@@ -185,14 +248,17 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
if (status->gsm_umts_index >= 0 &&
status->gsm_umts_index < status->num_apps) {
app_index = status->gsm_umts_index;
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, 1);
ril_sim_card_subscribe(self, app_index,
RIL_UICC_SUBSCRIPTION_ACTIVATE);
}
}
} else {
app_index = -1;
ril_sim_card_subscription_done(self);
}
if (app_index >= 0 &&
@@ -203,8 +269,8 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
}
if (!ril_sim_card_app_equal(old_app, self->app)) {
g_signal_emit(self,
ril_sim_card_signals[SIGNAL_APP_CHANGED], 0);
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_APP_CHANGED], 0);
}
}
@@ -218,23 +284,23 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
self->status = status;
ril_sim_card_update_app(self);
g_signal_emit(self, ril_sim_card_signals[
SIGNAL_STATUS_RECEIVED], 0);
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_STATUS_RECEIVED], 0);
if (diff & RIL_SIMCARD_STATUS_CHANGED) {
DBG("status changed");
g_signal_emit(self, ril_sim_card_signals[
SIGNAL_STATUS_CHANGED], 0);
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_STATUS_CHANGED], 0);
}
if (diff & RIL_SIMCARD_STATE_CHANGED) {
DBG("state changed");
g_signal_emit(self, ril_sim_card_signals[
SIGNAL_STATE_CHANGED], 0);
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_STATE_CHANGED], 0);
}
ril_sim_card_status_free(old_status);
} else {
ril_sim_card_status_free(status);
g_signal_emit(self, ril_sim_card_signals[
SIGNAL_STATUS_RECEIVED], 0);
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_STATUS_RECEIVED], 0);
}
}
@@ -317,7 +383,8 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
status->num_apps = num_apps;
if (num_apps > 0) {
status->apps = g_new0(struct ril_sim_card_app, num_apps);
status->apps =
g_new0(struct ril_sim_card_app, num_apps);
}
for (i = 0; i < num_apps; i++) {
@@ -338,6 +405,7 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
}
if (i == num_apps) {
GASSERT(grilio_parser_at_end(&rilp));
return status;
} else {
ril_sim_card_status_free(status);
@@ -349,7 +417,7 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_sim_card *self = user_data;
struct ril_sim_card *self = RIL_SIMCARD(user_data);
struct ril_sim_card_priv *priv = self->priv;
GASSERT(priv->status_req_id);
@@ -365,28 +433,105 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
}
}
static void ril_sim_card_request_status(struct ril_sim_card *self)
void ril_sim_card_request_status(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
if (G_LIKELY(self)) {
struct ril_sim_card_priv *priv = self->priv;
if (priv->status_req_id) {
/* Retry right away, don't wait for retry timeout to expire */
grilio_channel_retry_request(priv->io, priv->status_req_id);
} else {
GRilIoRequest* req = grilio_request_new();
if (priv->status_req_id) {
/* Retry right away, don't wait for retry
* timeout to expire */
grilio_channel_retry_request(priv->io,
priv->status_req_id);
} else {
GRilIoRequest* req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
priv->status_req_id = grilio_queue_send_request_full(priv->q,
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
priv->status_req_id =
grilio_queue_send_request_full(priv->q,
req, RIL_REQUEST_GET_SIM_STATUS,
ril_sim_card_status_cb, NULL, self);
grilio_request_unref(req);
grilio_request_unref(req);
}
}
}
static void ril_sim_card_update_sim_io_active(struct ril_sim_card *self)
{
/* SIM I/O is considered active for certain period of time after
* the last request has completed. That's because SIM_IO requests
* are usually submitted in large quantities and quick succession.
* Some RILs don't like being bothered while they are doing SIM I/O
* and some time after that too. That sucks but what else can we
* do about it? */
struct ril_sim_card_priv *priv = self->priv;
const gboolean active = priv->sim_io_idle_id ||
g_hash_table_size(priv->sim_io_pending);
if (self->sim_io_active != active) {
self->sim_io_active = active;
DBG("SIM I/O for slot %u is %sactive", self->slot,
active ? "" : "in");
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_SIM_IO_ACTIVE_CHANGED], 0);
}
}
void ril_sim_card_sim_io_started(struct ril_sim_card *self, guint id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
struct ril_sim_card_priv *priv = self->priv;
gpointer key = GINT_TO_POINTER(id);
g_hash_table_insert(priv->sim_io_pending, key, key);
if (priv->sim_io_idle_id) {
g_source_remove(priv->sim_io_idle_id);
priv->sim_io_idle_id = 0;
priv->sim_io_idle_count = 0;
}
ril_sim_card_update_sim_io_active(self);
}
}
static gboolean ril_sim_card_sim_io_idle_cb(gpointer user_data)
{
struct ril_sim_card *self = RIL_SIMCARD(user_data);
struct ril_sim_card_priv *priv = self->priv;
if (++(priv->sim_io_idle_count) >= SIM_IO_IDLE_LOOPS) {
priv->sim_io_idle_id = 0;
priv->sim_io_idle_count = 0;
ril_sim_card_update_sim_io_active(self);
return G_SOURCE_REMOVE;
} else {
return G_SOURCE_CONTINUE;
}
}
void ril_sim_card_sim_io_finished(struct ril_sim_card *self, guint id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
struct ril_sim_card_priv *priv = self->priv;
gpointer key = GINT_TO_POINTER(id);
if (g_hash_table_remove(priv->sim_io_pending, key) &&
!g_hash_table_size(priv->sim_io_pending)) {
/* Reset the idle loop count */
if (priv->sim_io_idle_id) {
g_source_remove(priv->sim_io_idle_id);
priv->sim_io_idle_count = 0;
}
priv->sim_io_idle_id =
g_idle_add(ril_sim_card_sim_io_idle_cb, self);
}
ril_sim_card_update_sim_io_active(self);
}
}
static void ril_sim_card_status_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_sim_card *self = user_data;
struct ril_sim_card *self = RIL_SIMCARD(user_data);
ril_sim_card_request_status(self);
}
@@ -474,6 +619,13 @@ gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *self,
SIGNAL_APP_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *self,
ril_sim_card_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
@@ -488,8 +640,11 @@ void ril_sim_card_remove_handlers(struct ril_sim_card *self, gulong *ids, int n)
static void ril_sim_card_init(struct ril_sim_card *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIMCARD_TYPE,
struct ril_sim_card_priv);
struct ril_sim_card_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_SIMCARD_TYPE, struct ril_sim_card_priv);
self->priv = priv;
priv->sim_io_pending = g_hash_table_new(g_direct_hash, g_direct_equal);
}
static void ril_sim_card_dispose(GObject *object)
@@ -507,6 +662,10 @@ static void ril_sim_card_finalize(GObject *object)
struct ril_sim_card *self = RIL_SIMCARD(object);
struct ril_sim_card_priv *priv = self->priv;
if (priv->sim_io_idle_id) {
g_source_remove(priv->sim_io_idle_id);
}
g_hash_table_destroy(priv->sim_io_pending);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
ril_sim_card_status_free(self->status);
@@ -520,22 +679,11 @@ static void ril_sim_card_class_init(RilSimCardClass *klass)
object_class->dispose = ril_sim_card_dispose;
object_class->finalize = ril_sim_card_finalize;
g_type_class_add_private(klass, sizeof(struct ril_sim_card_priv));
ril_sim_card_signals[SIGNAL_STATUS_RECEIVED] =
g_signal_new(SIGNAL_STATUS_RECEIVED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
ril_sim_card_signals[SIGNAL_STATUS_CHANGED] =
g_signal_new(SIGNAL_STATUS_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
ril_sim_card_signals[SIGNAL_STATE_CHANGED] =
g_signal_new(SIGNAL_STATE_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
ril_sim_card_signals[SIGNAL_APP_CHANGED] =
g_signal_new(SIGNAL_APP_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
NEW_SIGNAL_(klass,STATUS_RECEIVED);
NEW_SIGNAL(klass,STATUS);
NEW_SIGNAL(klass,STATE);
NEW_SIGNAL(klass,APP);
NEW_SIGNAL(klass,SIM_IO_ACTIVE);
}
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -44,6 +44,7 @@ struct ril_sim_card {
struct ril_sim_card_priv *priv;
struct ril_sim_card_status *status;
const struct ril_sim_card_app *app;
gboolean sim_io_active;
guint slot;
};
@@ -55,6 +56,9 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
void ril_sim_card_unref(struct ril_sim_card *sc);
void ril_sim_card_request_status(struct ril_sim_card *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);
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
@@ -64,6 +68,8 @@ gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
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);

View File

@@ -1,668 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_sim_info.h"
#include "ril_network.h"
#include "ril_log.h"
#include <ofono/sim.h>
#include "ofono.h"
#include "storage.h"
#define RIL_SIM_INFO_STORE "cache"
#define RIL_SIM_INFO_STORE_GROUP "sim"
#define RIL_SIM_INFO_STORE_SPN "spn"
/* ICCID -> IMSI map */
#define RIL_SIM_ICCID_MAP "iccidmap"
#define RIL_SIM_ICCID_MAP_IMSI "imsi"
#define RIL_SIM_DEFAULT_SPN_BUFSIZE 8
G_STATIC_ASSERT(RIL_SIM_DEFAULT_SPN_BUFSIZE >= \
OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1);
typedef GObjectClass RilSimInfoClass;
typedef struct ril_sim_info RilSimInfo;
typedef void (*ril_sim_info_remove_cb_t)(struct ofono_sim *sim,
unsigned int id);
typedef void (*ril_sim_info_set_value_cb_t)(struct ril_sim_info *info,
const char *value);
struct ril_sim_info_watch {
ril_sim_info_set_value_cb_t set_value;
ril_sim_info_remove_cb_t remove;
struct ril_sim_info *info;
unsigned int id;
};
struct ril_sim_info_priv {
char *log_prefix;
char *iccid;
char *imsi;
char *cached_spn;
char *sim_spn;
char *public_spn;
char default_spn[RIL_SIM_DEFAULT_SPN_BUFSIZE];
int public_spn_block;
struct ofono_sim *sim;
struct ril_sim_info_watch state_watch;
struct ril_sim_info_watch iccid_watch;
struct ril_sim_info_watch imsi_watch;
struct ril_sim_info_watch spn_watch;
struct ril_network *network;
gulong network_operator_changed_id;
gboolean update_imsi_cache;
gboolean update_iccid_map;
};
enum ril_sim_info_signal {
SIGNAL_ICCID_CHANGED,
SIGNAL_IMSI_CHANGED,
SIGNAL_SPN_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_ICCID_CHANGED_NAME "ril-sim-info-iccid-changed"
#define SIGNAL_IMSI_CHANGED_NAME "ril-sim-info-imsi-changed"
#define SIGNAL_SPN_CHANGED_NAME "ril-sim-info-spn-changed"
static guint ril_sim_info_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilSimInfo, ril_sim_info, G_TYPE_OBJECT)
#define RIL_SIMINFO_TYPE (ril_sim_info_get_type())
#define RIL_SIMINFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
RIL_SIMINFO_TYPE, RilSimInfo))
#define NEW_SIGNAL(klass,name) \
ril_sim_info_signals[SIGNAL_##name##_CHANGED] = \
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
#define DBG_(info,fmt,args...) DBG("%s" fmt, (info)->priv->log_prefix, ##args)
static void ril_sim_info_signal_emit(struct ril_sim_info *self,
enum ril_sim_info_signal id)
{
g_signal_emit(self, ril_sim_info_signals[id], 0);
}
static void ril_sim_info_watch_remove(struct ril_sim_info_watch *watch)
{
if (watch->id) {
struct ril_sim_info_priv *priv = watch->info->priv;
GASSERT(priv->sim);
if (priv->sim) {
watch->remove(priv->sim, watch->id);
GASSERT(!watch->id);
}
watch->id = 0;
}
if (watch->set_value) {
watch->set_value(watch->info, NULL);
}
}
static void ril_sim_info_remove_spn_watch(struct ofono_sim *sim,
unsigned int id)
{
ofono_sim_remove_spn_watch(sim, &id);
}
static void ril_sim_info_update_imsi_cache(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = self->priv;
if (priv->update_imsi_cache && priv->imsi && priv->imsi[0] &&
priv->cached_spn && priv->cached_spn[0]) {
gboolean save = FALSE;
const char *store = RIL_SIM_INFO_STORE;
GKeyFile *cache = storage_open(priv->imsi, store);
char *spn = g_key_file_get_string(cache,
RIL_SIM_INFO_STORE_GROUP,
RIL_SIM_INFO_STORE_SPN, NULL);
if (g_strcmp0(priv->cached_spn, spn)) {
save = TRUE;
g_key_file_set_string(cache, RIL_SIM_INFO_STORE_GROUP,
RIL_SIM_INFO_STORE_SPN, priv->cached_spn);
}
/*
* Since we are most likely running on flash which
* supports a limited number of writes, don't overwrite
* the file unless something has actually changed.
*/
if (save) {
DBG_(self, "updating " STORAGEDIR "/%s/%s",
priv->imsi, store);
storage_close(priv->imsi, store, cache, TRUE);
} else {
g_key_file_free(cache);
}
g_free(spn);
priv->update_imsi_cache = FALSE;
}
}
static void ril_sim_info_update_iccid_map(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = self->priv;
if (priv->update_iccid_map && priv->iccid && priv->iccid[0] &&
priv->imsi && priv->imsi[0]) {
const char *store = RIL_SIM_ICCID_MAP;
GKeyFile *map = storage_open(NULL, store);
char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
priv->iccid, NULL);
/*
* Since we are most likely running on flash which
* supports a limited number of writes, don't overwrite
* the file unless something has actually changed.
*/
if (g_strcmp0(imsi, priv->imsi)) {
DBG_(self, "updating " STORAGEDIR "/%s", store);
g_key_file_set_string(map, RIL_SIM_ICCID_MAP_IMSI,
priv->iccid, priv->imsi);
storage_close(NULL, store, map, TRUE);
} else {
g_key_file_free(map);
}
g_free(imsi);
priv->update_iccid_map = FALSE;
}
}
static void ril_sim_info_set_imsi(struct ril_sim_info *self, const char *imsi)
{
struct ril_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->imsi, imsi)) {
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(imsi);
priv->update_iccid_map = TRUE;
ril_sim_info_update_iccid_map(self);
ril_sim_info_update_imsi_cache(self);
ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
}
}
static void ril_sim_info_update_public_spn(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = self->priv;
GASSERT(priv->public_spn_block >= 0);
if (!priv->public_spn_block) {
const char *spn = priv->sim_spn ? priv->sim_spn :
priv->cached_spn ? priv->cached_spn :
priv->default_spn;
if (g_strcmp0(priv->public_spn, spn)) {
g_free(priv->public_spn);
self->spn = priv->public_spn = g_strdup(spn);
ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
}
}
}
static void ril_sim_info_set_cached_spn(struct ril_sim_info *self,
const char *spn)
{
struct ril_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->cached_spn, spn)) {
g_free(priv->cached_spn);
if (spn) {
DBG_(self, "cached spn \"%s\"", spn);
priv->cached_spn = g_strdup(spn);
priv->update_imsi_cache = TRUE;
ril_sim_info_update_imsi_cache(self);
} else {
priv->cached_spn = NULL;
}
ril_sim_info_update_public_spn(self);
}
}
static void ril_sim_info_set_sim_spn(struct ril_sim_info *self,
const char *spn)
{
struct ril_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->sim_spn, spn)) {
g_free(priv->sim_spn);
priv->sim_spn = g_strdup(spn);
priv->update_imsi_cache = TRUE;
ril_sim_info_set_cached_spn(self, spn);
ril_sim_info_update_imsi_cache(self);
ril_sim_info_update_public_spn(self);
}
}
static void ril_sim_info_update_default_spn(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = self->priv;
char buf[RIL_SIM_DEFAULT_SPN_BUFSIZE];
const char *mcc = NULL;
const char *mnc = NULL;
if (priv->sim &&
ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
mcc = ofono_sim_get_mcc(priv->sim);
mnc = ofono_sim_get_mnc(priv->sim);
}
if (mcc && mnc) {
snprintf(buf, RIL_SIM_DEFAULT_SPN_BUFSIZE, "%s%s", mcc, mnc);
buf[RIL_SIM_DEFAULT_SPN_BUFSIZE - 1] = 0;
} else {
buf[0] = 0;
}
if (strcmp(buf, priv->default_spn)) {
strncpy(priv->default_spn, buf, RIL_SIM_DEFAULT_SPN_BUFSIZE);
DBG_(self, "default spn \"%s\"", priv->default_spn);
ril_sim_info_update_public_spn(self);
}
}
static void ril_sim_info_network_check(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = self->priv;
if (priv->network && priv->network->operator && priv->sim &&
ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
const char *mcc = ofono_sim_get_mcc(priv->sim);
const char *mnc = ofono_sim_get_mnc(priv->sim);
const struct ofono_network_operator *op =
priv->network->operator;
if (mcc && mcc[0] && !strcmp(mcc, op->mcc) &&
mnc && mnc[0] && !strcmp(mnc, op->mnc)) {
/*
* If EFspn is present then sim_spn should be set
* before we get registered with the network.
*/
DBG_(self, "home network \"%s\"", op->name);
if (!priv->sim_spn) {
ril_sim_info_set_cached_spn(self, op->name);
}
}
}
}
static void ril_sim_info_network_operator_changed(struct ril_network *network,
void *user_data)
{
struct ril_sim_info *self = RIL_SIMINFO(user_data);
DBG_(self, "");
ril_sim_info_network_check(self);
}
static void ril_sim_info_load_cache(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = self->priv;
if (priv->iccid && priv->iccid[0]) {
GKeyFile *map = storage_open(NULL, RIL_SIM_ICCID_MAP);
char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
priv->iccid, NULL);
g_key_file_free(map);
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
if (priv->imsi && priv->imsi[0]) {
/* Need to update ICCID -> IMSI map */
DBG_(self, "IMSI changed %s -> %s",
priv->imsi, imsi);
priv->update_imsi_cache = TRUE;
}
g_free(priv->imsi);
self->imsi = priv->imsi = imsi;
DBG_(self, "imsi[%s] = %s", priv->iccid, imsi);
ril_sim_info_update_iccid_map(self);
ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
} else if (imsi) {
g_free(imsi);
} else {
DBG_(self, "no imsi for iccid %s", priv->iccid);
}
}
if (priv->imsi && priv->imsi[0]) {
GKeyFile *cache = storage_open(priv->imsi, RIL_SIM_INFO_STORE);
char *spn = g_key_file_get_string(cache,
RIL_SIM_INFO_STORE_GROUP,
RIL_SIM_INFO_STORE_SPN, NULL);
g_key_file_free(cache);
if (spn && spn[0] && g_strcmp0(priv->cached_spn, spn)) {
if (priv->cached_spn && priv->cached_spn[0]) {
/* Need to update the cache file */
DBG_(self, "spn changing %s -> %s",
priv->cached_spn, spn);
priv->update_imsi_cache = TRUE;
}
g_free(priv->cached_spn);
priv->cached_spn = spn;
DBG_(self, "spn[%s] = \"%s\"", priv->imsi, spn);
ril_sim_info_update_imsi_cache(self);
ril_sim_info_update_public_spn(self);
} else if (spn) {
g_free(spn);
} else {
DBG_(self, "no spn for imsi %s", priv->imsi);
}
}
}
static void ril_sim_info_set_iccid(struct ril_sim_info *self, const char *iccid)
{
struct ril_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->iccid, iccid)) {
g_free(priv->iccid);
self->iccid = priv->iccid = g_strdup(iccid);
ril_sim_info_signal_emit(self, SIGNAL_ICCID_CHANGED);
if (iccid) {
ril_sim_info_load_cache(self);
}
}
}
static void ril_sim_info_imsi_watch_cb(const char *imsi, void *data)
{
struct ril_sim_info_watch *watch = data;
DBG_(watch->info, "%s", imsi);
ril_sim_info_set_imsi(watch->info, imsi);
}
static void ril_sim_info_spn_watch_cb(const char *spn, const char *dc,
void *data)
{
struct ril_sim_info_watch *watch = data;
DBG_(watch->info, "%s", spn);
ril_sim_info_set_sim_spn(watch->info, spn);
}
static void ril_sim_info_iccid_watch_cb(const char *iccid, void *data)
{
struct ril_sim_info_watch *watch = data;
DBG_(watch->info, "%s", iccid);
ril_sim_info_set_iccid(watch->info, iccid);
}
static void ril_sim_info_watch_done(void *data)
{
struct ril_sim_info_watch *watch = data;
GASSERT(watch->id);
watch->id = 0;
}
static void ril_sim_info_handle_sim_state(struct ril_sim_info *self,
enum ofono_sim_state state)
{
struct ril_sim_info_priv *priv = self->priv;
struct ril_sim_info_watch *watch;
DBG_(self, "%d", state);
switch (state) {
case OFONO_SIM_STATE_READY:
/* SPN */
watch = &priv->spn_watch;
if (!watch->id) {
ofono_sim_add_spn_watch(priv->sim, &watch->id,
ril_sim_info_spn_watch_cb, watch,
ril_sim_info_watch_done);
GASSERT(priv->spn_watch.id);
}
/* IMSI */
watch = &priv->imsi_watch;
if (!watch->id) {
watch->id = ofono_sim_add_imsi_watch(priv->sim,
ril_sim_info_imsi_watch_cb, watch,
ril_sim_info_watch_done);
GASSERT(watch->id);
}
/* no break */
case OFONO_SIM_STATE_INSERTED:
case OFONO_SIM_STATE_LOCKED_OUT:
/* ICCID */
watch = &priv->iccid_watch;
if (!watch->id) {
watch->id = ofono_sim_add_iccid_watch(priv->sim,
ril_sim_info_iccid_watch_cb, watch,
ril_sim_info_watch_done);
GASSERT(watch->id);
}
break;
case OFONO_SIM_STATE_NOT_PRESENT:
case OFONO_SIM_STATE_RESETTING:
ril_sim_info_watch_remove(&priv->spn_watch);
ril_sim_info_watch_remove(&priv->imsi_watch);
ril_sim_info_watch_remove(&priv->iccid_watch);
break;
}
ril_sim_info_update_default_spn(self);
ril_sim_info_network_check(self);
}
static void ril_sim_info_state_watch_cb(enum ofono_sim_state new_state,
void *data)
{
struct ril_sim_info_watch *watch = data;
ril_sim_info_handle_sim_state(watch->info, new_state);
}
struct ril_sim_info *ril_sim_info_new(const char *log_prefix)
{
struct ril_sim_info *self = g_object_new(RIL_SIMINFO_TYPE, NULL);
self->priv->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
return self;
}
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_SIMINFO(self));
return self;
} else {
return NULL;
}
}
void ril_sim_info_unref(struct ril_sim_info *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_SIMINFO(self));
}
}
void ril_sim_info_set_ofono_sim(struct ril_sim_info *self,
struct ofono_sim *sim)
{
if (G_LIKELY(self)) {
struct ril_sim_info_priv *priv = self->priv;
if (priv->sim != sim) {
priv->public_spn_block++;
ril_sim_info_watch_remove(&priv->state_watch);
ril_sim_info_watch_remove(&priv->iccid_watch);
ril_sim_info_watch_remove(&priv->imsi_watch);
ril_sim_info_watch_remove(&priv->spn_watch);
priv->update_imsi_cache = FALSE;
priv->update_iccid_map = FALSE;
priv->sim = sim;
if (sim) {
priv->state_watch.id =
ofono_sim_add_state_watch(sim,
ril_sim_info_state_watch_cb,
&priv->state_watch,
ril_sim_info_watch_done);
GASSERT(priv->state_watch.id);
DBG_(self, "attached to sim");
ril_sim_info_handle_sim_state(self,
ofono_sim_get_state(sim));
} else {
DBG_(self, "detached from sim");
ril_sim_info_update_default_spn(self);
ril_sim_info_network_check(self);
}
priv->public_spn_block--;
ril_sim_info_update_public_spn(self);
}
}
}
void ril_sim_info_set_network(struct ril_sim_info *self,
struct ril_network *network)
{
if (G_LIKELY(self) && self->priv->network != network) {
struct ril_sim_info_priv *priv = self->priv;
if (priv->network) {
ril_network_remove_handlers(priv->network,
&priv->network_operator_changed_id, 1);
ril_network_unref(priv->network);
}
if (network) {
priv->network_operator_changed_id =
ril_network_add_operator_changed_handler(network,
ril_sim_info_network_operator_changed,
self);
priv->network = ril_network_ref(network);
ril_sim_info_network_check(self);
} else {
priv->network = NULL;
}
}
}
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *self,
ril_sim_info_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *self,
ril_sim_info_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *self,
ril_sim_info_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_sim_info_remove_handler(struct ril_sim_info *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
static void ril_sim_info_watch_init(struct ril_sim_info *self,
struct ril_sim_info_watch *watch,
ril_sim_info_set_value_cb_t set_value,
ril_sim_info_remove_cb_t remove)
{
watch->info = self;
watch->set_value = set_value;
watch->remove = remove;
}
static void ril_sim_info_init(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_SIMINFO_TYPE, struct ril_sim_info_priv);
self->priv = priv;
ril_sim_info_watch_init(self, &priv->state_watch,
NULL, ofono_sim_remove_state_watch);
ril_sim_info_watch_init(self, &priv->iccid_watch,
ril_sim_info_set_iccid, ofono_sim_remove_iccid_watch);
ril_sim_info_watch_init(self, &priv->imsi_watch,
ril_sim_info_set_imsi, ofono_sim_remove_imsi_watch);
ril_sim_info_watch_init(self, &priv->spn_watch,
ril_sim_info_set_sim_spn, ril_sim_info_remove_spn_watch);
}
static void ril_sim_info_dispose(GObject *object)
{
struct ril_sim_info *self = RIL_SIMINFO(object);
ril_sim_info_set_ofono_sim(self, NULL);
ril_sim_info_set_network(self, NULL);
G_OBJECT_CLASS(ril_sim_info_parent_class)->dispose(object);
}
static void ril_sim_info_finalize(GObject *object)
{
struct ril_sim_info *self = RIL_SIMINFO(object);
struct ril_sim_info_priv *priv = self->priv;
g_free(priv->log_prefix);
g_free(priv->cached_spn);
g_free(priv->public_spn);
GASSERT(!priv->iccid);
GASSERT(!priv->imsi);
GASSERT(!priv->sim_spn);
G_OBJECT_CLASS(ril_sim_info_parent_class)->finalize(object);
}
static void ril_sim_info_class_init(RilSimInfoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_sim_info_dispose;
object_class->finalize = ril_sim_info_finalize;
g_type_class_add_private(klass, sizeof(struct ril_sim_info_priv));
NEW_SIGNAL(klass, ICCID);
NEW_SIGNAL(klass, IMSI);
NEW_SIGNAL(klass, SPN);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,243 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_sim_info.h"
#include "ril_log.h"
#include <ofono/dbus.h>
#include <gdbus.h>
#include "ofono.h"
#include "storage.h"
enum sim_info_event_id {
SIM_INFO_EVENT_ICCID,
SIM_INFO_EVENT_IMSI,
SIM_INFO_EVENT_SPN,
SIM_INFO_EVENT_COUNT
};
struct ril_sim_info_dbus {
struct ril_modem *md;
struct ril_sim_info *info;
DBusConnection *conn;
char *path;
gulong handler_id[SIM_INFO_EVENT_COUNT];
};
#define RIL_SIM_INFO_DBUS_INTERFACE "org.nemomobile.ofono.SimInfo"
#define RIL_SIM_INFO_DBUS_INTERFACE_VERSION (1)
#define RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL "CardIdentifierChanged"
#define RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL "SubscriberIdentityChanged"
#define RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL "ServiceProviderNameChanged"
static void ril_sim_info_dbus_append_string(DBusMessageIter *it, const char *s)
{
if (!s) s = "";
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &s);
}
static DBusMessage *ril_sim_info_dbus_reply_with_string(DBusMessage *msg,
const char *str)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
ril_sim_info_dbus_append_string(&iter, str);
return reply;
}
static DBusMessage *ril_sim_info_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_info_dbus *dbus = data;
struct ril_sim_info *info = dbus->info;
DBusMessage *reply = dbus_message_new_method_return(msg);
const dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
ril_sim_info_dbus_append_string(&iter, info->iccid);
ril_sim_info_dbus_append_string(&iter, info->imsi);
ril_sim_info_dbus_append_string(&iter, info->spn);
return reply;
}
static DBusMessage *ril_sim_info_dbus_get_version(DBusConnection *dc,
DBusMessage *msg, void *data)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
return reply;
}
static DBusMessage *ril_sim_info_dbus_get_iccid(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_info_dbus *dbus = data;
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->iccid);
}
static DBusMessage *ril_sim_info_dbus_get_imsi(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_info_dbus *dbus = data;
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->imsi);
}
static DBusMessage *ril_sim_info_dbus_get_spn(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_info_dbus *dbus = data;
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->spn);
}
static const GDBusMethodTable ril_sim_info_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS({"version", "i" },
{"iccid", "s" },
{"imsi", "s" },
{"spn" , "s"}),
ril_sim_info_dbus_get_all) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
ril_sim_info_dbus_get_version) },
{ GDBUS_METHOD("GetCardIdentifier",
NULL, GDBUS_ARGS({ "iccid", "s" }),
ril_sim_info_dbus_get_iccid) },
{ GDBUS_METHOD("GetSubscriberIdentity",
NULL, GDBUS_ARGS({ "imsi", "s" }),
ril_sim_info_dbus_get_imsi) },
{ GDBUS_METHOD("GetServiceProviderName",
NULL, GDBUS_ARGS({ "spn", "s" }),
ril_sim_info_dbus_get_spn) },
{ }
};
static const GDBusSignalTable ril_sim_info_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
GDBUS_ARGS({ "iccid", "s" })) },
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
GDBUS_ARGS({ "spn", "s" })) },
{ }
};
static void ril_sim_info_dbus_emit(struct ril_sim_info_dbus *dbus,
const char *signal, const char *value)
{
const char *arg = value;
if (!arg) arg = "";
g_dbus_emit_signal(dbus->conn, dbus->path, RIL_SIM_INFO_DBUS_INTERFACE,
signal, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
}
static void ril_sim_info_dbus_iccid_cb(struct ril_sim_info *info, void *arg)
{
struct ril_sim_info_dbus *dbus = arg;
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
info->iccid);
}
static void ril_sim_info_dbus_imsi_cb(struct ril_sim_info *info, void *arg)
{
struct ril_sim_info_dbus *dbus = arg;
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
info->imsi);
}
static void ril_sim_info_dbus_spn_cb(struct ril_sim_info *info, void *arg)
{
struct ril_sim_info_dbus *dbus = arg;
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
info->spn);
}
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
struct ril_sim_info *info)
{
struct ril_sim_info_dbus *dbus = g_new0(struct ril_sim_info_dbus, 1);
DBG("%s", ril_modem_get_path(md));
dbus->md = md;
dbus->path = g_strdup(ril_modem_get_path(md));
dbus->info = ril_sim_info_ref(info);
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
/* Register D-Bus interface */
if (g_dbus_register_interface(dbus->conn, dbus->path,
RIL_SIM_INFO_DBUS_INTERFACE, ril_sim_info_dbus_methods,
ril_sim_info_dbus_signals, NULL, dbus, NULL)) {
ofono_modem_add_interface(md->ofono,
RIL_SIM_INFO_DBUS_INTERFACE);
dbus->handler_id[SIM_INFO_EVENT_ICCID] =
ril_sim_info_add_iccid_changed_handler(info,
ril_sim_info_dbus_iccid_cb, dbus);
dbus->handler_id[SIM_INFO_EVENT_IMSI] =
ril_sim_info_add_imsi_changed_handler(info,
ril_sim_info_dbus_imsi_cb, dbus);
dbus->handler_id[SIM_INFO_EVENT_SPN] =
ril_sim_info_add_spn_changed_handler(info,
ril_sim_info_dbus_spn_cb, dbus);
return dbus;
} else {
ofono_error("CellInfo D-Bus register failed");
ril_sim_info_dbus_free(dbus);
return NULL;
}
}
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus)
{
if (dbus) {
unsigned int i;
DBG("%s", dbus->path);
g_dbus_unregister_interface(dbus->conn, dbus->path,
RIL_SIM_INFO_DBUS_INTERFACE);
ofono_modem_remove_interface(dbus->md->ofono,
RIL_SIM_INFO_DBUS_INTERFACE);
dbus_connection_unref(dbus->conn);
for (i=0; i<G_N_ELEMENTS(dbus->handler_id); i++) {
ril_sim_info_remove_handler(dbus->info,
dbus->handler_id[i]);
}
ril_sim_info_unref(dbus->info);
g_free(dbus->path);
g_free(dbus);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,26 +16,31 @@
#include "ril_sim_settings.h"
#include "ril_log.h"
#include "sailfish_watch.h"
#include <gutil_misc.h>
#include <ofono/sim.h>
#include "ofono.h"
#include "storage.h"
#define RIL_SIM_STORE "ril"
#define RIL_SIM_STORE_GROUP "Settings"
#define RIL_SIM_STORE_PREF_MODE "TechnologyPreference"
#define RIL_SIM_STORE_PREF_MODE_DEFAULT(self) ((self)->enable_4g ? \
OFONO_RADIO_ACCESS_MODE_LTE : OFONO_RADIO_ACCESS_MODE_UMTS)
#define RIL_PREF_MODE_DEFAULT(self) (\
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
OFONO_RADIO_ACCESS_MODE_LTE : \
((self)->techs & OFONO_RADIO_ACCESS_MODE_UMTS) ? \
OFONO_RADIO_ACCESS_MODE_UMTS : \
OFONO_RADIO_ACCESS_MODE_GSM)
typedef GObjectClass RilSimSettingsClass;
typedef struct ril_sim_settings RilSimSettings;
enum sailfish_watch_events {
WATCH_EVENT_IMSI,
WATCH_EVENT_COUNT
};
struct ril_sim_settings_priv {
struct ofono_sim *sim;
guint imsi_watch_id;
guint state_watch_id;
gulong watch_event_id[WATCH_EVENT_COUNT];
struct sailfish_watch *watch;
GKeyFile *storage;
char *imsi;
};
@@ -62,176 +67,77 @@ G_DEFINE_TYPE(RilSimSettings, ril_sim_settings, G_TYPE_OBJECT)
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
/* Skip the leading slash from the modem path: */
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
static void ril_sim_settings_signal_emit(struct ril_sim_settings *self,
enum ril_sim_settings_signal id)
{
g_signal_emit(self, ril_sim_settings_signals[id], 0);
}
static void ril_sim_settings_reload(struct ril_sim_settings *self)
{
struct ril_sim_settings_priv *priv = self->priv;
if (priv->storage) {
g_key_file_free(priv->storage);
priv->storage = NULL;
}
if (priv->imsi) {
char *mode_str;
enum ofono_radio_access_mode mode;
priv->storage = storage_open(priv->imsi, RIL_SIM_STORE);
mode_str = g_key_file_get_string(priv->storage,
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_PREF_MODE, NULL);
if (ofono_radio_access_mode_from_string(mode_str, &mode)) {
if (!self->enable_4g &&
mode == OFONO_RADIO_ACCESS_MODE_LTE) {
mode = OFONO_RADIO_ACCESS_MODE_ANY;
}
} else {
mode = OFONO_RADIO_ACCESS_MODE_ANY;
}
if (mode == OFONO_RADIO_ACCESS_MODE_ANY) {
self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
} else {
self->pref_mode = mode;
}
g_free(mode_str);
}
}
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *self,
enum ofono_radio_access_mode mode)
{
if (G_LIKELY(self) && self->pref_mode != mode) {
struct ril_sim_settings_priv *priv = self->priv;
const char *mode_str = ofono_radio_access_mode_to_string(mode);
GASSERT(priv->storage);
if (mode_str) {
if (priv->storage) {
g_key_file_set_string(priv->storage,
RIL_SIM_STORE_GROUP,
RIL_SIM_STORE_PREF_MODE, mode_str);
storage_sync(self->imsi, RIL_SIM_STORE,
priv->storage);
}
self->pref_mode = mode;
ril_sim_settings_signal_emit(self,
SIGNAL_PREF_MODE_CHANGED);
}
self->pref_mode = mode;
ril_sim_settings_signal_emit(self, SIGNAL_PREF_MODE_CHANGED);
}
}
static void ril_sim_settings_set_imsi(struct ril_sim_settings *self,
const char *imsi)
{
struct ril_sim_settings_priv *priv = self->priv;
if (g_strcmp0(priv->imsi, imsi)) {
enum ofono_radio_access_mode prev_mode = self->pref_mode;
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(imsi);
ril_sim_settings_reload(self);
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
if (prev_mode != self->pref_mode) {
ril_sim_settings_signal_emit(self,
SIGNAL_PREF_MODE_CHANGED);
}
}
}
static void ril_sim_settings_imsi_watch_cb(const char *imsi, void *user_data)
{
ril_sim_settings_set_imsi(RIL_SIM_SETTINGS(user_data), imsi);
}
static void ril_sim_settings_imsi_watch_done(void *user_data)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
struct ril_sim_settings_priv *priv = self->priv;
GASSERT(priv->imsi_watch_id);
priv->imsi_watch_id = 0;
}
static void ril_sim_settings_state_check(struct ril_sim_settings *self,
enum ofono_sim_state new_state)
{
if (new_state != OFONO_SIM_STATE_READY) {
ril_sim_settings_set_imsi(self, NULL);
}
}
static void ril_sim_settings_state_watch(enum ofono_sim_state new_state,
static void ril_sim_settings_imsi_changed(struct sailfish_watch *watch,
void *user_data)
{
ril_sim_settings_state_check(RIL_SIM_SETTINGS(user_data), new_state);
}
static void ril_sim_settings_state_watch_done(void *user_data)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
struct ril_sim_settings_priv *priv = self->priv;
GASSERT(priv->state_watch_id);
priv->state_watch_id = 0;
}
void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
struct ofono_sim *sim)
{
if (G_LIKELY(self)) {
struct ril_sim_settings_priv *priv = self->priv;
if (priv->sim != sim) {
GASSERT(priv->sim || !priv->imsi_watch_id);
if (priv->imsi_watch_id) {
ofono_sim_remove_imsi_watch(priv->sim,
priv->imsi_watch_id);
/*
* ril_sim_settings_imsi_watch_done
* clears it
*/
GASSERT(!priv->imsi_watch_id);
}
if (priv->state_watch_id) {
ofono_sim_remove_state_watch(priv->sim,
priv->state_watch_id);
/*
* ril_sim_settings_state_watch_done
* clears it
*/
GASSERT(!priv->state_watch_id);
}
priv->sim = sim;
if (sim) {
priv->state_watch_id =
ofono_sim_add_state_watch(sim,
ril_sim_settings_state_watch, self,
ril_sim_settings_state_watch_done);
GASSERT(priv->state_watch_id);
ril_sim_settings_state_check(self,
ofono_sim_get_state(sim));
/*
* ofono_sim_add_imsi_watch immediately
* calls the event callback if IMSI is
* already known. It's useless though
* because we still have to check the
* current state in case if IMSI is not
* available yet.
*/
priv->imsi_watch_id =
ofono_sim_add_imsi_watch(priv->sim,
ril_sim_settings_imsi_watch_cb, self,
ril_sim_settings_imsi_watch_done);
GASSERT(priv->state_watch_id);
}
/* Luckily, ofono_sim_get_imsi handles NULL pointer */
ril_sim_settings_set_imsi(self,
ofono_sim_get_imsi(sim));
}
if (g_strcmp0(priv->imsi, watch->imsi)) {
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(watch->imsi);
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
}
}
struct ril_sim_settings *ril_sim_settings_new(const char *path,
enum ofono_radio_access_mode techs)
{
struct ril_sim_settings *self = NULL;
if (G_LIKELY(path)) {
struct ril_sim_settings_priv *priv;
self = g_object_new(RIL_SIM_SETTINGS_TYPE, NULL);
priv = self->priv;
self->techs = techs;
self->pref_mode = RIL_PREF_MODE_DEFAULT(self);
priv->watch = sailfish_watch_new(path);
priv->watch_event_id[WATCH_EVENT_IMSI] =
sailfish_watch_add_imsi_changed_handler(priv->watch,
ril_sim_settings_imsi_changed, self);
self->imsi = priv->imsi = g_strdup(priv->watch->imsi);
}
return self;
}
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_SIM_SETTINGS(self));
return self;
} else {
return NULL;
}
}
void ril_sim_settings_unref(struct ril_sim_settings *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_SIM_SETTINGS(self));
}
}
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *self,
ril_sim_settings_cb_t cb, void *arg)
{
@@ -260,51 +166,26 @@ void ril_sim_settings_remove_handlers(struct ril_sim_settings *self,
gutil_disconnect_handlers(self, ids, count);
}
struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc)
{
struct ril_sim_settings *self = g_object_new(RIL_SIM_SETTINGS_TYPE, 0);
self->enable_4g = sc->enable_4g;
self->slot = sc->slot;
self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
return self;
}
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_SIM_SETTINGS(self));
return self;
} else {
return NULL;
}
}
void ril_sim_settings_unref(struct ril_sim_settings *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_SIM_SETTINGS(self));
}
}
static void ril_sim_settings_init(struct ril_sim_settings *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIM_SETTINGS_TYPE,
struct ril_sim_settings_priv);
}
static void ril_sim_settings_dispose(GObject *object)
static void ril_sim_settings_finalize(GObject *object)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
struct ril_sim_settings_priv *priv = self->priv;
ril_sim_settings_set_ofono_sim(self, NULL);
G_OBJECT_CLASS(ril_sim_settings_parent_class)->dispose(object);
sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
sailfish_watch_unref(priv->watch);
g_free(priv->imsi);
G_OBJECT_CLASS(ril_sim_settings_parent_class)->finalize(object);
}
static void ril_sim_settings_class_init(RilSimSettingsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_sim_settings_dispose;
G_OBJECT_CLASS(klass)->finalize = ril_sim_settings_finalize;
g_type_class_add_private(klass, sizeof(struct ril_sim_settings_priv));
NEW_SIGNAL(klass, IMSI);
NEW_SIGNAL(klass, PREF_MODE);

View File

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

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,7 +14,6 @@
*/
#include "ril_plugin.h"
#include "ril_constants.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -255,8 +254,9 @@ static void ril_sms_submit(struct ofono_sms *sms, const unsigned char *pdu,
DBG("%s", tpdu);
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SEND_SMS, ril_sms_submit_cb,
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
mms ? RIL_REQUEST_SEND_SMS_EXPECT_MORE : RIL_REQUEST_SEND_SMS,
ril_sms_submit_cb, ril_sms_cbd_free,
ril_sms_cbd_new(sd, cb, data));
grilio_request_unref(req);
g_free(tpdu);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "util.h"

View File

@@ -21,6 +21,13 @@
#
#EmptyConfig=false
# User and group for the ofono process. RIL clients are typically
# expected to run under radio:radio.
#
# Default is radio:radio
#
#Identity=radio:radio
# If the phone has more than one SIM slot, the 3G/LTE module may be
# shared by all modems, meaning that only one of the slots can use
# 3G/LTE. In order to "hand 4G over" to the other slot, the modem
@@ -35,6 +42,17 @@
#
#3GLTEHandover=true
# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
# This option allows you to forcibly enable or disable use of this request.
# It's involved in 3G/LTE handover between the modems, meaning that it only
# makes sense if you have more than one slot.
#
# Possible values are auto, on and off
#
# Default is auto (enable for RIL version >= 11)
#
#SetRadioCapability=auto
[ril_0]
# Required entry, defines the RIL socket path
@@ -67,9 +85,15 @@ socket=/dev/socket/rild
#
#timeout=0
# Setting this one to false would disable 4G technology selection.
# Comma-separated list of radio technologies supported by the modem.
# Valid technologies are "gsm", "umts" and "lte". The special value
# "all" means that all technologies are supported.
#
# By default 4G is enabled
# The default is all
#
#technologies=all
# This one is deprecated, use the technologies entry instead (above).
#
#enable4G=true
@@ -100,7 +124,7 @@ socket=/dev/socket/rild
# This option allows you to forcibly enable or disable use of this request.
# Possible values are auto, on and off
#
# Default is auto (usage based on the RIL version)
# Default is auto (enable for RIL version >= 11)
#
#allowDataReq=auto
@@ -142,3 +166,31 @@ socket=/dev/socket/rild
# Default is 200 ms
#
#dataCallRetryDelay=200
# Additional local and remote hangup reasons. Remote reasons are checked
# first. Normally, RIL plugin figures it out automatically. You would only
# need to define these if your RIL does something unusual.
#
# No default
#
#remoteHangupReasons=20
#localHangupReasons=23
# Voice call support. Some devices like USB modems and tablets don't support
# voice calls. By default, voice calls are enabled and this option allows you
# to disable voice call handling.
#
# Default true
#
#enableVoicecall=true
# Timeout for the modem to show up, in milliseconds. Those that don't
# show up before this timeout expires, will be dropped (ignored).
#
# In some fairly rare cases it makes sense to shorten this timeout for
# optional modems (which may or may not be available), to speed up the
# boot up process.
#
# The default is 20000 (20 seconds)
#
#startTimeout=20000

View File

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

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "smsutil.h"
#include "util.h"

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,6 +20,8 @@
#include <sys/socket.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include "common.h"
#include "netreg.h"
@@ -48,7 +50,8 @@ const char *ril_error_to_string(int error)
RIL_E_(MODE_NOT_SUPPORTED);
RIL_E_(FDN_CHECK_FAILURE);
RIL_E_(ILLEGAL_SIM_OR_ME);
RIL_E_(UNUSED);
RIL_E_(MISSING_RESOURCE);
RIL_E_(NO_SUCH_ELEMENT);
RIL_E_(DIAL_MODIFIED_TO_USSD);
RIL_E_(DIAL_MODIFIED_TO_SS);
RIL_E_(DIAL_MODIFIED_TO_DIAL);
@@ -57,11 +60,39 @@ const char *ril_error_to_string(int error)
RIL_E_(USSD_MODIFIED_TO_USSD);
RIL_E_(SS_MODIFIED_TO_DIAL);
RIL_E_(SS_MODIFIED_TO_USSD);
RIL_E_(SS_MODIFIED_TO_SS);
RIL_E_(SUBSCRIPTION_NOT_SUPPORTED);
RIL_E_(MISSING_RESOURCE);
RIL_E_(NO_SUCH_ELEMENT);
RIL_E_(INVALID_PARAMETER);
RIL_E_(SS_MODIFIED_TO_SS);
RIL_E_(LCE_NOT_SUPPORTED);
RIL_E_(NO_MEMORY);
RIL_E_(INTERNAL_ERR);
RIL_E_(SYSTEM_ERR);
RIL_E_(MODEM_ERR);
RIL_E_(INVALID_STATE);
RIL_E_(NO_RESOURCES);
RIL_E_(SIM_ERR);
RIL_E_(INVALID_ARGUMENTS);
RIL_E_(INVALID_SIM_STATE);
RIL_E_(INVALID_MODEM_STATE);
RIL_E_(INVALID_CALL_ID);
RIL_E_(NO_SMS_TO_ACK);
RIL_E_(NETWORK_ERR);
RIL_E_(REQUEST_RATE_LIMITED);
RIL_E_(SIM_BUSY);
RIL_E_(SIM_FULL);
RIL_E_(NETWORK_REJECT);
RIL_E_(OPERATION_NOT_ALLOWED);
RIL_E_(EMPTY_RECORD);
RIL_E_(INVALID_SMS_FORMAT);
RIL_E_(ENCODING_ERR);
RIL_E_(INVALID_SMSC_ADDRESS);
RIL_E_(NO_SUCH_ENTRY);
RIL_E_(NETWORK_NOT_READY);
RIL_E_(NOT_PROVISIONED);
RIL_E_(NO_SUBSCRIPTION);
RIL_E_(NO_NETWORK_FOUND);
RIL_E_(DEVICE_IN_USE);
RIL_E_(ABORTED);
RIL_E_(INVALID_RESPONSE);
default:
snprintf(unknown, sizeof(unknown), "%d", error);
return unknown;
@@ -204,6 +235,8 @@ const char *ril_request_to_string(guint request)
RIL_REQUEST_(SHUTDOWN);
RIL_REQUEST_(GET_RADIO_CAPABILITY);
RIL_REQUEST_(SET_RADIO_CAPABILITY);
case RIL_RESPONSE_ACKNOWLEDGEMENT:
return "RESPONSE_ACK";
default:
snprintf(unknown, sizeof(unknown), "RIL_REQUEST_%d", request);
return unknown;
@@ -293,8 +326,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
{
int access_tech = -1;
int tech = -1;
if (stech && stech[0]) {
tech = atoi(stech);
if (ril_parse_int(stech, 0, &tech)) {
switch (tech) {
case RADIO_TECH_GPRS:
case RADIO_TECH_GSM:
@@ -351,8 +383,8 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
if (i == OFONO_MAX_MCC_LENGTH) {
/* Usually 2 but sometimes 3 digit network code */
for (i=0;
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
for (i = 0;
i < OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
i++) {
op->mnc[i] = *ptr++;
}
@@ -379,6 +411,26 @@ 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-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,6 +26,7 @@ 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) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,17 +14,21 @@
*/
#include "ril_plugin.h"
#include "ril_constants.h"
#include "ril_ecclist.h"
#include "ril_util.h"
#include "ril_log.h"
#include "common.h"
#include <gutil_ints.h>
#include <gutil_ring.h>
#include <gutil_idlequeue.h>
#include <gutil_intarray.h>
#define FLAG_NEED_CLIP 1
#define VOICECALL_BLOCK_TIMEOUT_MS (5*1000)
enum ril_voicecall_events {
VOICECALL_EVENT_CALL_STATE_CHANGED,
VOICECALL_EVENT_SUPP_SVC_NOTIFICATION,
@@ -38,12 +42,14 @@ struct ril_voicecall {
GRilIoQueue *q;
struct ofono_voicecall *vc;
struct ril_ecclist *ecclist;
unsigned int local_release;
unsigned char flags;
ofono_voicecall_cb_t cb;
void *data;
guint timer_id;
GUtilRing* dtmf_queue;
GUtilIntArray *local_release_ids;
GUtilIdleQueue *idleq;
GUtilRing *dtmf_queue;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
guint send_dtmf_id;
guint clcc_poll_id;
gulong event_id[VOICECALL_EVENT_COUNT];
@@ -52,35 +58,48 @@ struct ril_voicecall {
gulong ecclist_change_id;
};
struct ril_voicecall_change_state_req {
struct ril_voicecall_request_data {
int ref_count;
int pending_call_count;
int success;
struct ofono_voicecall *vc;
ofono_voicecall_cb_t cb;
gpointer data;
int affected_types;
};
struct lastcause_req {
struct ofono_voicecall *vc;
struct ril_voicecall *vd;
int id;
};
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
/*
* structs ofono_voicecall and voicecall are fully defined
* in src/voicecall.c; we need (read) access to the
* call objects, so partially redefine them here.
*/
struct ofono_voicecall {
GSList *call_list;
/* ... */
};
struct ril_voicecall_request_data *ril_voicecall_request_data_new
(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall_request_data *req =
g_slice_new0(struct ril_voicecall_request_data);
struct voicecall {
struct ofono_call *call;
/* ... */
};
req->ref_count = 1;
req->vc = vc;
req->cb = cb;
req->data = data;
return req;
}
static void ril_voicecall_request_data_unref
(struct ril_voicecall_request_data *req)
{
if (!--req->ref_count) {
g_slice_free(struct ril_voicecall_request_data, req);
}
}
static void ril_voicecall_request_data_free(gpointer data)
{
ril_voicecall_request_data_unref(data);
}
static inline struct ril_voicecall *ril_voicecall_get_data(
struct ofono_voicecall *vc)
@@ -166,38 +185,76 @@ static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
}
/* Valid call statuses have value >= 0 */
static int call_status_with_id(struct ofono_voicecall *vc, int id)
static int ril_voicecall_status_with_id(struct ofono_voicecall *vc,
unsigned int id)
{
GSList *l;
struct voicecall *v;
struct ofono_call *call = ofono_voicecall_find_call(vc, id);
GASSERT(vc);
return call ? call->status : -1;
}
for (l = vc->call_list; l; l = l->next) {
v = l->data;
if (v->call->id == id) {
return v->call->status;
/* Tries to parse the payload as a uint followed by a string */
static int ril_voicecall_parse_lastcause_1(const void *data, guint len)
{
int result = -1;
if (len > 8) {
int code;
char *msg = NULL;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &code) && code >= 0 &&
(msg = grilio_parser_get_utf8(&rilp)) &&
grilio_parser_at_end(&rilp)) {
DBG("%d \"%s\"", code, msg);
result = code;
}
g_free(msg);
}
return -1;
return result;
}
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct lastcause_req *reqdata = user_data;
struct ofono_voicecall *vc = reqdata->vc;
int tmp;
struct ril_voicecall *vd = reqdata->vd;
struct ofono_voicecall *vc = vd->vc;
int id = reqdata->id;
int call_status;
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
grilio_parser_get_int32(&rilp, &last_cause);
int last_cause;
/*
* According to ril.h:
*
* "response" is a "int *"
* ((int *)response)[0] is RIL_LastCallFailCause. GSM failure
* reasons are mapped to cause codes defined in TS 24.008 Annex H
* where possible.
*
* However some RILs feel free to invent their own formats,
* try those first.
*/
last_cause = ril_voicecall_parse_lastcause_1(data, len);
if (last_cause < 0) {
GRilIoParser rilp;
int num, code;
/* Default format described in ril.h */
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &num) && num == 1 &&
grilio_parser_get_int32(&rilp, &code) &&
grilio_parser_at_end(&rilp)) {
last_cause = code;
} else {
ofono_warn("Unable to parse last call fail cause");
last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
}
}
/*
@@ -208,7 +265,14 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
* from a network failure.
*/
switch (last_cause) {
if (gutil_ints_contains(vd->remote_hangup_reasons, last_cause)) {
DBG("hangup cause %d => remote hangup", last_cause);
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
} else if (gutil_ints_contains(vd->local_hangup_reasons, last_cause)) {
DBG("hangup cause %d => local hangup", last_cause);
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
} else {
switch (last_cause) {
case CALL_FAIL_UNOBTAINABLE_NUMBER:
case CALL_FAIL_NORMAL:
case CALL_FAIL_BUSY:
@@ -216,19 +280,19 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
case CALL_FAIL_CHANNEL_UNACCEPTABLE:
case CALL_FAIL_OPERATOR_DETERMINED_BARRING:
case CALL_FAIL_NO_USER_RESPONDING:
case CALL_FAIL_USER_ALERTING_NO_ANSWER:
case CALL_FAIL_NO_ANSWER_FROM_USER:
case CALL_FAIL_CALL_REJECTED:
case CALL_FAIL_NUMBER_CHANGED:
case CALL_FAIL_ANONYMOUS_CALL_REJECTION:
case CALL_FAIL_PRE_EMPTION:
case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
case CALL_FAIL_INCOMPLETE_NUMBER:
case CALL_FAIL_INVALID_NUMBER_FORMAT:
case CALL_FAIL_FACILITY_REJECTED:
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
break;
case CALL_FAIL_NORMAL_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
call_status = ril_voicecall_status_with_id(vc, id);
if (call_status == CALL_STATUS_ACTIVE ||
call_status == CALL_STATUS_HELD ||
call_status == CALL_STATUS_DIALING ||
@@ -240,9 +304,10 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
break;
case CALL_FAIL_ERROR_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
call_status = ril_voicecall_status_with_id(vc, id);
if (call_status == CALL_STATUS_DIALING ||
call_status == CALL_STATUS_ALERTING) {
call_status == CALL_STATUS_ALERTING ||
call_status == CALL_STATUS_INCOMING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
}
break;
@@ -250,6 +315,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
default:
reason = OFONO_DISCONNECT_REASON_ERROR;
break;
}
}
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
@@ -285,7 +351,9 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
struct ofono_call *oc = o ? o->data : NULL;
if (oc && (nc == NULL || (nc->id > oc->id))) {
if (vd->local_release & (1 << oc->id)) {
/* old call is gone */
if (gutil_int_array_remove_all_fast(
vd->local_release_ids, oc->id)) {
ofono_voicecall_disconnected(vd->vc, oc->id,
OFONO_DISCONNECT_REASON_LOCAL_HANGUP,
NULL);
@@ -295,7 +363,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
struct lastcause_req *reqdata =
g_new0(struct lastcause_req, 1);
reqdata->vc = vd->vc;
reqdata->vd = vd;
reqdata->id = oc->id;
grilio_queue_send_request_full(vd->q, NULL,
RIL_REQUEST_LAST_CALL_FAIL_CAUSE,
@@ -365,9 +433,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
}
g_slist_free_full(vd->calls, g_free);
vd->calls = calls;
vd->local_release = 0;
}
static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
@@ -386,52 +452,47 @@ static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
static void ril_voicecall_request_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_voicecall_change_state_req *req = user_data;
struct ril_voicecall_request_data *req = user_data;
struct ril_voicecall *vd = ril_voicecall_get_data(req->vc);
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
GSList *l;
if (req->affected_types) {
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
if (req->affected_types & (1 << call->status)) {
vd->local_release |= (1 << call->id);
}
}
}
ril_error_init_ok(&error);
} else {
ofono_error("generic fail");
ril_error_init_failure(&error);
}
ril_voicecall_clcc_poll(vd);
/* We have to callback after we schedule a poll if required */
if (req->cb) {
/*
* The ofono API call is considered successful if at least one
* associated RIL request succeeds.
*/
if (status == RIL_E_SUCCESS) {
req->success++;
}
/*
* Only invoke the callback if this is the last request associated
* with this ofono api call (pending call count becomes zero).
*/
GASSERT(req->pending_call_count > 0);
if (!--req->pending_call_count && req->cb) {
struct ofono_error error;
if (req->success) {
ril_error_init_ok(&error);
} else {
ril_error_init_failure(&error);
}
req->cb(&error, req->data);
}
}
static void ril_voicecall_request(const guint rreq, struct ofono_voicecall *vc,
unsigned int affected_types, GRilIoRequest *ioreq,
ofono_voicecall_cb_t cb, void *data)
static void ril_voicecall_request(const guint code, struct ofono_voicecall *vc,
GRilIoRequest *req, ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ril_voicecall_change_state_req *req;
struct ril_voicecall_request_data *req_data =
ril_voicecall_request_data_new(vc, cb, data);
req = g_new0(struct ril_voicecall_change_state_req, 1);
req->vc = vc;
req->cb = cb;
req->data = data;
req->affected_types = affected_types;
grilio_queue_send_request_full(vd->q, ioreq, rreq,
ril_voicecall_request_cb, g_free, req);
req_data->pending_call_count++;
grilio_queue_send_request_full(ril_voicecall_get_data(vc)->q, req,
code, ril_voicecall_request_cb,
ril_voicecall_request_data_free, req_data);
}
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
@@ -489,47 +550,68 @@ static void ril_voicecall_dial(struct ofono_voicecall *vc,
grilio_request_unref(req);
}
static void ril_voicecall_submit_hangup_req(struct ofono_voicecall *vc,
int id, struct ril_voicecall_request_data *req)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
GRilIoRequest *ioreq = grilio_request_array_int32_new(1, id);
/* Append the call id to the list of calls being released locally */
GASSERT(!gutil_int_array_contains(vd->local_release_ids, id));
gutil_int_array_append(vd->local_release_ids, id);
/* Send request to RIL. ril_voicecall_request_data_free will unref
* the request data */
req->ref_count++;
req->pending_call_count++;
grilio_queue_send_request_full(vd->q, ioreq, RIL_REQUEST_HANGUP,
ril_voicecall_request_cb,
ril_voicecall_request_data_free, req);
grilio_request_unref(ioreq);
}
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ofono_error error;
GSList *l;
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
GRilIoRequest *req = grilio_request_sized_new(8);
if (vd->calls) {
GSList *l;
struct ril_voicecall_request_data *req =
ril_voicecall_request_data_new(vc, cb, data);
/* TODO: Hangup just the active ones once we have call
* state tracking (otherwise it can't handle ringing) */
DBG("Hanging up call with id %d", call->id);
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
grilio_request_append_int32(req, call->id);
/*
* Here the idea is that we submit (potentially) multiple
* hangup requests to RIL and invoke the callback after
* the last request has completed (pending call count
* becomes zero).
*/
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
/* Send request to RIL */
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req,
NULL, NULL);
grilio_request_unref(req);
/* Send request to RIL */
DBG("Hanging up call with id %d", call->id);
ril_voicecall_submit_hangup_req(vc, call->id, req);
}
/* Release our reference */
ril_voicecall_request_data_unref(req);
} else {
/* No calls */
struct ofono_error error;
cb(ril_error_ok(&error), data);
}
/* TODO: Deal in case of an error at hungup */
cb(ril_error_ok(&error), data);
}
static void ril_voicecall_hangup_specific(struct ofono_voicecall *vc,
static void ril_voicecall_release_specific(struct ofono_voicecall *vc,
int id, ofono_voicecall_cb_t cb, void *data)
{
GRilIoRequest *req = grilio_request_sized_new(8);
struct ofono_error error;
struct ril_voicecall_request_data *req =
ril_voicecall_request_data_new(vc, cb, data);
DBG("Hanging up call with id %d", id);
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
grilio_request_append_int32(req, id);
/* Send request to RIL */
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req, NULL, NULL);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
ril_voicecall_submit_hangup_req(vc, id, req);
ril_voicecall_request_data_unref(req);
}
static void ril_voicecall_call_state_changed_event(GRilIoChannel *io,
@@ -584,7 +666,7 @@ static void ril_voicecall_answer(struct ofono_voicecall *vc,
{
/* Send request to RIL */
DBG("Answering current call");
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, 0, NULL, cb, data);
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, NULL, cb, data);
}
static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
@@ -653,29 +735,25 @@ static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd)
static void ril_voicecall_create_multiparty(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_CONFERENCE,
vc, 0, NULL, cb, data);
ril_voicecall_request(RIL_REQUEST_CONFERENCE, vc, NULL, cb, data);
}
static void ril_voicecall_transfer(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_EXPLICIT_CALL_TRANSFER,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
ofono_voicecall_cb_t cb, void *data)
{
GRilIoRequest *req = grilio_request_sized_new(8);
GRilIoRequest *req = grilio_request_array_int32_new(1, id);
struct ofono_error error;
DBG("Private chat with id %d", id);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, id);
ril_voicecall_request(RIL_REQUEST_SEPARATE_CONNECTION,
vc, 0, req, NULL, NULL);
vc, req, NULL, NULL);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
}
@@ -683,51 +761,52 @@ static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
static void ril_voicecall_swap_without_accept(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_hold_all_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_release_all_held(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_release_all_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
vc, 0, NULL, cb, data);
vc, NULL, cb, data);
}
static gboolean ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
static void ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
{
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1); /* size of array */
grilio_request_append_int32(req, 1); /* notifications enabled */
GRilIoRequest *req = grilio_request_array_int32_new(1, 1);
grilio_request_set_timeout(req, VOICECALL_BLOCK_TIMEOUT_MS);
grilio_request_set_blocking(req, TRUE);
grilio_queue_send_request(vd->q, req,
RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION);
grilio_request_unref(req);
/* Makes this a single shot */
return FALSE;
}
static void ril_voicecall_ringback_tone_event(GRilIoChannel *io,
@@ -755,12 +834,10 @@ static void ril_voicecall_ecclist_changed(struct ril_ecclist *list, void *data)
ofono_voicecall_en_list_notify(vd->vc, vd->ecclist->list);
}
static gboolean ril_delayed_register(gpointer user_data)
static void ril_voicecall_register(gpointer user_data)
{
struct ril_voicecall *vd = user_data;
GASSERT(vd->timer_id);
vd->timer_id = 0;
ofono_voicecall_register(vd->vc);
/* Emergency Call Codes */
@@ -794,15 +871,13 @@ static gboolean ril_delayed_register(gpointer user_data)
grilio_channel_add_unsol_event_handler(vd->io,
ril_voicecall_ringback_tone_event,
RIL_UNSOL_RINGBACK_TONE, vd);
/* This makes the timeout a single-shot */
return FALSE;
}
static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
const struct ril_slot_config *cfg = &modem->config;
struct ril_voicecall *vd;
DBG("");
@@ -810,13 +885,17 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
vd->io = grilio_channel_ref(ril_modem_io(modem));
vd->q = grilio_queue_new(vd->io);
vd->dtmf_queue = gutil_ring_new();
vd->local_hangup_reasons = gutil_ints_ref(cfg->local_hangup_reasons);
vd->remote_hangup_reasons = gutil_ints_ref(cfg->remote_hangup_reasons);
vd->local_release_ids = gutil_int_array_new();
vd->idleq = gutil_idle_queue_new();
vd->vc = vc;
vd->timer_id = g_idle_add(ril_delayed_register, vd);
if (modem->ecclist_file) {
vd->ecclist = ril_ecclist_new(modem->ecclist_file);
}
ril_voicecall_clear_dtmf_queue(vd);
ofono_voicecall_set_data(vc, vd);
gutil_idle_queue_add(vd->idleq, ril_voicecall_register, vd);
return 0;
}
@@ -828,10 +907,6 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
ofono_voicecall_set_data(vc, NULL);
g_slist_free_full(vd->calls, g_free);
if (vd->timer_id > 0) {
g_source_remove(vd->timer_id);
}
ril_ecclist_remove_handler(vd->ecclist, vd->ecclist_change_id);
ril_ecclist_unref(vd->ecclist);
@@ -841,6 +916,10 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
grilio_queue_cancel_all(vd->q, FALSE);
grilio_queue_unref(vd->q);
gutil_ring_unref(vd->dtmf_queue);
gutil_ints_unref(vd->local_hangup_reasons);
gutil_ints_unref(vd->remote_hangup_reasons);
gutil_int_array_free(vd->local_release_ids, TRUE);
gutil_idle_queue_free(vd->idleq);
g_free(vd);
}
@@ -851,7 +930,7 @@ const struct ofono_voicecall_driver ril_voicecall_driver = {
.dial = ril_voicecall_dial,
.answer = ril_voicecall_answer,
.hangup_all = ril_voicecall_hangup_all,
.release_specific = ril_voicecall_hangup_specific,
.release_specific = ril_voicecall_release_specific,
.send_tones = ril_voicecall_send_dtmf,
.create_multiparty = ril_voicecall_create_multiparty,
.transfer = ril_voicecall_transfer,

View File

@@ -261,6 +261,7 @@ static void ublox_send_uauthreq(struct ofono_gprs_context *gc,
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = 1;
break;
case OFONO_GPRS_AUTH_METHOD_ANY:
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = 2;
break;

View File

@@ -49,7 +49,9 @@ enum ofono_gprs_context_type {
};
enum ofono_gprs_auth_method {
OFONO_GPRS_AUTH_METHOD_CHAP = 0,
OFONO_GPRS_AUTH_METHOD_ANY = 0,
OFONO_GPRS_AUTH_METHOD_NONE,
OFONO_GPRS_AUTH_METHOD_CHAP,
OFONO_GPRS_AUTH_METHOD_PAP,
};

View File

@@ -71,11 +71,12 @@ struct ofono_debug_desc {
.file = __FILE__, .flags = OFONO_DEBUG_FLAG_DEFAULT, \
}; \
if (__ofono_debug_desc.flags & OFONO_DEBUG_FLAG_PRINT) \
__ofono_dbg(&__ofono_debug_desc, "%s() " fmt, \
ofono_dbg(&__ofono_debug_desc, "%s() " fmt, \
__FUNCTION__ , ## arg); \
} while (0)
void __ofono_dbg(const struct ofono_debug_desc *desc, const char *format, ...)
extern void ofono_dbg(const struct ofono_debug_desc *desc,
const char *format, ...)
__attribute__((format(printf, 2, 3)));
typedef void (*ofono_log_hook_cb_t)(const struct ofono_debug_desc *desc,

View File

@@ -114,6 +114,7 @@ int ofono_netreg_get_status(struct ofono_netreg *netreg);
int ofono_netreg_get_technology(struct ofono_netreg *netreg);
const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg);
const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg);
const char *ofono_netreg_get_name(struct ofono_netreg *netreg);
struct sim_spdi *ofono_netreg_get_spdi(struct ofono_netreg *netreg);
#ifdef __cplusplus

View File

@@ -0,0 +1,114 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef SAILFISH_CELL_INFO_H
#define SAILFISH_CELL_INFO_H
#include <glib.h>
enum sailfish_cell_type {
SAILFISH_CELL_TYPE_GSM,
SAILFISH_CELL_TYPE_WCDMA,
SAILFISH_CELL_TYPE_LTE
};
struct sailfish_cell_info_gsm {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int lac; /* Location Area Code (0..65535) */
int cid; /* GSM Cell Identity (0..65535) TS 27.007 */
int arfcn; /* 16-bit GSM Absolute RF channel number */
int bsic; /* 6-bit Base Station Identity Code */
int signalStrength; /* (0-31, 99) TS 27.007 */
int bitErrorRate; /* (0-7, 99) TS 27.007 */
int timingAdvance; /* Timing Advance. 1 period = 48/13 us */
};
struct sailfish_cell_info_wcdma {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int lac; /* Location Area Code (0..65535) */
int cid; /* UMTS Cell Identity (0..268435455) TS 25.331 */
int psc; /* Primary Scrambling Code (0..511) TS 25.331) */
int uarfcn; /* 16-bit UMTS Absolute RF Channel Number */
int signalStrength; /* (0-31, 99) TS 27.007 */
int bitErrorRate; /* (0-7, 99) TS 27.007 */
};
struct sailfish_cell_info_lte {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int ci; /* Cell Identity */
int pci; /* Physical cell id (0..503) */
int tac; /* Tracking area code */
int earfcn; /* 18-bit LTE Absolute RC Channel Number */
int signalStrength; /* (0-31, 99) TS 27.007 8.5 */
int rsrp; /* Reference Signal Receive Power TS 36.133 */
int rsrq; /* Reference Signal Receive Quality TS 36.133 */
int rssnr; /* Reference Signal-to-Noise Ratio TS 36.101*/
int cqi; /* Channel Quality Indicator TS 36.101 */
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
};
struct sailfish_cell {
enum sailfish_cell_type type;
gboolean registered;
union {
struct sailfish_cell_info_gsm gsm;
struct sailfish_cell_info_wcdma wcdma;
struct sailfish_cell_info_lte lte;
} info;
};
struct sailfish_cell_info {
const struct sailfish_cell_info_proc *proc;
GSList *cells;
};
typedef void (*sailfish_cell_info_cb_t)(struct sailfish_cell_info *info,
void *arg);
struct sailfish_cell_info_proc {
void (*ref)(struct sailfish_cell_info *info);
void (*unref)(struct sailfish_cell_info *info);
gulong (*add_cells_changed_handler)(struct sailfish_cell_info *info,
sailfish_cell_info_cb_t cb, void *arg);
void (*remove_handler)(struct sailfish_cell_info *info, gulong id);
};
/* Utilities */
gint sailfish_cell_compare_func(gconstpointer v1, gconstpointer v2);
gint sailfish_cell_compare_location(const struct sailfish_cell *c1,
const struct sailfish_cell *c2);
/* Cell info object API */
struct sailfish_cell_info *sailfish_cell_info_ref
(struct sailfish_cell_info *info);
void sailfish_cell_info_unref(struct sailfish_cell_info *info);
gulong sailfish_cell_info_add_cells_changed_handler
(struct sailfish_cell_info *info,
sailfish_cell_info_cb_t cb, void *arg);
void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
gulong id);
#endif /* SAILFISH_CELINFO_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,125 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef SAILFISH_MANAGER_H
#define SAILFISH_MANAGER_H
struct ofono_modem;
#include <ofono/types.h>
#include <ofono/radio-settings.h>
#include <glib.h>
struct sailfish_manager;
struct sailfish_slot;
struct sailfish_slot_impl;
struct sailfish_slot_driver;
struct sailfish_slot_driver_reg;
struct sailfish_slot_manager;
struct sailfish_slot_manager_impl;
struct sailfish_cell_info;
typedef void (*sailfish_slot_manager_impl_cb_t)
(struct sailfish_slot_manager_impl *impl, void *user_data);
typedef struct sailfish_slot {
const char *path;
const char *imei;
const char *imeisv;
gboolean sim_present;
gboolean enabled;
} const *sailfish_slot_ptr;
struct sailfish_manager {
const char *mms_imsi;
const char *mms_path;
const char *default_voice_imsi;
const char *default_data_imsi;
const char *default_voice_path;
const char *default_data_path;
const sailfish_slot_ptr *slots;
gboolean ready;
};
enum sailfish_sim_state {
SAILFISH_SIM_STATE_UNKNOWN,
SAILFISH_SIM_STATE_ABSENT,
SAILFISH_SIM_STATE_PRESENT,
SAILFISH_SIM_STATE_ERROR
};
enum sailfish_data_role {
SAILFISH_DATA_ROLE_NONE, /* Data not allowed */
SAILFISH_DATA_ROLE_MMS, /* Data is allowed at any speed */
SAILFISH_DATA_ROLE_INTERNET /* Data is allowed at full speed */
};
/* Register/unregister the driver */
struct sailfish_slot_driver_reg *sailfish_slot_driver_register
(const struct sailfish_slot_driver *d);
void sailfish_slot_driver_unregister(struct sailfish_slot_driver_reg *r);
/* For use by the driver implementations */
void sailfish_manager_foreach_slot_manager
(struct sailfish_slot_driver_reg *r,
sailfish_slot_manager_impl_cb_t cb, void *user_data);
struct sailfish_slot *sailfish_manager_slot_add
(struct sailfish_slot_manager *m, struct sailfish_slot_impl *i,
const char *path, enum ofono_radio_access_mode techs,
const char *imei, const char *imeisv,
enum sailfish_sim_state sim_state);
void sailfish_manager_imei_obtained(struct sailfish_slot *s, const char *imei);
void sailfish_manager_imeisv_obtained(struct sailfish_slot *s,
const char *imeisv);
void sailfish_manager_set_sim_state(struct sailfish_slot *s,
enum sailfish_sim_state state);
void sailfish_slot_manager_started(struct sailfish_slot_manager *m);
void sailfish_manager_slot_error(struct sailfish_slot *s, const char *key,
const char *message);
void sailfish_manager_error(struct sailfish_slot_manager *m, const char *key,
const char *message);
void sailfish_manager_set_cell_info(struct sailfish_slot *s,
struct sailfish_cell_info *ci);
/* Callbacks provided by slot plugins */
struct sailfish_slot_driver {
const char *name;
int priority;
/* Slot manager methods */
struct sailfish_slot_manager_impl *(*manager_create)
(struct sailfish_slot_manager *m);
guint (*manager_start)(struct sailfish_slot_manager_impl *s);
void (*manager_cancel_start)(struct sailfish_slot_manager_impl *s,
guint id);
void (*manager_free)(struct sailfish_slot_manager_impl *s);
/* Slot methods */
void (*slot_enabled_changed)(struct sailfish_slot_impl *s);
void (*slot_set_data_role)(struct sailfish_slot_impl *s,
enum sailfish_data_role role);
void (*slot_free)(struct sailfish_slot_impl *s);
};
#endif /* SAILFISH_MANAGER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,81 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef SAILFISH_WATCH_H
#define SAILFISH_WATCH_H
struct ofono_modem;
struct ofono_sim;
struct ofono_netreg;
#include <glib.h>
#include <glib-object.h>
/* This object watches ofono modem and various related things */
struct sailfish_watch_priv;
struct sailfish_watch {
GObject object;
struct sailfish_watch_priv *priv;
const char *path;
/* Modem */
struct ofono_modem *modem;
gboolean online;
/* OFONO_ATOM_TYPE_SIM */
struct ofono_sim *sim;
const char *iccid;
const char *imsi;
const char *spn;
/* OFONO_ATOM_TYPE_NETREG */
struct ofono_netreg *netreg;
};
typedef void (*sailfish_watch_cb_t)(struct sailfish_watch *w, void *user_data);
struct sailfish_watch *sailfish_watch_new(const char *path);
struct sailfish_watch *sailfish_watch_ref(struct sailfish_watch *w);
void sailfish_watch_unref(struct sailfish_watch *w);
gulong sailfish_watch_add_modem_changed_handler(struct sailfish_watch *w,
sailfish_watch_cb_t cb, void *user_data);
gulong sailfish_watch_add_online_changed_handler(struct sailfish_watch *w,
sailfish_watch_cb_t cb, void *user_data);
gulong sailfish_watch_add_sim_changed_handler(struct sailfish_watch *w,
sailfish_watch_cb_t cb, void *user_data);
gulong sailfish_watch_add_sim_state_changed_handler(struct sailfish_watch *w,
sailfish_watch_cb_t cb, void *user_data);
gulong sailfish_watch_add_iccid_changed_handler(struct sailfish_watch *w,
sailfish_watch_cb_t cb, void *user_data);
gulong sailfish_watch_add_imsi_changed_handler(struct sailfish_watch *w,
sailfish_watch_cb_t cb, void *user_data);
gulong sailfish_watch_add_spn_changed_handler(struct sailfish_watch *w,
sailfish_watch_cb_t cb, void *user_data);
gulong sailfish_watch_add_netreg_changed_handler(struct sailfish_watch *w,
sailfish_watch_cb_t cb, void *user_data);
void sailfish_watch_remove_handler(struct sailfish_watch *w, gulong id);
void sailfish_watch_remove_handlers(struct sailfish_watch *w, gulong *ids,
int count);
#define sailfish_watch_remove_all_handlers(w,ids) \
sailfish_watch_remove_handlers(w, ids, G_N_ELEMENTS(ids))
#endif /* SAILFISH_WATCH_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

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

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -53,6 +54,9 @@ const char *mbpi_database = MBPI_DATABASE;
enum ofono_gprs_proto mbpi_default_internet_proto = OFONO_GPRS_PROTO_IPV4V6;
enum ofono_gprs_proto mbpi_default_mms_proto = OFONO_GPRS_PROTO_IP;
enum ofono_gprs_proto mbpi_default_proto = OFONO_GPRS_PROTO_IP;
enum ofono_gprs_auth_method mbpi_default_auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
#define OFONO_GPRS_AUTH_METHOD_UNSPECIFIED ((enum ofono_gprs_auth_method)(-1))
#define _(x) case x: return (#x)
@@ -142,6 +146,39 @@ static const GMarkupParser text_parser = {
NULL,
};
static void protocol_start(GMarkupParseContext *context,
const gchar **attribute_names,
const gchar **attribute_values,
enum ofono_gprs_proto *proto,
GError **error)
{
const char *text = NULL;
int i;
for (i = 0; attribute_names[i]; i++)
if (g_str_equal(attribute_names[i], "type") == TRUE)
text = attribute_values[i];
if (text == NULL) {
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"Missing attribute: type");
return;
}
if (strcmp(text, "ip") == 0)
*proto = OFONO_GPRS_PROTO_IP;
else if (strcmp(text, "ipv6") == 0)
*proto = OFONO_GPRS_PROTO_IPV6;
else if (strcmp(text, "ipv4v6") == 0)
*proto = OFONO_GPRS_PROTO_IPV4V6;
else
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
"Unknown authentication method: %s",
text);
}
static void authentication_start(GMarkupParseContext *context,
const gchar **attribute_names,
const gchar **attribute_values,
@@ -166,6 +203,10 @@ static void authentication_start(GMarkupParseContext *context,
*auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
else if (strcmp(text, "pap") == 0)
*auth_method = OFONO_GPRS_AUTH_METHOD_PAP;
else if (strcmp(text, "any") == 0)
*auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
else if (strcmp(text, "none") == 0)
*auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
else
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
@@ -221,6 +262,9 @@ static void apn_start(GMarkupParseContext *context, const gchar *element_name,
else if (g_str_equal(element_name, "password"))
g_markup_parse_context_push(context, &text_parser,
&apn->password);
else if (g_str_equal(element_name, "protocol"))
protocol_start(context, attribute_names,
attribute_values, &apn->proto, error);
else if (g_str_equal(element_name, "authentication"))
authentication_start(context, attribute_names,
attribute_values, &apn->auth_method, error);
@@ -344,7 +388,7 @@ static void apn_handler(GMarkupParseContext *context, struct gsm_data *gsm,
ap->apn = g_strdup(apn);
ap->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
ap->proto = mbpi_default_proto;
ap->auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
ap->auth_method = OFONO_GPRS_AUTH_METHOD_UNSPECIFIED;
g_markup_parse_context_push(context, &apn_parser, ap);
}
@@ -414,6 +458,17 @@ static void gsm_end(GMarkupParseContext *context, const gchar *element_name,
if (ap == NULL)
return;
/* Fix the authentication method if none was specified */
if (ap->auth_method == OFONO_GPRS_AUTH_METHOD_UNSPECIFIED) {
if ((!ap->username || !ap->username[0]) &&
(!ap->password || !ap->password[0])) {
/* No username or password => no authentication */
ap->auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
} else {
ap->auth_method = mbpi_default_auth_method;
}
}
if (gsm->allow_duplicates == FALSE) {
GSList *l;

View File

@@ -23,6 +23,7 @@ extern const char *mbpi_database;
extern enum ofono_gprs_proto mbpi_default_internet_proto;
extern enum ofono_gprs_proto mbpi_default_mms_proto;
extern enum ofono_gprs_proto mbpi_default_proto;
extern enum ofono_gprs_auth_method mbpi_default_auth_method;
const char *mbpi_ap_type(enum ofono_gprs_context_type type);

View File

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

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

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

View File

@@ -0,0 +1,129 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <sailfish_cell_info.h>
#include <gutil_log.h>
gint sailfish_cell_compare_location(const struct sailfish_cell *c1,
const struct sailfish_cell *c2)
{
if (c1 && c2) {
if (c1->type != c2->type) {
return c1->type - c2->type;
} else if (c1->type == SAILFISH_CELL_TYPE_GSM) {
const struct sailfish_cell_info_gsm *g1;
const struct sailfish_cell_info_gsm *g2;
g1 = &c1->info.gsm;
g2 = &c2->info.gsm;
if (g1->mcc != g2->mcc) {
return g1->mcc - g2->mcc;
} else if (g1->mnc != g2->mnc) {
return g1->mnc - g2->mnc;
} else if (g1->lac != g2->lac) {
return g1->lac - g2->lac;
} else {
return g1->cid - g2->cid;
}
} else if (c2->type == SAILFISH_CELL_TYPE_WCDMA) {
const struct sailfish_cell_info_wcdma *w1;
const struct sailfish_cell_info_wcdma *w2;
w1 = &c1->info.wcdma;
w2 = &c2->info.wcdma;
if (w1->mcc != w2->mcc) {
return w1->mcc - w2->mcc;
} else if (w1->mnc != w2->mnc) {
return w1->mnc - w2->mnc;
} else if (w1->lac != w2->lac) {
return w1->lac - w2->lac;
} else {
return w1->cid - w2->cid;
}
} else {
const struct sailfish_cell_info_lte *l1 =
&c1->info.lte;
const struct sailfish_cell_info_lte *l2 =
&c2->info.lte;
GASSERT(c1->type == SAILFISH_CELL_TYPE_LTE);
l1 = &c1->info.lte;
l2 = &c2->info.lte;
if (l1->mcc != l2->mcc) {
return l1->mcc - l2->mcc;
} else if (l1->mnc != l2->mnc) {
return l1->mnc - l2->mnc;
} else if (l1->ci != l2->ci) {
return l1->ci - l2->ci;
} else if (l1->pci != l2->pci) {
return l1->pci - l2->pci;
} else {
return l1->tac - l2->tac;
}
}
} else if (c1) {
return 1;
} else if (c2) {
return -1;
} else {
return 0;
}
}
gint sailfish_cell_compare_func(gconstpointer v1, gconstpointer v2)
{
return sailfish_cell_compare_location(v1, v2);
}
struct sailfish_cell_info *sailfish_cell_info_ref
(struct sailfish_cell_info *info)
{
if (info) {
info->proc->ref(info);
return info;
}
return NULL;
}
void sailfish_cell_info_unref(struct sailfish_cell_info *info)
{
if (info) {
info->proc->unref(info);
}
}
gulong sailfish_cell_info_add_cells_changed_handler
(struct sailfish_cell_info *info,
sailfish_cell_info_cb_t cb, void *arg)
{
return info ? info->proc->add_cells_changed_handler(info, cb, arg) : 0;
}
void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
gulong id)
{
if (info) {
info->proc->remove_handler(info, id);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,598 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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_cell_info_dbus.h"
#include "sailfish_cell_info.h"
#include <ofono/modem.h>
#include <ofono/dbus.h>
#include <ofono/log.h>
#include <gdbus.h>
struct sailfish_cell_entry {
guint cell_id;
char *path;
struct sailfish_cell cell;
};
struct sailfish_cell_info_dbus {
struct sailfish_cell_info *info;
DBusConnection *conn;
char *path;
gulong handler_id;
guint next_cell_id;
GSList *entries;
};
#define CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
#define CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
#define CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
#define CELL_DBUS_INTERFACE_VERSION (1)
#define CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
#define CELL_DBUS_REGISTERED_CHANGED_SIGNAL "RegisteredChanged"
#define CELL_DBUS_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
#define CELL_DBUS_REMOVED_SIGNAL "Removed"
struct sailfish_cell_property {
const char *name;
glong off;
int flag;
};
#define CELL_GSM_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct sailfish_cell_info_gsm,name), value }
#define CELL_WCDMA_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct sailfish_cell_info_wcdma,name), value }
#define CELL_LTE_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct sailfish_cell_info_lte,name), value }
static const struct sailfish_cell_property sailfish_cell_gsm_properties [] = {
CELL_GSM_PROPERTY(0x001,mcc),
CELL_GSM_PROPERTY(0x002,mnc),
CELL_GSM_PROPERTY(0x004,lac),
CELL_GSM_PROPERTY(0x008,cid),
CELL_GSM_PROPERTY(0x010,arfcn),
CELL_GSM_PROPERTY(0x020,bsic),
CELL_GSM_PROPERTY(0x040,signalStrength),
CELL_GSM_PROPERTY(0x080,bitErrorRate),
CELL_GSM_PROPERTY(0x100,timingAdvance)
};
static const struct sailfish_cell_property sailfish_cell_wcdma_properties [] = {
CELL_WCDMA_PROPERTY(0x01,mcc),
CELL_WCDMA_PROPERTY(0x02,mnc),
CELL_WCDMA_PROPERTY(0x04,lac),
CELL_WCDMA_PROPERTY(0x08,cid),
CELL_WCDMA_PROPERTY(0x10,psc),
CELL_WCDMA_PROPERTY(0x20,uarfcn),
CELL_WCDMA_PROPERTY(0x40,signalStrength),
CELL_WCDMA_PROPERTY(0x80,bitErrorRate)
};
static const struct sailfish_cell_property sailfish_cell_lte_properties [] = {
CELL_LTE_PROPERTY(0x001,mcc),
CELL_LTE_PROPERTY(0x002,mnc),
CELL_LTE_PROPERTY(0x004,ci),
CELL_LTE_PROPERTY(0x008,pci),
CELL_LTE_PROPERTY(0x010,tac),
CELL_LTE_PROPERTY(0x020,earfcn),
CELL_LTE_PROPERTY(0x040,signalStrength),
CELL_LTE_PROPERTY(0x080,rsrp),
CELL_LTE_PROPERTY(0x100,rsrq),
CELL_LTE_PROPERTY(0x200,rssnr),
CELL_LTE_PROPERTY(0x400,cqi),
CELL_LTE_PROPERTY(0x800,timingAdvance)
};
#define SAILFISH_CELL_PROPERTY_REGISTERED 0x1000
typedef void (*sailfish_cell_info_dbus_append_fn)(DBusMessageIter *it,
const struct sailfish_cell_entry *entry);
static const char *sailfish_cell_info_dbus_cell_type_str
(enum sailfish_cell_type type)
{
switch (type) {
case SAILFISH_CELL_TYPE_GSM:
return "gsm";
case SAILFISH_CELL_TYPE_WCDMA:
return "wcdma";
case SAILFISH_CELL_TYPE_LTE:
return "lte";
default:
return "unknown";
}
};
static const struct sailfish_cell_property *
sailfish_cell_info_dbus_cell_properties(
enum sailfish_cell_type type, int *count)
{
switch (type) {
case SAILFISH_CELL_TYPE_GSM:
*count = G_N_ELEMENTS(sailfish_cell_gsm_properties);
return sailfish_cell_gsm_properties;
case SAILFISH_CELL_TYPE_WCDMA:
*count = G_N_ELEMENTS(sailfish_cell_wcdma_properties);
return sailfish_cell_wcdma_properties;
case SAILFISH_CELL_TYPE_LTE:
*count = G_N_ELEMENTS(sailfish_cell_lte_properties);
return sailfish_cell_lte_properties;
default:
*count = 0;
return NULL;
}
};
static void sailfish_cell_info_destroy_entry(struct sailfish_cell_entry *entry)
{
if (entry) {
g_free(entry->path);
g_free(entry);
}
}
static DBusMessage *sailfish_cell_info_dbus_reply(DBusMessage *msg,
const struct sailfish_cell_entry *entry,
sailfish_cell_info_dbus_append_fn append)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it;
dbus_message_iter_init_append(reply, &it);
append(&it, entry);
return reply;
}
static void sailfish_cell_info_dbus_append_version(DBusMessageIter *it,
const struct sailfish_cell_entry *entry)
{
dbus_int32_t version = CELL_DBUS_INTERFACE_VERSION;
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
}
static void sailfish_cell_info_dbus_append_type(DBusMessageIter *it,
const struct sailfish_cell_entry *entry)
{
const char *type =
sailfish_cell_info_dbus_cell_type_str(entry->cell.type);
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &type);
}
static void sailfish_cell_info_dbus_append_registered(DBusMessageIter *it,
const struct sailfish_cell_entry *entry)
{
dbus_bool_t registered = entry->cell.registered;
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &registered);
}
static void sailfish_cell_info_dbus_append_properties(DBusMessageIter *it,
const struct sailfish_cell_entry *entry)
{
int i, n;
DBusMessageIter dict;
const struct sailfish_cell *cell = &entry->cell;
const struct sailfish_cell_property *prop =
sailfish_cell_info_dbus_cell_properties(cell->type, &n);
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &dict);
for (i = 0; i < n; i++) {
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
if (value != INT_MAX) {
ofono_dbus_dict_append(&dict, prop[i].name,
DBUS_TYPE_INT32, &value);
}
}
dbus_message_iter_close_container(it, &dict);
}
static void sailfish_cell_info_dbus_append_all(DBusMessageIter *it,
const struct sailfish_cell_entry *entry)
{
sailfish_cell_info_dbus_append_version(it, entry);
sailfish_cell_info_dbus_append_type(it, entry);
sailfish_cell_info_dbus_append_registered(it, entry);
sailfish_cell_info_dbus_append_properties(it, entry);
}
static DBusMessage *sailfish_cell_info_dbus_cell_get_all
(DBusConnection *conn, DBusMessage *msg, void *data)
{
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
data, sailfish_cell_info_dbus_append_all);
}
static DBusMessage *sailfish_cell_info_dbus_cell_get_version
(DBusConnection *conn, DBusMessage *msg, void *data)
{
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
data, sailfish_cell_info_dbus_append_version);
}
static DBusMessage *sailfish_cell_info_dbus_cell_get_type
(DBusConnection *conn, DBusMessage *msg, void *data)
{
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
data, sailfish_cell_info_dbus_append_type);
}
static DBusMessage *sailfish_cell_info_dbus_cell_get_registered
(DBusConnection *conn, DBusMessage *msg, void *data)
{
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
data, sailfish_cell_info_dbus_append_registered);
}
static DBusMessage *sailfish_cell_info_dbus_cell_get_properties
(DBusConnection *conn, DBusMessage *msg, void *data)
{
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
data, sailfish_cell_info_dbus_append_properties);
}
static const GDBusMethodTable sailfish_cell_info_dbus_cell_methods[] = {
{ GDBUS_METHOD("GetAll", NULL,
GDBUS_ARGS({ "version", "i" },
{ "type", "s" },
{ "registered", "b" },
{ "properties", "a{sv}" }),
sailfish_cell_info_dbus_cell_get_all) },
{ GDBUS_METHOD("GetInterfaceVersion", NULL,
GDBUS_ARGS({ "version", "i" }),
sailfish_cell_info_dbus_cell_get_version) },
{ GDBUS_METHOD("GetType", NULL,
GDBUS_ARGS({ "type", "s" }),
sailfish_cell_info_dbus_cell_get_type) },
{ GDBUS_METHOD("GetRegistered", NULL,
GDBUS_ARGS({ "registered", "b" }),
sailfish_cell_info_dbus_cell_get_registered) },
{ GDBUS_METHOD("GetProperties", NULL,
GDBUS_ARGS({ "properties", "a{sv}" }),
sailfish_cell_info_dbus_cell_get_properties) },
{ }
};
static const GDBusSignalTable sailfish_cell_info_dbus_cell_signals[] = {
{ GDBUS_SIGNAL(CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
GDBUS_ARGS({ "registered", "b" })) },
{ GDBUS_SIGNAL(CELL_DBUS_PROPERTY_CHANGED_SIGNAL,
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
{ GDBUS_SIGNAL(CELL_DBUS_REMOVED_SIGNAL,
GDBUS_ARGS({})) },
{ }
};
static struct sailfish_cell_entry *sailfish_cell_info_dbus_find_id(
struct sailfish_cell_info_dbus *dbus, guint id)
{
GSList *l;
for (l = dbus->entries; l; l = l->next) {
struct sailfish_cell_entry *entry = l->data;
if (entry->cell_id == id) {
return entry;
}
}
return NULL;
}
static guint sailfish_cell_info_dbus_next_cell_id
(struct sailfish_cell_info_dbus *dbus)
{
while (sailfish_cell_info_dbus_find_id(dbus, dbus->next_cell_id)) {
dbus->next_cell_id++;
}
return dbus->next_cell_id++;
}
static struct sailfish_cell_entry *sailfish_cell_info_dbus_find_cell
(struct sailfish_cell_info_dbus *dbus,
const struct sailfish_cell *cell)
{
if (cell) {
GSList *l;
for (l = dbus->entries; l; l = l->next) {
struct sailfish_cell_entry *entry = l->data;
if (!sailfish_cell_compare_location(&entry->cell,
cell)) {
return entry;
}
}
}
return NULL;
}
static void sailfish_cell_info_dbus_emit_path_list
(struct sailfish_cell_info_dbus *dbus, const char *name,
GPtrArray *list)
{
guint i;
DBusMessageIter it, array;
DBusMessage *signal = dbus_message_new_signal(dbus->path,
CELL_INFO_DBUS_INTERFACE, name);
dbus_message_iter_init_append(signal, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
for (i = 0; i < list->len; i++) {
const char* path = list->pdata[i];
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
&path);
}
dbus_message_iter_close_container(&it, &array);
g_dbus_send_message(dbus->conn, signal);
}
static int sailfish_cell_info_dbus_compare(const struct sailfish_cell *c1,
const struct sailfish_cell *c2)
{
if (c1->type == c2->type) {
int i, n, mask = 0;
const struct sailfish_cell_property *prop =
sailfish_cell_info_dbus_cell_properties(c1->type, &n);
if (c1->registered != c2->registered) {
mask |= SAILFISH_CELL_PROPERTY_REGISTERED;
}
for (i = 0; i < n; i++) {
const glong offset = prop[i].off;
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
if (v1 != v2) {
mask |= prop[i].flag;
}
}
return mask;
} else {
return -1;
}
}
static void sailfish_cell_info_dbus_property_changed
(struct sailfish_cell_info_dbus *dbus,
const struct sailfish_cell_entry *entry, int mask)
{
int i, n;
const struct sailfish_cell *cell = &entry->cell;
const struct sailfish_cell_property *prop =
sailfish_cell_info_dbus_cell_properties(cell->type, &n);
if (mask & SAILFISH_CELL_PROPERTY_REGISTERED) {
dbus_bool_t registered = cell->registered;
g_dbus_emit_signal(dbus->conn, entry->path,
CELL_DBUS_INTERFACE,
CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
DBUS_TYPE_BOOLEAN, &registered, DBUS_TYPE_INVALID);
mask &= ~SAILFISH_CELL_PROPERTY_REGISTERED;
}
for (i = 0; i < n && mask; i++) {
if (mask & prop[i].flag) {
ofono_dbus_signal_property_changed(dbus->conn,
entry->path, CELL_DBUS_INTERFACE,
prop[i].name, DBUS_TYPE_INT32,
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
mask &= ~prop[i].flag;
}
}
}
static void sailfish_cell_info_dbus_update_entries
(struct sailfish_cell_info_dbus *dbus, gboolean emit_signals)
{
GSList *l;
GPtrArray* added = NULL;
GPtrArray* removed = NULL;
/* Remove non-existent cells */
l = dbus->entries;
while (l) {
GSList *next = l->next;
struct sailfish_cell_entry *entry = l->data;
if (!g_slist_find_custom(dbus->info->cells, &entry->cell,
sailfish_cell_compare_func)) {
DBG("%s removed", entry->path);
dbus->entries = g_slist_delete_link(dbus->entries, l);
g_dbus_emit_signal(dbus->conn, entry->path,
CELL_DBUS_INTERFACE,
CELL_DBUS_REMOVED_SIGNAL,
DBUS_TYPE_INVALID);
g_dbus_unregister_interface(dbus->conn, entry->path,
CELL_DBUS_INTERFACE);
if (emit_signals) {
if (!removed) {
removed =
g_ptr_array_new_with_free_func(
g_free);
}
/* Steal the path */
g_ptr_array_add(removed, entry->path);
entry->path = NULL;
}
sailfish_cell_info_destroy_entry(entry);
}
l = next;
}
/* Add new cells */
for (l = dbus->info->cells; l; l = l->next) {
const struct sailfish_cell *cell = l->data;
struct sailfish_cell_entry *entry =
sailfish_cell_info_dbus_find_cell(dbus, cell);
if (entry) {
if (emit_signals) {
int diff = sailfish_cell_info_dbus_compare(cell,
&entry->cell);
entry->cell = *cell;
sailfish_cell_info_dbus_property_changed(dbus,
entry, diff);
} else {
entry->cell = *cell;
}
} else {
entry = g_new0(struct sailfish_cell_entry, 1);
entry->cell = *cell;
entry->cell_id =
sailfish_cell_info_dbus_next_cell_id(dbus);
entry->path = g_strdup_printf("%s/cell_%u", dbus->path,
entry->cell_id);
dbus->entries = g_slist_append(dbus->entries, entry);
DBG("%s added", entry->path);
g_dbus_register_interface(dbus->conn, entry->path,
CELL_DBUS_INTERFACE,
sailfish_cell_info_dbus_cell_methods,
sailfish_cell_info_dbus_cell_signals, NULL,
entry, NULL);
if (emit_signals) {
if (!added) {
added = g_ptr_array_new();
}
g_ptr_array_add(added, entry->path);
}
}
}
if (removed) {
sailfish_cell_info_dbus_emit_path_list(dbus,
CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL, removed);
g_ptr_array_free(removed, TRUE);
}
if (added) {
sailfish_cell_info_dbus_emit_path_list(dbus,
CELL_INFO_DBUS_CELLS_ADDED_SIGNAL, added);
g_ptr_array_free(added, TRUE);
}
}
static void sailfish_cell_info_dbus_cells_changed_cb
(struct sailfish_cell_info *info, void *arg)
{
DBG("");
sailfish_cell_info_dbus_update_entries
((struct sailfish_cell_info_dbus *)arg, TRUE);
}
static DBusMessage *sailfish_cell_info_dbus_get_cells(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct sailfish_cell_info_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it, array;
GSList *l;
dbus_message_iter_init_append(reply, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
for (l = dbus->entries; l; l = l->next) {
const struct sailfish_cell_entry *entry = l->data;
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
&entry->path);
}
dbus_message_iter_close_container(&it, &array);
return reply;
}
static const GDBusMethodTable sailfish_cell_info_dbus_methods[] = {
{ GDBUS_METHOD("GetCells", NULL,
GDBUS_ARGS({ "paths", "ao" }),
sailfish_cell_info_dbus_get_cells) },
{ }
};
static const GDBusSignalTable sailfish_cell_info_dbus_signals[] = {
{ GDBUS_SIGNAL(CELL_INFO_DBUS_CELLS_ADDED_SIGNAL,
GDBUS_ARGS({ "paths", "ao" })) },
{ GDBUS_SIGNAL(CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
GDBUS_ARGS({ "paths", "ao" })) },
{ }
};
struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
(struct ofono_modem *modem, struct sailfish_cell_info *info)
{
if (modem && info) {
struct sailfish_cell_info_dbus *dbus =
g_new0(struct sailfish_cell_info_dbus, 1);
DBG("%s", ofono_modem_get_path(modem));
dbus->path = g_strdup(ofono_modem_get_path(modem));
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
dbus->info = sailfish_cell_info_ref(info);
dbus->handler_id =
sailfish_cell_info_add_cells_changed_handler(info,
sailfish_cell_info_dbus_cells_changed_cb, dbus);
/* Register D-Bus interface */
if (g_dbus_register_interface(dbus->conn, dbus->path,
CELL_INFO_DBUS_INTERFACE,
sailfish_cell_info_dbus_methods,
sailfish_cell_info_dbus_signals,
NULL, dbus, NULL)) {
ofono_modem_add_interface(modem,
CELL_INFO_DBUS_INTERFACE);
sailfish_cell_info_dbus_update_entries(dbus, FALSE);
return dbus;
} else {
ofono_error("CellInfo D-Bus register failed");
sailfish_cell_info_dbus_free(dbus);
}
}
return NULL;
}
void sailfish_cell_info_dbus_free(struct sailfish_cell_info_dbus *dbus)
{
if (dbus) {
GSList *l;
DBG("%s", dbus->path);
g_dbus_unregister_interface(dbus->conn, dbus->path,
CELL_INFO_DBUS_INTERFACE);
/* Unregister cells */
l = dbus->entries;
while (l) {
struct sailfish_cell_entry *entry = l->data;
g_dbus_unregister_interface(dbus->conn, entry->path,
CELL_DBUS_INTERFACE);
sailfish_cell_info_destroy_entry(entry);
l = l->next;
}
g_slist_free(dbus->entries);
dbus_connection_unref(dbus->conn);
sailfish_cell_info_remove_handler(dbus->info, dbus->handler_id);
sailfish_cell_info_unref(dbus->info);
g_free(dbus->path);
g_free(dbus);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,16 +13,19 @@
* GNU General Public License for more details.
*/
#ifndef RIL_MTU_H
#define RIL_MTU_H
#ifndef SAILFISH_CELL_INFO_DBUS_H
#define SAILFISH_CELL_INFO_DBUS_H
#include "ril_types.h"
struct ofono_modem;
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu);
void ril_mtu_watch_free(struct ril_mtu_watch *mw);
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *mw, const char *ifname);
struct sailfish_cell_info;
struct sailfish_cell_info_dbus;
#endif /* RIL_MTU_H */
struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
(struct ofono_modem *modem, struct sailfish_cell_info *info);
void sailfish_cell_info_dbus_free(struct sailfish_cell_info_dbus *dbus);
#endif /* SAILFISH_CELL_INFO_DBUS_H */
/*
* Local Variables:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 SAILFISH_MANAGER_DBUS_H
#define SAILFISH_MANAGER_DBUS_H
#include <sailfish_manager.h>
struct sailfish_manager_dbus;
enum sailfish_manager_dbus_block {
SAILFISH_MANAGER_DBUS_BLOCK_NONE = 0,
SAILFISH_MANAGER_DBUS_BLOCK_MODEM = 0x01,
SAILFISH_MANAGER_DBUS_BLOCK_IMEI = 0x02,
SAILFISH_MANAGER_DBUS_BLOCK_ALL = 0x03
};
enum sailfish_manager_dbus_signal {
SAILFISH_MANAGER_SIGNAL_NONE = 0,
SAILFISH_MANAGER_SIGNAL_VOICE_IMSI = 0x01,
SAILFISH_MANAGER_SIGNAL_DATA_IMSI = 0x02,
SAILFISH_MANAGER_SIGNAL_VOICE_PATH = 0x04,
SAILFISH_MANAGER_SIGNAL_DATA_PATH = 0x08,
SAILFISH_MANAGER_SIGNAL_ENABLED_SLOTS = 0x10,
SAILFISH_MANAGER_SIGNAL_MMS_IMSI = 0x20,
SAILFISH_MANAGER_SIGNAL_MMS_PATH = 0x40,
SAILFISH_MANAGER_SIGNAL_READY = 0x80
};
/* Functionality provided by sailfish_manager to sailfish_manager_dbus */
struct sailfish_manager_dbus_cb {
GHashTable *(*get_errors)(struct sailfish_manager *m);
GHashTable *(*get_slot_errors)(const struct sailfish_slot *s);
void (*set_enabled_slots)(struct sailfish_manager *m, char **slots);
gboolean (*set_mms_imsi)(struct sailfish_manager *m, const char *imsi);
void (*set_default_voice_imsi)(struct sailfish_manager *m,
const char *imsi);
void (*set_default_data_imsi)(struct sailfish_manager *m,
const char *imsi);
};
struct sailfish_manager_dbus *sailfish_manager_dbus_new
(struct sailfish_manager *m,
const struct sailfish_manager_dbus_cb *cb);
void sailfish_manager_dbus_free(struct sailfish_manager_dbus *d);
void sailfish_manager_dbus_set_block(struct sailfish_manager_dbus *d,
enum sailfish_manager_dbus_block b);
void sailfish_manager_dbus_signal(struct sailfish_manager_dbus *d,
enum sailfish_manager_dbus_signal m);
void sailfish_manager_dbus_signal_sim(struct sailfish_manager_dbus *d,
int index, gboolean present);
void sailfish_manager_dbus_signal_error(struct sailfish_manager_dbus *d,
const char *id, const char *message);
void sailfish_manager_dbus_signal_modem_error(struct sailfish_manager_dbus *d,
int index, const char *id, const char *msg);
#endif /* SAILFISH_MANAGER_DBUS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,614 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "sailfish_sim_info.h"
#include "sailfish_watch.h"
#include <gutil_misc.h>
#include <gutil_log.h>
#include "ofono.h"
#include "common.h"
#include "storage.h"
#define SAILFISH_SIM_INFO_STORE "cache"
#define SAILFISH_SIM_INFO_STORE_GROUP "sim"
#define SAILFISH_SIM_INFO_STORE_SPN "spn"
/* ICCID -> IMSI map */
#define SAILFISH_SIM_ICCID_MAP "iccidmap"
#define SAILFISH_SIM_ICCID_MAP_IMSI "imsi"
#define DEFAULT_SPN_BUFSIZE 8
G_STATIC_ASSERT(DEFAULT_SPN_BUFSIZE >= \
OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1);
typedef GObjectClass SailfishSimInfoClass;
typedef struct sailfish_sim_info SailfishSimInfo;
enum sailfish_watch_events {
WATCH_EVENT_SIM,
WATCH_EVENT_SIM_STATE,
WATCH_EVENT_ICCID,
WATCH_EVENT_IMSI,
WATCH_EVENT_SPN,
WATCH_EVENT_NETREG,
WATCH_EVENT_COUNT
};
struct sailfish_sim_info_priv {
struct sailfish_watch *watch;
struct ofono_netreg *netreg;
char *iccid;
char *imsi;
char *cached_spn;
char *sim_spn;
char *public_spn;
char default_spn[DEFAULT_SPN_BUFSIZE];
gulong watch_event_id[WATCH_EVENT_COUNT];
guint netreg_status_watch_id;
gboolean update_imsi_cache;
gboolean update_iccid_map;
};
enum sailfish_sim_info_signal {
SIGNAL_ICCID_CHANGED,
SIGNAL_IMSI_CHANGED,
SIGNAL_SPN_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_ICCID_CHANGED_NAME "sailfish-siminfo-iccid-changed"
#define SIGNAL_IMSI_CHANGED_NAME "sailfish-siminfo-imsi-changed"
#define SIGNAL_SPN_CHANGED_NAME "sailfish-siminfo-spn-changed"
static guint sailfish_sim_info_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(SailfishSimInfo, sailfish_sim_info, G_TYPE_OBJECT)
#define SAILFISH_SIMINFO_TYPE (sailfish_sim_info_get_type())
#define SAILFISH_SIMINFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
SAILFISH_SIMINFO_TYPE, SailfishSimInfo))
#define NEW_SIGNAL(klass,name) \
sailfish_sim_info_signals[SIGNAL_##name##_CHANGED] = \
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
/* Skip the leading slash from the modem path: */
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
static void sailfish_sim_info_signal_emit(struct sailfish_sim_info *self,
enum sailfish_sim_info_signal id)
{
g_signal_emit(self, sailfish_sim_info_signals[id], 0);
}
static void sailfish_sim_info_update_imsi_cache(struct sailfish_sim_info *self)
{
struct sailfish_sim_info_priv *priv = self->priv;
if (priv->update_imsi_cache && priv->imsi && priv->imsi[0] &&
priv->cached_spn && priv->cached_spn[0]) {
gboolean save = FALSE;
const char *store = SAILFISH_SIM_INFO_STORE;
GKeyFile *cache = storage_open(priv->imsi, store);
char *spn = g_key_file_get_string(cache,
SAILFISH_SIM_INFO_STORE_GROUP,
SAILFISH_SIM_INFO_STORE_SPN, NULL);
if (g_strcmp0(priv->cached_spn, spn)) {
save = TRUE;
g_key_file_set_string(cache,
SAILFISH_SIM_INFO_STORE_GROUP,
SAILFISH_SIM_INFO_STORE_SPN,
priv->cached_spn);
}
/*
* Since we are most likely running on flash which
* supports a limited number of writes, don't overwrite
* the file unless something has actually changed.
*/
if (save) {
DBG_(self, "updating " STORAGEDIR "/%s/%s",
priv->imsi, store);
storage_close(priv->imsi, store, cache, TRUE);
} else {
g_key_file_free(cache);
}
g_free(spn);
priv->update_imsi_cache = FALSE;
}
}
static void sailfish_sim_info_update_iccid_map(struct sailfish_sim_info *self)
{
struct sailfish_sim_info_priv *priv = self->priv;
if (priv->update_iccid_map && priv->iccid && priv->iccid[0] &&
priv->imsi && priv->imsi[0]) {
const char *store = SAILFISH_SIM_ICCID_MAP;
GKeyFile *map = storage_open(NULL, store);
char *imsi = g_key_file_get_string(map,
SAILFISH_SIM_ICCID_MAP_IMSI, priv->iccid, NULL);
/*
* Since we are most likely running on flash which
* supports a limited number of writes, don't overwrite
* the file unless something has actually changed.
*/
if (g_strcmp0(imsi, priv->imsi)) {
DBG_(self, "updating " STORAGEDIR "/%s", store);
g_key_file_set_string(map, SAILFISH_SIM_ICCID_MAP_IMSI,
priv->iccid, priv->imsi);
storage_close(NULL, store, map, TRUE);
} else {
g_key_file_free(map);
}
g_free(imsi);
priv->update_iccid_map = FALSE;
}
}
static void sailfish_sim_info_update_public_spn(struct sailfish_sim_info *self)
{
struct sailfish_sim_info_priv *priv = self->priv;
const char *spn = priv->sim_spn ? priv->sim_spn :
priv->cached_spn ? priv->cached_spn :
priv->default_spn;
if (g_strcmp0(priv->public_spn, spn)) {
g_free(priv->public_spn);
self->spn = priv->public_spn = g_strdup(spn);
sailfish_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
}
}
static void sailfish_sim_info_set_cached_spn(struct sailfish_sim_info *self,
const char *spn)
{
struct sailfish_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->cached_spn, spn)) {
g_free(priv->cached_spn);
if (spn) {
DBG_(self, "cached spn \"%s\"", spn);
priv->cached_spn = g_strdup(spn);
priv->update_imsi_cache = TRUE;
sailfish_sim_info_update_imsi_cache(self);
} else {
priv->cached_spn = NULL;
}
sailfish_sim_info_update_public_spn(self);
}
}
static void sailfish_sim_info_set_spn(struct sailfish_sim_info *self,
const char *spn)
{
struct sailfish_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->sim_spn, spn)) {
DBG_(self, "%s", spn);
g_free(priv->sim_spn);
priv->sim_spn = g_strdup(spn);
priv->update_imsi_cache = TRUE;
sailfish_sim_info_set_cached_spn(self, spn);
sailfish_sim_info_update_imsi_cache(self);
sailfish_sim_info_update_public_spn(self);
}
}
static void sailfish_sim_info_update_spn(struct sailfish_sim_info *self)
{
struct sailfish_watch *watch = self->priv->watch;
if (watch->spn && watch->spn[0]) {
sailfish_sim_info_set_spn(self, watch->spn);
}
}
static void sailfish_sim_info_update_default_spn(struct sailfish_sim_info *self)
{
struct sailfish_sim_info_priv *priv = self->priv;
struct ofono_sim *sim = priv->watch->sim;
char buf[DEFAULT_SPN_BUFSIZE];
const char *mcc = NULL;
const char *mnc = NULL;
if (sim && ofono_sim_get_state(sim) == OFONO_SIM_STATE_READY) {
mcc = ofono_sim_get_mcc(sim);
mnc = ofono_sim_get_mnc(sim);
}
if (mcc && mnc) {
snprintf(buf, DEFAULT_SPN_BUFSIZE, "%s%s", mcc, mnc);
buf[DEFAULT_SPN_BUFSIZE - 1] = 0;
} else {
buf[0] = 0;
}
if (strcmp(buf, priv->default_spn)) {
strncpy(priv->default_spn, buf, DEFAULT_SPN_BUFSIZE);
DBG_(self, "default spn \"%s\"", priv->default_spn);
sailfish_sim_info_update_public_spn(self);
}
}
static void sailfish_sim_info_set_imsi(struct sailfish_sim_info *self,
const char *imsi)
{
struct sailfish_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->imsi, imsi)) {
DBG_(self, "%s", imsi);
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(imsi);
priv->update_iccid_map = TRUE;
sailfish_sim_info_update_iccid_map(self);
sailfish_sim_info_update_imsi_cache(self);
sailfish_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
}
}
static void sailfish_sim_info_update_imsi(struct sailfish_sim_info *self)
{
struct sailfish_watch *watch = self->priv->watch;
if (watch->imsi && watch->imsi[0]) {
sailfish_sim_info_set_imsi(self, watch->imsi);
}
}
static void sailfish_sim_info_network_check(struct sailfish_sim_info *self)
{
struct sailfish_sim_info_priv *priv = self->priv;
struct ofono_sim *sim = priv->watch->sim;
enum network_registration_status reg_status =
ofono_netreg_get_status(priv->netreg);
if (sim && ofono_sim_get_state(sim) == OFONO_SIM_STATE_READY &&
(reg_status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
reg_status == NETWORK_REGISTRATION_STATUS_ROAMING)) {
const char *sim_mcc = ofono_sim_get_mcc(sim);
const char *sim_mnc = ofono_sim_get_mnc(sim);
const char *net_mcc = ofono_netreg_get_mcc(priv->netreg);
const char *net_mnc = ofono_netreg_get_mnc(priv->netreg);
const char *name = ofono_netreg_get_name(priv->netreg);
if (sim_mcc && sim_mcc[0] && sim_mnc && sim_mnc[0] &&
net_mcc && net_mcc[0] && net_mnc && net_mnc[0] &&
name && name[0] && !strcmp(sim_mcc, net_mcc) &&
!strcmp(sim_mnc, net_mnc)) {
/*
* If EFspn is present then sim_spn should be set
* before we get registered with the network.
*/
DBG_(self, "home network \"%s\"", name);
if (!priv->sim_spn) {
sailfish_sim_info_set_cached_spn(self, name);
}
}
}
}
static void sailfish_sim_info_load_cache(struct sailfish_sim_info *self)
{
struct sailfish_sim_info_priv *priv = self->priv;
if (priv->iccid && priv->iccid[0]) {
GKeyFile *map = storage_open(NULL, SAILFISH_SIM_ICCID_MAP);
char *imsi = g_key_file_get_string(map,
SAILFISH_SIM_ICCID_MAP_IMSI, priv->iccid, NULL);
g_key_file_free(map);
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
if (priv->imsi && priv->imsi[0]) {
/* Need to update ICCID -> IMSI map */
DBG_(self, "IMSI changed %s -> %s",
priv->imsi, imsi);
priv->update_imsi_cache = TRUE;
}
g_free(priv->imsi);
self->imsi = priv->imsi = imsi;
DBG_(self, "imsi[%s] = %s", priv->iccid, imsi);
sailfish_sim_info_update_iccid_map(self);
sailfish_sim_info_signal_emit(self,
SIGNAL_IMSI_CHANGED);
} else if (imsi) {
g_free(imsi);
} else {
DBG_(self, "no imsi for iccid %s", priv->iccid);
}
}
if (priv->imsi && priv->imsi[0]) {
GKeyFile *cache = storage_open(priv->imsi,
SAILFISH_SIM_INFO_STORE);
char *spn = g_key_file_get_string(cache,
SAILFISH_SIM_INFO_STORE_GROUP,
SAILFISH_SIM_INFO_STORE_SPN, NULL);
g_key_file_free(cache);
if (spn && spn[0] && g_strcmp0(priv->cached_spn, spn)) {
if (priv->cached_spn && priv->cached_spn[0]) {
/* Need to update the cache file */
DBG_(self, "spn changing %s -> %s",
priv->cached_spn, spn);
priv->update_imsi_cache = TRUE;
}
g_free(priv->cached_spn);
priv->cached_spn = spn;
DBG_(self, "spn[%s] = \"%s\"", priv->imsi, spn);
sailfish_sim_info_update_imsi_cache(self);
sailfish_sim_info_update_public_spn(self);
} else if (spn) {
g_free(spn);
} else {
DBG_(self, "no spn for imsi %s", priv->imsi);
}
}
}
static void sailfish_sim_info_set_iccid(struct sailfish_sim_info *self,
const char *iccid)
{
struct sailfish_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->iccid, iccid)) {
g_free(priv->iccid);
self->iccid = priv->iccid = g_strdup(iccid);
sailfish_sim_info_signal_emit(self, SIGNAL_ICCID_CHANGED);
if (iccid) {
sailfish_sim_info_load_cache(self);
} else {
if (priv->imsi) {
g_free(priv->imsi);
self->imsi = priv->imsi = NULL;
sailfish_sim_info_signal_emit(self,
SIGNAL_IMSI_CHANGED);
}
if (priv->sim_spn) {
g_free(priv->sim_spn);
priv->sim_spn = NULL;
sailfish_sim_info_set_cached_spn(self, NULL);
}
}
}
}
static void sailfish_sim_info_sim_watch_cb(struct sailfish_watch *watch,
void *data)
{
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
struct ofono_sim *sim = self->priv->watch->sim;
sailfish_sim_info_update_default_spn(self);
if (ofono_sim_get_state(sim) == OFONO_SIM_STATE_NOT_PRESENT) {
sailfish_sim_info_set_iccid(self, NULL);
}
sailfish_sim_info_network_check(self);
}
static void sailfish_sim_info_iccid_watch_cb(struct sailfish_watch *watch,
void *data)
{
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
DBG_(self, "%s", watch->iccid);
sailfish_sim_info_set_iccid(self, watch->iccid);
}
static void sailfish_sim_info_imsi_watch_cb(struct sailfish_watch *watch,
void *data)
{
sailfish_sim_info_update_imsi(SAILFISH_SIMINFO(data));
}
static void sailfish_sim_info_spn_watch_cb(struct sailfish_watch *watch,
void *data)
{
sailfish_sim_info_update_spn(SAILFISH_SIMINFO(data));
}
static void sailfish_sim_info_netreg_watch(int status, int lac, int ci,
int tech, const char *mcc, const char *mnc, void *data)
{
sailfish_sim_info_network_check(SAILFISH_SIMINFO(data));
}
static void sailfish_sim_info_netreg_watch_done(void *data)
{
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
struct sailfish_sim_info_priv *priv = self->priv;
GASSERT(priv->netreg_status_watch_id);
priv->netreg_status_watch_id = 0;
}
static void sailfish_sim_info_set_netreg(struct sailfish_sim_info *self,
struct ofono_netreg *netreg)
{
struct sailfish_sim_info_priv *priv = self->priv;
if (priv->netreg != netreg) {
if (netreg) {
DBG_(self, "netreg attached");
priv->netreg = netreg;
priv->netreg_status_watch_id =
__ofono_netreg_add_status_watch(netreg,
sailfish_sim_info_netreg_watch, self,
sailfish_sim_info_netreg_watch_done);
sailfish_sim_info_network_check(self);
} else if (priv->netreg) {
if (priv->netreg_status_watch_id) {
__ofono_netreg_remove_status_watch(priv->netreg,
priv->netreg_status_watch_id);
GASSERT(!priv->netreg_status_watch_id);
}
DBG_(self, "netreg detached");
priv->netreg = NULL;
}
}
}
static void sailfish_sim_info_netreg_changed(struct sailfish_watch *watch,
void *data)
{
sailfish_sim_info_set_netreg(SAILFISH_SIMINFO(data), watch->netreg);
}
struct sailfish_sim_info *sailfish_sim_info_new(const char *path)
{
struct sailfish_sim_info *self = NULL;
if (path) {
struct sailfish_watch *watch = sailfish_watch_new(path);
struct sailfish_sim_info_priv *priv;
self = g_object_new(SAILFISH_SIMINFO_TYPE, NULL);
priv = self->priv;
priv->watch = watch;
self->path = watch->path;
priv->watch_event_id[WATCH_EVENT_SIM] =
sailfish_watch_add_sim_changed_handler(watch,
sailfish_sim_info_sim_watch_cb, self);
priv->watch_event_id[WATCH_EVENT_SIM_STATE] =
sailfish_watch_add_sim_state_changed_handler(watch,
sailfish_sim_info_sim_watch_cb, self);
priv->watch_event_id[WATCH_EVENT_ICCID] =
sailfish_watch_add_iccid_changed_handler(watch,
sailfish_sim_info_iccid_watch_cb, self);
priv->watch_event_id[WATCH_EVENT_IMSI] =
sailfish_watch_add_imsi_changed_handler(watch,
sailfish_sim_info_imsi_watch_cb, self);
priv->watch_event_id[WATCH_EVENT_SPN] =
sailfish_watch_add_spn_changed_handler(watch,
sailfish_sim_info_spn_watch_cb, self);
priv->watch_event_id[WATCH_EVENT_NETREG] =
sailfish_watch_add_netreg_changed_handler(watch,
sailfish_sim_info_netreg_changed, self);
sailfish_sim_info_set_iccid(self, watch->iccid);
sailfish_sim_info_set_netreg(self, watch->netreg);
sailfish_sim_info_update_imsi(self);
sailfish_sim_info_update_spn(self);
sailfish_sim_info_network_check(self);
}
return self;
}
struct sailfish_sim_info *sailfish_sim_info_ref(struct sailfish_sim_info *self)
{
if (self) {
g_object_ref(SAILFISH_SIMINFO(self));
return self;
} else {
return NULL;
}
}
void sailfish_sim_info_unref(struct sailfish_sim_info *self)
{
if (self) {
g_object_unref(SAILFISH_SIMINFO(self));
}
}
void sailfish_sim_info_invalidate(struct sailfish_sim_info *self)
{
if (self) {
sailfish_sim_info_set_iccid(self, NULL);
}
}
gulong sailfish_sim_info_add_iccid_changed_handler(struct sailfish_sim_info *s,
sailfish_sim_info_cb_t cb, void *arg)
{
return (s && cb) ? g_signal_connect(s, SIGNAL_ICCID_CHANGED_NAME,
G_CALLBACK(cb), arg) : 0;
}
gulong sailfish_sim_info_add_imsi_changed_handler(struct sailfish_sim_info *s,
sailfish_sim_info_cb_t cb, void *arg)
{
return (s && cb) ? g_signal_connect(s, SIGNAL_IMSI_CHANGED_NAME,
G_CALLBACK(cb), arg) : 0;
}
gulong sailfish_sim_info_add_spn_changed_handler(struct sailfish_sim_info *s,
sailfish_sim_info_cb_t cb, void *arg)
{
return (s && cb) ? g_signal_connect(s, SIGNAL_SPN_CHANGED_NAME,
G_CALLBACK(cb), arg) : 0;
}
void sailfish_sim_info_remove_handler(struct sailfish_sim_info *s, gulong id)
{
if (s && id) {
g_signal_handler_disconnect(s, id);
}
}
void sailfish_sim_info_remove_handlers(struct sailfish_sim_info *self,
gulong *ids, int count)
{
gutil_disconnect_handlers(self, ids, count);
}
static void sailfish_sim_info_init(struct sailfish_sim_info *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SAILFISH_SIMINFO_TYPE,
struct sailfish_sim_info_priv);
}
static void sailfish_sim_info_finalize(GObject *object)
{
struct sailfish_sim_info *self = SAILFISH_SIMINFO(object);
struct sailfish_sim_info_priv *priv = self->priv;
sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
sailfish_watch_unref(priv->watch);
g_free(priv->iccid);
g_free(priv->imsi);
g_free(priv->sim_spn);
g_free(priv->cached_spn);
g_free(priv->public_spn);
G_OBJECT_CLASS(sailfish_sim_info_parent_class)->finalize(object);
}
static void sailfish_sim_info_class_init(SailfishSimInfoClass *klass)
{
G_OBJECT_CLASS(klass)->finalize = sailfish_sim_info_finalize;
g_type_class_add_private(klass, sizeof(struct sailfish_sim_info_priv));
NEW_SIGNAL(klass, ICCID);
NEW_SIGNAL(klass, IMSI);
NEW_SIGNAL(klass, SPN);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,81 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef SAILFISH_SIM_INFO_H
#define SAILFISH_SIM_INFO_H
#include <ofono/types.h>
#include <glib.h>
#include <glib-object.h>
/*
* Note that iccid, imsi and spn provided by this class can be cached,
* i.e. become available before the pin code is entered and before those
* are known to the ofono core. That's the whole purpose of this thing.
*
* If you need to follow imsi known to the ofono core, you can use
* sailfish_sim_settings for that (or fight with ofono imsi watchers
* directly).
*/
struct ofono_modem;
struct sailfish_sim_info_priv;
struct sailfish_sim_info {
GObject object;
struct sailfish_sim_info_priv *priv;
const char *path;
const char *iccid;
const char *imsi;
const char *spn;
};
typedef void (*sailfish_sim_info_cb_t)(struct sailfish_sim_info *si,
void *user_data);
/* SIM info object associated with the particular slot */
struct sailfish_sim_info *sailfish_sim_info_new(const char *path);
struct sailfish_sim_info *sailfish_sim_info_ref(struct sailfish_sim_info *si);
void sailfish_sim_info_unref(struct sailfish_sim_info *si);
void sailfish_sim_info_invalidate(struct sailfish_sim_info *si);
gulong sailfish_sim_info_add_iccid_changed_handler(struct sailfish_sim_info *si,
sailfish_sim_info_cb_t cb, void *user_data);
gulong sailfish_sim_info_add_imsi_changed_handler(struct sailfish_sim_info *si,
sailfish_sim_info_cb_t cb, void *user_data);
gulong sailfish_sim_info_add_spn_changed_handler(struct sailfish_sim_info *si,
sailfish_sim_info_cb_t cb, void *user_data);
void sailfish_sim_info_remove_handler(struct sailfish_sim_info *si, gulong id);
void sailfish_sim_info_remove_handlers(struct sailfish_sim_info *si,
gulong *ids, int count);
#define sailfish_sim_info_remove_all_handlers(si,ids) \
sailfish_sim_info_remove_handlers(si, ids, G_N_ELEMENTS(ids))
/* And the D-Bus interface for it */
struct sailfish_sim_info_dbus;
struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new
(struct sailfish_sim_info *si);
struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new_path
(const char *path);
void sailfish_sim_info_dbus_free(struct sailfish_sim_info_dbus *dbus);
#endif /* SAILFISH_SIM_INFO_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,296 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "sailfish_sim_info.h"
#include "sailfish_watch.h"
#include <ofono/dbus.h>
#include <gdbus.h>
#include "ofono.h"
enum watch_event_id {
WATCH_EVENT_MODEM,
WATCH_EVENT_COUNT
};
enum sim_info_event_id {
SIM_INFO_EVENT_ICCID,
SIM_INFO_EVENT_IMSI,
SIM_INFO_EVENT_SPN,
SIM_INFO_EVENT_COUNT
};
struct sailfish_sim_info_dbus {
struct sailfish_sim_info *info;
struct sailfish_watch *watch;
DBusConnection *conn;
gulong watch_event_id[WATCH_EVENT_COUNT];
gulong info_event_id[SIM_INFO_EVENT_COUNT];
};
#define SIM_INFO_DBUS_INTERFACE "org.nemomobile.ofono.SimInfo"
#define SIM_INFO_DBUS_INTERFACE_VERSION (1)
#define SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL "CardIdentifierChanged"
#define SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL "SubscriberIdentityChanged"
#define SIM_INFO_DBUS_SPN_CHANGED_SIGNAL "ServiceProviderNameChanged"
static void sailfish_sim_info_dbus_append_version(DBusMessageIter *it)
{
const dbus_int32_t version = SIM_INFO_DBUS_INTERFACE_VERSION;
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
}
static void sailfish_sim_info_dbus_append_string(DBusMessageIter *it,
const char *str)
{
if (!str) str = "";
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
}
static DBusMessage *sailfish_sim_info_dbus_reply_with_string(DBusMessage *msg,
const char *str)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
sailfish_sim_info_dbus_append_string(&iter, str);
return reply;
}
static DBusMessage *sailfish_sim_info_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct sailfish_sim_info_dbus *dbus = data;
struct sailfish_sim_info *info = dbus->info;
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it;
dbus_message_iter_init_append(reply, &it);
sailfish_sim_info_dbus_append_version(&it);
sailfish_sim_info_dbus_append_string(&it, info->iccid);
sailfish_sim_info_dbus_append_string(&it, info->imsi);
sailfish_sim_info_dbus_append_string(&it, info->spn);
return reply;
}
static DBusMessage *sailfish_sim_info_dbus_get_version(DBusConnection *dc,
DBusMessage *msg, void *data)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it;
dbus_message_iter_init_append(reply, &it);
sailfish_sim_info_dbus_append_version(&it);
return reply;
}
static DBusMessage *sailfish_sim_info_dbus_get_iccid(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct sailfish_sim_info_dbus *dbus = data;
return sailfish_sim_info_dbus_reply_with_string(msg, dbus->info->iccid);
}
static DBusMessage *sailfish_sim_info_dbus_get_imsi(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct sailfish_sim_info_dbus *dbus = data;
return sailfish_sim_info_dbus_reply_with_string(msg, dbus->info->imsi);
}
static DBusMessage *sailfish_sim_info_dbus_get_spn(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct sailfish_sim_info_dbus *dbus = data;
return sailfish_sim_info_dbus_reply_with_string(msg, dbus->info->spn);
}
#define SIM_INFO_DBUS_VERSION_ARG {"version", "i"}
#define SIM_INFO_DBUS_ICCID_ARG {"iccid", "s"}
#define SIM_INFO_DBUS_IMSI_ARG {"imsi", "s"}
#define SIM_INFO_DBUS_SPN_ARG {"spn" , "s"}
#define SIM_INFO_DBUS_GET_ALL_ARGS \
SIM_INFO_DBUS_VERSION_ARG, \
SIM_INFO_DBUS_ICCID_ARG, \
SIM_INFO_DBUS_IMSI_ARG, \
SIM_INFO_DBUS_SPN_ARG
static const GDBusMethodTable sailfish_sim_info_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS(SIM_INFO_DBUS_GET_ALL_ARGS),
sailfish_sim_info_dbus_get_all) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS(SIM_INFO_DBUS_VERSION_ARG),
sailfish_sim_info_dbus_get_version) },
{ GDBUS_METHOD("GetCardIdentifier",
NULL, GDBUS_ARGS(SIM_INFO_DBUS_ICCID_ARG),
sailfish_sim_info_dbus_get_iccid) },
{ GDBUS_METHOD("GetSubscriberIdentity",
NULL, GDBUS_ARGS(SIM_INFO_DBUS_IMSI_ARG),
sailfish_sim_info_dbus_get_imsi) },
{ GDBUS_METHOD("GetServiceProviderName",
NULL, GDBUS_ARGS(SIM_INFO_DBUS_SPN_ARG),
sailfish_sim_info_dbus_get_spn) },
{ }
};
static const GDBusSignalTable sailfish_sim_info_dbus_signals[] = {
{ GDBUS_SIGNAL(SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
GDBUS_ARGS(SIM_INFO_DBUS_ICCID_ARG)) },
{ GDBUS_SIGNAL(SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
GDBUS_ARGS(SIM_INFO_DBUS_IMSI_ARG)) },
{ GDBUS_SIGNAL(SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
GDBUS_ARGS(SIM_INFO_DBUS_SPN_ARG)) },
{ }
};
static void sailfish_sim_info_dbus_modem_cb(struct sailfish_watch *watch,
void *data)
{
if (watch->modem) {
ofono_modem_add_interface(watch->modem,
SIM_INFO_DBUS_INTERFACE);
}
}
static void sailfish_sim_info_dbus_emit(struct sailfish_sim_info_dbus *dbus,
const char *signal, const char *value)
{
const char *arg = value;
if (!arg) arg = "";
g_dbus_emit_signal(dbus->conn, dbus->info->path,
SIM_INFO_DBUS_INTERFACE, signal,
DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
}
static void sailfish_sim_info_dbus_iccid_cb(struct sailfish_sim_info *info,
void *data)
{
sailfish_sim_info_dbus_emit((struct sailfish_sim_info_dbus *)data,
SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL, info->iccid);
}
static void sailfish_sim_info_dbus_imsi_cb(struct sailfish_sim_info *info,
void *data)
{
sailfish_sim_info_dbus_emit((struct sailfish_sim_info_dbus *)data,
SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL, info->imsi);
}
static void sailfish_sim_info_dbus_spn_cb(struct sailfish_sim_info *info,
void *data)
{
sailfish_sim_info_dbus_emit((struct sailfish_sim_info_dbus *)data,
SIM_INFO_DBUS_SPN_CHANGED_SIGNAL, info->spn);
}
struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new
(struct sailfish_sim_info *info)
{
struct sailfish_sim_info_dbus *dbus =
g_slice_new0(struct sailfish_sim_info_dbus);
DBG("%s", info->path);
dbus->info = sailfish_sim_info_ref(info);
dbus->watch = sailfish_watch_new(info->path);
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
/* Register D-Bus interface */
if (g_dbus_register_interface(dbus->conn, dbus->info->path,
SIM_INFO_DBUS_INTERFACE,
sailfish_sim_info_dbus_methods,
sailfish_sim_info_dbus_signals,
NULL, dbus, NULL)) {
if (dbus->watch->modem) {
ofono_modem_add_interface(dbus->watch->modem,
SIM_INFO_DBUS_INTERFACE);
}
dbus->watch_event_id[WATCH_EVENT_MODEM] =
sailfish_watch_add_modem_changed_handler(dbus->watch,
sailfish_sim_info_dbus_modem_cb, dbus);
dbus->info_event_id[SIM_INFO_EVENT_ICCID] =
sailfish_sim_info_add_iccid_changed_handler(info,
sailfish_sim_info_dbus_iccid_cb, dbus);
dbus->info_event_id[SIM_INFO_EVENT_IMSI] =
sailfish_sim_info_add_imsi_changed_handler(info,
sailfish_sim_info_dbus_imsi_cb, dbus);
dbus->info_event_id[SIM_INFO_EVENT_SPN] =
sailfish_sim_info_add_spn_changed_handler(info,
sailfish_sim_info_dbus_spn_cb, dbus);
return dbus;
} else {
ofono_error("SimInfo D-Bus register failed");
sailfish_sim_info_dbus_free(dbus);
return NULL;
}
}
struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new_path
(const char *path)
{
struct sailfish_sim_info_dbus *dbus = NULL;
struct sailfish_sim_info *info = sailfish_sim_info_new(path);
if (info) {
dbus = sailfish_sim_info_dbus_new(info);
sailfish_sim_info_unref(info);
}
return dbus;
}
void sailfish_sim_info_dbus_free(struct sailfish_sim_info_dbus *dbus)
{
if (dbus) {
DBG("%s", dbus->info->path);
g_dbus_unregister_interface(dbus->conn, dbus->info->path,
SIM_INFO_DBUS_INTERFACE);
if (dbus->watch->modem) {
ofono_modem_remove_interface(dbus->watch->modem,
SIM_INFO_DBUS_INTERFACE);
}
dbus_connection_unref(dbus->conn);
sailfish_watch_remove_all_handlers(dbus->watch,
dbus->watch_event_id);
sailfish_watch_unref(dbus->watch);
sailfish_sim_info_remove_all_handlers(dbus->info,
dbus->info_event_id);
sailfish_sim_info_unref(dbus->info);
g_slice_free(struct sailfish_sim_info_dbus, dbus);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,680 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "sailfish_watch.h"
#include <gutil_misc.h>
#include <gutil_log.h>
#include "ofono.h"
typedef GObjectClass SailfishWatchClass;
typedef struct sailfish_watch SailfishWatch;
struct sailfish_watch_priv {
char *path;
char *iccid;
char *imsi;
char *spn;
int signals_suspended;
int queued_signals;
guint modem_watch_id;
guint online_watch_id;
guint sim_watch_id;
guint sim_state_watch_id;
guint iccid_watch_id;
guint imsi_watch_id;
guint spn_watch_id;
guint netreg_watch_id;
};
enum sailfish_watch_signal {
SIGNAL_MODEM_CHANGED,
SIGNAL_ONLINE_CHANGED,
SIGNAL_SIM_CHANGED,
SIGNAL_SIM_STATE_CHANGED,
SIGNAL_ICCID_CHANGED,
SIGNAL_IMSI_CHANGED,
SIGNAL_SPN_CHANGED,
SIGNAL_NETREG_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_MODEM_CHANGED_NAME "sailfish-watch-modem-changed"
#define SIGNAL_ONLINE_CHANGED_NAME "sailfish-watch-online-changed"
#define SIGNAL_SIM_CHANGED_NAME "sailfish-watch-sim-changed"
#define SIGNAL_SIM_STATE_CHANGED_NAME "sailfish-watch-sim-state-changed"
#define SIGNAL_ICCID_CHANGED_NAME "sailfish-watch-iccid-changed"
#define SIGNAL_IMSI_CHANGED_NAME "sailfish-watch-imsi-changed"
#define SIGNAL_SPN_CHANGED_NAME "sailfish-watch-spn-changed"
#define SIGNAL_NETREG_CHANGED_NAME "sailfish-watch-netreg-changed"
static guint sailfish_watch_signals[SIGNAL_COUNT] = { 0 };
static GHashTable* sailfish_watch_table = NULL;
G_DEFINE_TYPE(SailfishWatch, sailfish_watch, G_TYPE_OBJECT)
#define SAILFISH_WATCH_TYPE (sailfish_watch_get_type())
#define SAILFISH_WATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
SAILFISH_WATCH_TYPE, SailfishWatch))
#define NEW_SIGNAL(klass,name) \
sailfish_watch_signals[SIGNAL_##name##_CHANGED] = \
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
/* Skip the leading slash from the modem path: */
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
static inline int sailfish_watch_signal_bit(enum sailfish_watch_signal id)
{
return (1 << id);
}
static inline void sailfish_watch_signal_emit(struct sailfish_watch *self,
enum sailfish_watch_signal id)
{
self->priv->queued_signals &= ~sailfish_watch_signal_bit(id);
g_signal_emit(self, sailfish_watch_signals[id], 0);
}
static inline void sailfish_watch_signal_queue(struct sailfish_watch *self,
enum sailfish_watch_signal id)
{
self->priv->queued_signals |= sailfish_watch_signal_bit(id);
}
static void sailfish_watch_emit_queued_signals(struct sailfish_watch *self)
{
struct sailfish_watch_priv *priv = self->priv;
if (priv->signals_suspended < 1) {
int i;
for (i = 0; priv->queued_signals && i < SIGNAL_COUNT; i++) {
if (priv->queued_signals &
sailfish_watch_signal_bit(i)) {
sailfish_watch_signal_emit(self, i);
}
}
}
}
static inline void sailfish_watch_suspend_signals(struct sailfish_watch *self)
{
self->priv->signals_suspended++;
}
static inline void sailfish_watch_resume_signals(struct sailfish_watch *self)
{
struct sailfish_watch_priv *priv = self->priv;
GASSERT(priv->signals_suspended > 0);
priv->signals_suspended--;
sailfish_watch_emit_queued_signals(self);
}
static void sailfish_watch_sim_state_notify(enum ofono_sim_state new_state,
void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
sailfish_watch_signal_queue(self, SIGNAL_SIM_STATE_CHANGED);
sailfish_watch_emit_queued_signals(self);
}
static void sailfish_watch_sim_state_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
struct sailfish_watch_priv *priv = self->priv;
GASSERT(priv->sim_state_watch_id);
priv->sim_state_watch_id = 0;
}
static void sailfish_watch_iccid_update(struct sailfish_watch *self,
const char *iccid)
{
struct sailfish_watch_priv *priv = self->priv;
if (g_strcmp0(priv->iccid, iccid)) {
g_free(priv->iccid);
self->iccid = priv->iccid = g_strdup(iccid);
sailfish_watch_signal_queue(self, SIGNAL_ICCID_CHANGED);
}
}
static void sailfish_watch_iccid_notify(const char *iccid, void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
sailfish_watch_iccid_update(self, iccid);
sailfish_watch_emit_queued_signals(self);
}
static void sailfish_watch_iccid_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
struct sailfish_watch_priv *priv = self->priv;
GASSERT(priv->iccid_watch_id);
priv->iccid_watch_id = 0;
}
static void sailfish_watch_spn_update(struct sailfish_watch *self,
const char *spn)
{
struct sailfish_watch_priv *priv = self->priv;
if (g_strcmp0(priv->spn, spn)) {
g_free(priv->spn);
self->spn = priv->spn = g_strdup(spn);
sailfish_watch_signal_queue(self, SIGNAL_SPN_CHANGED);
}
}
static void sailfish_watch_spn_notify(const char *spn, const char *dc,
void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
sailfish_watch_spn_update(self, spn);
sailfish_watch_emit_queued_signals(self);
}
static void sailfish_watch_spn_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
struct sailfish_watch_priv *priv = self->priv;
GASSERT(priv->spn_watch_id);
priv->spn_watch_id = 0;
}
static void sailfish_watch_imsi_update(struct sailfish_watch *self,
const char *imsi)
{
struct sailfish_watch_priv *priv = self->priv;
if (g_strcmp0(priv->imsi, imsi)) {
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(imsi);
sailfish_watch_signal_queue(self, SIGNAL_IMSI_CHANGED);
/* ofono core crashes if we add spn watch too early */
if (imsi) {
ofono_sim_add_spn_watch(self->sim, &priv->spn_watch_id,
sailfish_watch_spn_notify, self,
sailfish_watch_spn_destroy);
}
}
}
static void sailfish_watch_imsi_notify(const char *imsi, void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
sailfish_watch_imsi_update(self, imsi);
sailfish_watch_emit_queued_signals(self);
}
static void sailfish_watch_imsi_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
struct sailfish_watch_priv *priv = self->priv;
GASSERT(priv->imsi_watch_id);
priv->imsi_watch_id = 0;
}
static void sailfish_watch_set_sim(struct sailfish_watch *self,
struct ofono_sim *sim)
{
if (self->sim != sim) {
struct sailfish_watch_priv *priv = self->priv;
if (priv->sim_state_watch_id) {
ofono_sim_remove_state_watch(self->sim,
priv->sim_state_watch_id);
/* The destroy callback clears it */
GASSERT(!priv->sim_state_watch_id);
}
if (priv->iccid_watch_id) {
ofono_sim_remove_iccid_watch(self->sim,
priv->iccid_watch_id);
/* The destroy callback clears it */
GASSERT(!priv->iccid_watch_id);
}
if (priv->imsi_watch_id) {
ofono_sim_remove_imsi_watch(self->sim,
priv->imsi_watch_id);
/* The destroy callback clears it */
GASSERT(!priv->imsi_watch_id);
}
if (priv->spn_watch_id) {
ofono_sim_remove_spn_watch(self->sim,
&priv->spn_watch_id);
/* The destroy callback clears it */
GASSERT(!priv->spn_watch_id);
}
self->sim = sim;
sailfish_watch_signal_queue(self, SIGNAL_SIM_CHANGED);
sailfish_watch_suspend_signals(self);
if (sim) {
priv->sim_state_watch_id =
ofono_sim_add_state_watch(sim,
sailfish_watch_sim_state_notify, self,
sailfish_watch_sim_state_destroy);
/*
* Unlike ofono_sim_add_state_watch, the rest
* of ofono_sim_add_xxx_watch functions call the
* notify callback if the value is already known
* to the ofono core.
*
* Also note that ofono core crashes if we add
* spn watch too early.
*/
priv->iccid_watch_id =
ofono_sim_add_iccid_watch(self->sim,
sailfish_watch_iccid_notify, self,
sailfish_watch_iccid_destroy);
priv->imsi_watch_id =
ofono_sim_add_imsi_watch(self->sim,
sailfish_watch_imsi_notify, self,
sailfish_watch_imsi_destroy);
} else {
/* And these will just queue the signals
* if necessary */
sailfish_watch_iccid_update(self, NULL);
sailfish_watch_imsi_update(self, NULL);
sailfish_watch_spn_update(self, NULL);
}
/* Emit the pending signals. */
sailfish_watch_resume_signals(self);
}
}
static void sailfish_watch_sim_notify(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond, void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
struct ofono_sim *sim = __ofono_atom_get_data(atom);
DBG_(self, "sim registered");
sailfish_watch_set_sim(self, sim);
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
DBG_(self, "sim unregistered");
sailfish_watch_set_sim(self, NULL);
}
}
static void sailfish_watch_sim_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
self->priv->sim_watch_id = 0;
}
static void sailfish_watch_set_netreg(struct sailfish_watch *self,
struct ofono_netreg *netreg)
{
if (self->netreg != netreg) {
self->netreg = netreg;
sailfish_watch_signal_emit(self, SIGNAL_NETREG_CHANGED);
}
}
static void sailfish_watch_netreg_notify(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond, void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
struct ofono_netreg *netreg = __ofono_atom_get_data(atom);
DBG_(self, "netreg registered");
sailfish_watch_set_netreg(self, netreg);
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
DBG_(self, "netreg unregistered");
sailfish_watch_set_netreg(self, NULL);
}
}
static void sailfish_watch_netreg_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
self->priv->netreg_watch_id = 0;
}
static void sailfish_watch_online_update(struct sailfish_watch *self,
gboolean online)
{
if (self->online != online) {
self->online = online;
sailfish_watch_signal_queue(self, SIGNAL_ONLINE_CHANGED);
}
}
static void sailfish_watch_online_notify(struct ofono_modem *modem,
ofono_bool_t online, void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
GASSERT(self->modem == modem);
GASSERT(online == ofono_modem_get_online(modem));
sailfish_watch_online_update(self, online);
sailfish_watch_emit_queued_signals(self);
}
static void sailfish_watch_online_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
self->priv->online_watch_id = 0;
}
static void sailfish_watch_setup_modem(struct sailfish_watch *self)
{
struct sailfish_watch_priv *priv = self->priv;
GASSERT(!priv->online_watch_id);
priv->online_watch_id =
__ofono_modem_add_online_watch(self->modem,
sailfish_watch_online_notify, self,
sailfish_watch_online_destroy);
/* __ofono_modem_add_atom_watch() calls the notify callback if the
* atom is already registered */
GASSERT(!priv->sim_watch_id);
priv->sim_watch_id = __ofono_modem_add_atom_watch(self->modem,
OFONO_ATOM_TYPE_SIM, sailfish_watch_sim_notify,
self, sailfish_watch_sim_destroy);
GASSERT(!priv->netreg_watch_id);
priv->netreg_watch_id = __ofono_modem_add_atom_watch(self->modem,
OFONO_ATOM_TYPE_NETREG, sailfish_watch_netreg_notify,
self, sailfish_watch_netreg_destroy);
}
static void sailfish_watch_cleanup_modem(struct sailfish_watch *self,
struct ofono_modem *modem)
{
/* Caller checks the self->modem isn't NULL */
struct sailfish_watch_priv *priv = self->priv;
if (priv->online_watch_id) {
__ofono_modem_remove_online_watch(modem,
priv->online_watch_id);
GASSERT(!priv->online_watch_id);
}
if (priv->sim_watch_id) {
__ofono_modem_remove_atom_watch(modem, priv->sim_watch_id);
GASSERT(!priv->sim_watch_id);
}
if (priv->netreg_watch_id) {
__ofono_modem_remove_atom_watch(modem, priv->netreg_watch_id);
GASSERT(!priv->netreg_watch_id);
}
sailfish_watch_set_sim(self, NULL);
sailfish_watch_set_netreg(self, NULL);
}
static void sailfish_watch_set_modem(struct sailfish_watch *self,
struct ofono_modem *modem)
{
if (self->modem != modem) {
struct ofono_modem *old_modem = self->modem;
self->modem = modem;
sailfish_watch_signal_queue(self, SIGNAL_MODEM_CHANGED);
if (old_modem) {
sailfish_watch_cleanup_modem(self, old_modem);
}
if (modem) {
sailfish_watch_setup_modem(self);
}
sailfish_watch_emit_queued_signals(self);
}
}
static void sailfish_watch_modem_notify(struct ofono_modem *modem,
gboolean added, void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
if (added) {
if (!g_strcmp0(self->path, ofono_modem_get_path(modem))) {
sailfish_watch_set_modem(self, modem);
}
} else if (self->modem == modem) {
sailfish_watch_set_modem(self, NULL);
}
}
static void sailfish_watch_modem_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
self->priv->modem_watch_id = 0;
}
static ofono_bool_t sailfish_watch_modem_find(struct ofono_modem *modem,
void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
if (!g_strcmp0(self->path, ofono_modem_get_path(modem))) {
self->modem = modem;
sailfish_watch_setup_modem(self);
return TRUE;
} else {
return FALSE;
}
}
static void sailfish_watch_initialize(struct sailfish_watch *self,
const char *path)
{
struct sailfish_watch_priv *priv = self->priv;
self->path = priv->path = g_strdup(path);
ofono_modem_find(sailfish_watch_modem_find, self);
self->online = ofono_modem_get_online(self->modem);
priv->modem_watch_id =
__ofono_modemwatch_add(sailfish_watch_modem_notify, self,
sailfish_watch_modem_destroy);
}
static void sailfish_watch_destroyed(gpointer key, GObject* obj)
{
GASSERT(sailfish_watch_table);
DBG("%s", (char*)key);
if (sailfish_watch_table) {
GASSERT(g_hash_table_lookup(sailfish_watch_table, key) == obj);
g_hash_table_remove(sailfish_watch_table, key);
if (g_hash_table_size(sailfish_watch_table) == 0) {
g_hash_table_unref(sailfish_watch_table);
sailfish_watch_table = NULL;
}
}
}
struct sailfish_watch *sailfish_watch_new(const char *path)
{
struct sailfish_watch *watch = NULL;
if (path) {
if (sailfish_watch_table) {
watch = sailfish_watch_ref(g_hash_table_lookup(
sailfish_watch_table, path));
}
if (!watch) {
char* key = g_strdup(path);
watch = g_object_new(SAILFISH_WATCH_TYPE, NULL);
sailfish_watch_initialize(watch, path);
if (!sailfish_watch_table) {
/* Create the table on demand */
sailfish_watch_table =
g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, NULL);
}
g_hash_table_replace(sailfish_watch_table, key, watch);
g_object_weak_ref(G_OBJECT(watch),
sailfish_watch_destroyed, key);
DBG_(watch, "created");
}
}
return watch;
}
struct sailfish_watch *sailfish_watch_ref(struct sailfish_watch *self)
{
if (self) {
g_object_ref(SAILFISH_WATCH(self));
return self;
} else {
return NULL;
}
}
void sailfish_watch_unref(struct sailfish_watch *self)
{
if (self) {
g_object_unref(SAILFISH_WATCH(self));
}
}
gulong sailfish_watch_add_modem_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_MODEM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_online_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_sim_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_SIM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_sim_state_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_SIM_STATE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_iccid_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_imsi_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_spn_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_netreg_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_NETREG_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
void sailfish_watch_remove_handler(struct sailfish_watch *self, gulong id)
{
if (self && id) {
g_signal_handler_disconnect(self, id);
}
}
void sailfish_watch_remove_handlers(struct sailfish_watch *self, gulong *ids,
int count)
{
gutil_disconnect_handlers(self, ids, count);
}
static void sailfish_watch_init(struct sailfish_watch *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SAILFISH_WATCH_TYPE,
struct sailfish_watch_priv);
}
static void sailfish_watch_finalize(GObject *object)
{
struct sailfish_watch *self = SAILFISH_WATCH(object);
struct sailfish_watch_priv *priv = self->priv;
if (self->modem) {
struct ofono_modem *modem = self->modem;
self->modem = NULL;
sailfish_watch_cleanup_modem(self, modem);
}
if (priv->modem_watch_id) {
__ofono_modemwatch_remove(priv->modem_watch_id);
GASSERT(!priv->modem_watch_id);
}
g_free(priv->path);
G_OBJECT_CLASS(sailfish_watch_parent_class)->finalize(object);
}
static void sailfish_watch_class_init(SailfishWatchClass *klass)
{
G_OBJECT_CLASS(klass)->finalize = sailfish_watch_finalize;
g_type_class_add_private(klass, sizeof(struct sailfish_watch_priv));
NEW_SIGNAL(klass, MODEM);
NEW_SIGNAL(klass, ONLINE);
NEW_SIGNAL(klass, SIM);
NEW_SIGNAL(klass, SIM_STATE);
NEW_SIGNAL(klass, ICCID);
NEW_SIGNAL(klass, IMSI);
NEW_SIGNAL(klass, SPN);
NEW_SIGNAL(klass, NETREG);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2014 Jolla Ltd.
* Copyright (C) 2013-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -9,17 +9,13 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <gutil_inotify.h>
#include <sys/inotify.h>
#include <wspcodec.h>
@@ -75,10 +71,7 @@ struct push_datagram_handler {
static GSList *handlers;
static GSList *modems;
static unsigned int modem_watch_id;
static int inotify_fd = -1;
static int inotify_watch_id = -1;
static guint inotify_watch_source_id;
static GIOChannel *inotify_watch_channel;
static GUtilInotifyWatchCallback *inotify_cb;
static void pf_notify_handler(struct push_datagram_handler *h,
const char *imsi, const char *from, const struct tm *remote,
@@ -277,10 +270,7 @@ static void pf_modem_watch(struct ofono_modem *modem,
if (added != FALSE) {
struct pf_modem *pm;
pm = g_try_new0(struct pf_modem, 1);
if (pm == NULL)
return;
pm = g_new0(struct pf_modem, 1);
pm->modem = modem;
pm->sms_watch_id = __ofono_modem_add_atom_watch(modem,
OFONO_ATOM_TYPE_SMS, pf_sms_watch, pm,
@@ -349,10 +339,7 @@ static void pf_parse_handler(GKeyFile *conf, const char *g)
if (path == NULL)
goto no_path;
h = g_try_new0(struct push_datagram_handler, 1);
if (h == NULL)
goto no_memory;
h = g_new0(struct push_datagram_handler, 1);
h->name = g_strdup(g);
h->interface = interface;
h->service = service;
@@ -385,9 +372,6 @@ static void pf_parse_handler(GKeyFile *conf, const char *g)
handlers = g_slist_append(handlers, h);
return;
no_memory:
g_free(path);
no_path:
g_free(method);
@@ -448,30 +432,11 @@ static void pf_parse_config(void)
g_dir_close(dir);
}
static gboolean pf_inotify(GIOChannel *gio, GIOCondition c, gpointer data)
static void pf_inotify(GUtilInotifyWatch *watch, guint mask, guint cookie,
const char *name, void *user_data)
{
int avail;
gsize len;
void *buf;
GError *error;
if (ioctl(inotify_fd, FIONREAD, &avail) < 0)
return FALSE;
buf = g_try_malloc(avail);
if (buf == NULL)
return FALSE;
error = NULL;
if (g_io_channel_read_chars(gio, buf, avail, &len, &error) !=
G_IO_STATUS_NORMAL) {
g_free(buf);
return FALSE;
}
DBG("'%s' changed (0x%04x)", name, mask);
pf_parse_config();
g_free(buf);
return TRUE;
}
static int pf_plugin_init(void)
@@ -480,37 +445,8 @@ static int pf_plugin_init(void)
pf_parse_config();
modem_watch_id = __ofono_modemwatch_add(pf_modem_watch, NULL, NULL);
__ofono_modem_foreach(pf_modem_init, NULL);
inotify_fd = inotify_init();
if (inotify_fd < 0)
return 0;
inotify_watch_id = inotify_add_watch(inotify_fd,
PF_CONFIG_DIR,
IN_CLOSE_WRITE | IN_DELETE | IN_MOVE);
if (inotify_watch_id < 0)
goto no_inotify_watch_id;
inotify_watch_channel = g_io_channel_unix_new(inotify_fd);
if (inotify_watch_channel == NULL)
goto no_inotify_watch_channel;
g_io_channel_set_encoding(inotify_watch_channel, NULL, NULL);
g_io_channel_set_buffered(inotify_watch_channel, FALSE);
inotify_watch_source_id = g_io_add_watch(inotify_watch_channel,
G_IO_IN, pf_inotify, NULL);
if (inotify_watch_source_id != 0)
return 0;
g_io_channel_unref(inotify_watch_channel);
inotify_watch_channel = NULL;
no_inotify_watch_channel:
inotify_rm_watch(inotify_fd, inotify_watch_id);
inotify_watch_id = -1;
no_inotify_watch_id:
close(inotify_fd);
inotify_fd = -1;
inotify_cb = gutil_inotify_watch_callback_new(PF_CONFIG_DIR,
IN_CLOSE_WRITE | IN_DELETE | IN_MOVE, pf_inotify, NULL);
return 0;
}
@@ -523,19 +459,18 @@ static void pf_plugin_exit(void)
modems = NULL;
g_slist_free_full(handlers, pf_free_handler);
handlers = NULL;
if (inotify_watch_source_id == 0)
return;
g_source_remove(inotify_watch_source_id);
inotify_watch_source_id = 0;
g_io_channel_unref(inotify_watch_channel);
inotify_watch_channel = NULL;
inotify_rm_watch(inotify_fd, inotify_watch_id);
inotify_watch_id = -1;
close(inotify_fd);
inotify_fd = -1;
gutil_inotify_watch_callback_free(inotify_cb);
inotify_cb = NULL;
}
OFONO_PLUGIN_DEFINE(push_forwarder, "Push Forwarder Plugin", VERSION,
OFONO_PLUGIN_DEFINE(pushforwarder, "Push Forwarder Plugin", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT, pf_plugin_init,
pf_plugin_exit)
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -34,6 +34,7 @@
#include <net/route.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <glib.h>
#include <gdbus.h>
@@ -258,6 +259,10 @@ static gboolean gprs_proto_from_string(const char *str,
static const char *gprs_auth_method_to_string(enum ofono_gprs_auth_method auth)
{
switch (auth) {
case OFONO_GPRS_AUTH_METHOD_ANY:
return "any";
case OFONO_GPRS_AUTH_METHOD_NONE:
return "none";
case OFONO_GPRS_AUTH_METHOD_CHAP:
return "chap";
case OFONO_GPRS_AUTH_METHOD_PAP:
@@ -276,6 +281,12 @@ static gboolean gprs_auth_method_from_string(const char *str,
} else if (g_str_equal(str, "pap")) {
*auth = OFONO_GPRS_AUTH_METHOD_PAP;
return TRUE;
} else if (g_str_equal(str, "any")) {
*auth = OFONO_GPRS_AUTH_METHOD_ANY;
return TRUE;
} else if (g_str_equal(str, "none")) {
*auth = OFONO_GPRS_AUTH_METHOD_NONE;
return TRUE;
}
return FALSE;
@@ -641,7 +652,48 @@ static gboolean pri_parse_proxy(struct pri_context *ctx, const char *proxy)
}
g_free(ctx->proxy_host);
ctx->proxy_host = g_strdup(host);
ctx->proxy_host = NULL;
if (host[0] == '0' || strstr(host, ".0")) {
/*
* Some operators provide IP address of the MMS proxy
* prepending zeros to each number shorter then 3 digits,
* e.g. "192.168.094.023" instead of "192.168.94.23".
* That may look nicer but it's actually wrong because
* the numbers starting with zeros are interpreted as
* octal numbers. In the example above 023 actually means
* 16 and 094 is not a valid number at all.
*
* In addition to publishing these broken settings on their
* web sites, some of the operators send them over the air,
* in which case we can't even blame the user for entering
* an invalid IP address. We better be prepared to deal with
* those.
*
* Since nobody in the world seems to be actually using the
* octal notation to write an IP address, let's remove the
* leading zeros if we find them in the host part of the MMS
* proxy URL.
*/
char** parts = g_strsplit(host, ".", -1);
guint count = g_strv_length(parts);
if (count == 4) {
char** ptr = parts;
while (*ptr) {
char* part = *ptr;
while (part[0] == '0' && isdigit(part[1])) {
memmove(part, part+1, strlen(part));
}
*ptr++ = part;
}
ctx->proxy_host = g_strjoinv(".", parts);
DBG("%s => %s", host, ctx->proxy_host);
}
g_strfreev(parts);
}
if (!ctx->proxy_host)
ctx->proxy_host = g_strdup(host);
g_free(scheme);
return TRUE;
@@ -892,6 +944,13 @@ static void pri_reset_context_properties(struct pri_context *ctx,
gprs_proto_to_string(ctx->context.proto));
}
if (ctx->context.auth_method != ap->auth_method) {
ctx->context.auth_method = ap->auth_method;
changed = TRUE;
pri_str_signal_change(ctx, "AuthenticationMethod",
gprs_auth_method_to_string(ctx->context.auth_method));
}
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
if (pri_str_update(ctx->message_proxy, ap->message_proxy,
sizeof(ctx->message_proxy))) {
@@ -2274,6 +2333,11 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
const char *path;
enum ofono_gprs_context_type type;
#ifdef DISABLE_ADD_REMOVE_CONTEXT
ofono_error("AddContext not allowed");
return __ofono_error_not_supported(msg);
#endif
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &typestr,
DBUS_TYPE_INVALID))
return __ofono_error_invalid_args(msg);
@@ -2355,6 +2419,11 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
const char *path;
const char *atompath;
#ifdef DISABLE_ADD_REMOVE_CONTEXT
ofono_error("RemoveContext not allowed");
return __ofono_error_not_supported(msg);
#endif
if (gprs->pending)
return __ofono_error_busy(msg);

View File

@@ -143,7 +143,7 @@ void ofono_debug(const char *format, ...)
}
}
void __ofono_dbg(const struct ofono_debug_desc *desc, const char *format, ...)
void ofono_dbg(const struct ofono_debug_desc *desc, const char *format, ...)
{
va_list ap;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
* oFono - Open Source Telephony
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,16 +13,23 @@
* GNU General Public License for more details.
*/
#include "ril_mtu.h"
#include "ril_log.h"
#include "mtu-watch.h"
#include <net/if.h>
#include <ofono/log.h>
#include <glib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <net/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
struct ril_mtu_watch {
struct mtu_watch {
int max_mtu;
char *ifname;
void *buf;
@@ -32,7 +39,7 @@ struct ril_mtu_watch {
int fd;
};
static void ril_mtu_watch_limit_mtu(struct ril_mtu_watch *self)
static void mtu_watch_limit_mtu(struct mtu_watch *self)
{
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd >= 0) {
@@ -52,7 +59,7 @@ static void ril_mtu_watch_limit_mtu(struct ril_mtu_watch *self)
}
}
static void ril_mtu_watch_handle_rtattr(struct ril_mtu_watch *self,
static void mtu_watch_handle_rtattr(struct mtu_watch *self,
const struct rtattr *rta, int len)
{
int mtu = 0;
@@ -70,43 +77,43 @@ static void ril_mtu_watch_handle_rtattr(struct ril_mtu_watch *self,
}
if (mtu > self->max_mtu && !g_strcmp0(ifname, self->ifname)) {
DBG("%s %d", ifname, mtu);
ril_mtu_watch_limit_mtu(self);
mtu_watch_limit_mtu(self);
}
}
static void ril_mtu_watch_handle_ifinfomsg(struct ril_mtu_watch *self,
static void mtu_watch_handle_ifinfomsg(struct mtu_watch *self,
const struct ifinfomsg *ifi, int len)
{
if (ifi->ifi_flags & IFF_UP) {
const struct rtattr *rta = IFLA_RTA(ifi);
ril_mtu_watch_handle_rtattr(self, rta,
mtu_watch_handle_rtattr(self, rta,
len - ((char*)rta - (char*)ifi));
}
}
static void ril_mtu_watch_handle_nlmsg(struct ril_mtu_watch *self,
static void mtu_watch_handle_nlmsg(struct mtu_watch *self,
const struct nlmsghdr *hdr, int len)
{
while (len > 0 && NLMSG_OK(hdr, len)) {
if (hdr->nlmsg_type == RTM_NEWLINK) {
ril_mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr),
mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr),
IFLA_PAYLOAD(hdr));
}
hdr = NLMSG_NEXT(hdr, len);
}
}
static gboolean ril_mtu_watch_event(GIOChannel *ch, GIOCondition cond,
static gboolean mtu_watch_event(GIOChannel *ch, GIOCondition cond,
gpointer data)
{
struct ril_mtu_watch *self = data;
struct mtu_watch *self = data;
struct sockaddr_nl addr;
socklen_t addrlen = sizeof(addr);
ssize_t result = recvfrom(self->fd, self->buf, self->bufsize, 0,
(struct sockaddr *)&addr, &addrlen);
if (result > 0) {
if (!addr.nl_pid) {
ril_mtu_watch_handle_nlmsg(self, self->buf, result);
mtu_watch_handle_nlmsg(self, self->buf, result);
}
return G_SOURCE_CONTINUE;
} else if (result == 0 || errno == EINTR || errno == EAGAIN) {
@@ -118,9 +125,8 @@ static gboolean ril_mtu_watch_event(GIOChannel *ch, GIOCondition cond,
}
}
static gboolean ril_mtu_watch_open_socket(struct ril_mtu_watch *self)
static gboolean mtu_watch_open_socket(struct mtu_watch *self)
{
GASSERT(self->fd < 0);
self->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (self->fd >= 0) {
struct sockaddr_nl nl;
@@ -140,20 +146,18 @@ static gboolean ril_mtu_watch_open_socket(struct ril_mtu_watch *self)
return FALSE;
}
static gboolean ril_mtu_watch_start(struct ril_mtu_watch *self)
static gboolean mtu_watch_start(struct mtu_watch *self)
{
if (self->fd >= 0) {
return TRUE;
} else if (ril_mtu_watch_open_socket(self)) {
GASSERT(!self->channel);
GASSERT(!self->io_watch);
} else if (mtu_watch_open_socket(self)) {
self->channel = g_io_channel_unix_new(self->fd);
if (self->channel) {
g_io_channel_set_encoding(self->channel, NULL, NULL);
g_io_channel_set_buffered(self->channel, FALSE);
self->io_watch = g_io_add_watch(self->channel,
G_IO_IN | G_IO_NVAL | G_IO_HUP,
ril_mtu_watch_event, self);
mtu_watch_event, self);
return TRUE;
}
close(self->fd);
@@ -162,7 +166,7 @@ static gboolean ril_mtu_watch_start(struct ril_mtu_watch *self)
return FALSE;
}
static void ril_mtu_watch_stop(struct ril_mtu_watch *self)
static void mtu_watch_stop(struct mtu_watch *self)
{
if (self->io_watch) {
g_source_remove(self->io_watch);
@@ -179,9 +183,9 @@ static void ril_mtu_watch_stop(struct ril_mtu_watch *self)
}
}
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu)
struct mtu_watch *mtu_watch_new(int max_mtu)
{
struct ril_mtu_watch *self = g_new0(struct ril_mtu_watch, 1);
struct mtu_watch *self = g_new0(struct mtu_watch, 1);
self->fd = -1;
self->max_mtu = max_mtu;
self->bufsize = 4096;
@@ -189,35 +193,27 @@ struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu)
return self;
}
void ril_mtu_watch_free(struct ril_mtu_watch *self)
void mtu_watch_free(struct mtu_watch *self)
{
if (self) {
ril_mtu_watch_stop(self);
mtu_watch_stop(self);
g_free(self->ifname);
g_free(self->buf);
g_free(self);
}
}
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *self, const char *ifname)
void mtu_watch_set_ifname(struct mtu_watch *self, const char *ifname)
{
if (self && g_strcmp0(self->ifname, ifname)) {
g_free(self->ifname);
if (ifname) {
self->ifname = g_strdup(ifname);
ril_mtu_watch_limit_mtu(self);
ril_mtu_watch_start(self);
mtu_watch_limit_mtu(self);
mtu_watch_start(self);
} else {
self->ifname = NULL;
ril_mtu_watch_stop(self);
mtu_watch_stop(self);
}
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

25
ofono/src/mtu-watch.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 MTU_WATCH_H
#define MTU_WATCH_H
struct mtu_watch;
struct mtu_watch *mtu_watch_new(int max_mtu);
void mtu_watch_free(struct mtu_watch *mw);
void mtu_watch_set_ifname(struct mtu_watch *mw, const char *ifname);
#endif /* MTU_WATCH_H */

View File

@@ -1828,6 +1828,17 @@ const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg)
return netreg->current_operator->mnc;
}
const char *ofono_netreg_get_name(struct ofono_netreg *netreg)
{
if (netreg == NULL)
return NULL;
if (netreg->current_operator == NULL)
return NULL;
return netreg->current_operator->name;
}
struct sim_spdi *ofono_netreg_get_spdi(struct ofono_netreg *netreg)
{
if (netreg == NULL)

View File

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

View File

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

View File

@@ -197,7 +197,10 @@ static gboolean password_is_pin(enum ofono_sim_password_type type)
return FALSE;
}
static enum ofono_sim_password_type puk2pin(enum ofono_sim_password_type type)
#define puk2pin(type) __ofono_sim_puk2pin(type)
enum ofono_sim_password_type __ofono_sim_puk2pin(
enum ofono_sim_password_type type)
{
switch (type) {
case OFONO_SIM_PASSWORD_SIM_PUK:

View File

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

View File

@@ -1182,7 +1182,8 @@ static gboolean compute_incoming_msgid(GSList *sms_list,
static void dispatch_app_datagram(struct ofono_sms *sms,
const struct ofono_uuid *uuid,
int dst, int src,
unsigned char *buf, unsigned len,
const unsigned char *buf,
unsigned int len,
const struct sms_address *addr,
const struct sms_scts *scts)
{

View File

@@ -4134,12 +4134,13 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
*/
for (; i < written; i++, bufsize++) {
if (unpacked[i] == '\r') {
int t;
int j;
t = strspn((const char *) unpacked + i,
"\r");
for (j = i + 1; j < written; j++)
if (unpacked[j] != '\r')
break;
if (t + i == written)
if (j == written)
break;
}

View File

@@ -28,6 +28,11 @@
#include <fcntl.h>
#include <sys/types.h>
/* STORAGEDIR may need to be redefined in unit tests */
#ifndef STORAGEDIR
# define STORAGEDIR DEFAULT_STORAGEDIR
#endif
int create_dirs(const char *filename, const mode_t mode);
ssize_t read_file(unsigned char *buffer, size_t len,

View File

@@ -514,6 +514,20 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs,
DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
ussd_change_state(ussd, new_state);
goto free;
} else if (ussd->state == USSD_STATE_USER_ACTION &&
status != OFONO_USSD_STATUS_ACTION_REQUIRED) {
ussd_change_state(ussd, USSD_STATE_IDLE);
if (status == OFONO_USSD_STATUS_NOTIFY && str && str[0]) {
const char *path = __ofono_atom_get_path(ussd->atom);
g_dbus_emit_signal(conn, path,
OFONO_SUPPLEMENTARY_SERVICES_INTERFACE,
"NotificationReceived", DBUS_TYPE_STRING,
&str, DBUS_TYPE_INVALID);
}
goto free;
} else {
ofono_error("Received an unsolicited USSD but can't handle.");

View File

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

62
ofono/unit/coverage Executable file
View File

@@ -0,0 +1,62 @@
#!/bin/bash
#
# Script to generate unit test coverage report, requires lcov:
#
# http://ltp.sourceforge.net/coverage/lcov.php
#
# Tests with coverage enabled:
TESTS="\
test-common \
test-util \
test-idmap \
test-simutil \
test-stkutil \
test-sms \
test-cdmasms \
test-sms-root \
test-caif \
test-provision \
test-ril_util \
test-sailfish_cell_info \
test-sailfish_manager \
test-sailfish_sim_info"
pushd `dirname $0` > /dev/null
TEST_DIR="$PWD"
pushd .. > /dev/null
BASE_DIR="$PWD"
popd > /dev/null
popd > /dev/null
FULL_COV="$TEST_DIR/full.gcov"
DRIVERS_COV="$TEST_DIR/drivers.gcov"
PLUGINS_COV="$TEST_DIR/plugins.gcov"
SRC_COV="$TEST_DIR/src.gcov"
OUT="$TEST_DIR/html"
# Clean everything up
find "$BASE_DIR" -name "*.gcda" -exec rm {} \;
rm -f "$FULL_COV" "$DRIVERS_COV" "$PLUGINS_COV" "$SRC_COV"
rm -fr "$OUT"
# Run the tests
for t in $TESTS ; do
pushd "$TEST_DIR" > /dev/null
"$TEST_DIR/$t"
RC=$?
popd > /dev/null
[ $RC = 0 ] || exit 1
done
# LCOV 1.10 has branch coverage disabled per default
LCOV_OPT="--rc lcov_branch_coverage=1"
GENHTML_OPT="--branch-coverage"
lcov $LCOV_OPT -c -d "$BASE_DIR" -o "$FULL_COV" || exit 1
lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/drivers/*" -o "$DRIVERS_COV" || exit 1
lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/plugins/*" -o "$PLUGINS_COV" || exit 1
lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/src/*" -o "$SRC_COV" || exit 1
genhtml $GENHTML_OPT -t ofono "$DRIVERS_COV" "$PLUGINS_COV" "$SRC_COV" --output-directory "$OUT" || exit 1
echo Coverage report: $OUT/index.html

View File

@@ -0,0 +1,326 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "fake_sailfish_watch.h"
#include <gutil_misc.h>
#include <gutil_log.h>
#include "ofono.h"
typedef GObjectClass SailfishWatchClass;
typedef struct sailfish_watch SailfishWatch;
struct sailfish_watch_priv {
char *path;
char *iccid;
char *imsi;
char *spn;
int queued_signals;
};
#define SIGNAL_MODEM_CHANGED_NAME "sailfish-watch-modem-changed"
#define SIGNAL_ONLINE_CHANGED_NAME "sailfish-watch-online-changed"
#define SIGNAL_SIM_CHANGED_NAME "sailfish-watch-sim-changed"
#define SIGNAL_SIM_STATE_CHANGED_NAME "sailfish-watch-sim-state-changed"
#define SIGNAL_ICCID_CHANGED_NAME "sailfish-watch-iccid-changed"
#define SIGNAL_IMSI_CHANGED_NAME "sailfish-watch-imsi-changed"
#define SIGNAL_SPN_CHANGED_NAME "sailfish-watch-spn-changed"
#define SIGNAL_NETREG_CHANGED_NAME "sailfish-watch-netreg-changed"
static guint sailfish_watch_signals[WATCH_SIGNAL_COUNT] = { 0 };
static GHashTable* sailfish_watch_table = NULL;
G_DEFINE_TYPE(SailfishWatch, sailfish_watch, G_TYPE_OBJECT)
#define SAILFISH_WATCH_TYPE (sailfish_watch_get_type())
#define SAILFISH_WATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
SAILFISH_WATCH_TYPE, SailfishWatch))
#define NEW_SIGNAL(klass,name) \
sailfish_watch_signals[WATCH_SIGNAL_##name##_CHANGED] = \
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
static inline int sailfish_watch_signal_bit(enum sailfish_watch_signal id)
{
return (1 << id);
}
static inline void sailfish_watch_signal_emit(struct sailfish_watch *self,
enum sailfish_watch_signal id)
{
self->priv->queued_signals &= ~sailfish_watch_signal_bit(id);
g_signal_emit(self, sailfish_watch_signals[id], 0);
}
void fake_sailfish_watch_signal_queue(struct sailfish_watch *self,
enum sailfish_watch_signal id)
{
self->priv->queued_signals |= sailfish_watch_signal_bit(id);
}
void fake_sailfish_watch_emit_queued_signals(struct sailfish_watch *self)
{
struct sailfish_watch_priv *priv = self->priv;
int i;
for (i = 0; priv->queued_signals && i < WATCH_SIGNAL_COUNT; i++) {
if (priv->queued_signals & sailfish_watch_signal_bit(i)) {
sailfish_watch_signal_emit(self, i);
}
}
}
void fake_sailfish_watch_set_ofono_iccid(struct sailfish_watch *self,
const char *iccid)
{
struct sailfish_watch_priv *priv = self->priv;
if (g_strcmp0(priv->iccid, iccid)) {
g_free(priv->iccid);
self->iccid = priv->iccid = g_strdup(iccid);
fake_sailfish_watch_signal_queue(self,
WATCH_SIGNAL_ICCID_CHANGED);
}
}
void fake_sailfish_watch_set_ofono_imsi(struct sailfish_watch *self,
const char *imsi)
{
struct sailfish_watch_priv *priv = self->priv;
if (g_strcmp0(priv->imsi, imsi)) {
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(imsi);
fake_sailfish_watch_signal_queue(self,
WATCH_SIGNAL_IMSI_CHANGED);
}
}
void fake_sailfish_watch_set_ofono_spn(struct sailfish_watch *self,
const char *spn)
{
struct sailfish_watch_priv *priv = self->priv;
if (g_strcmp0(priv->spn, spn)) {
g_free(priv->spn);
self->spn = priv->spn = g_strdup(spn);
fake_sailfish_watch_signal_queue(self,
WATCH_SIGNAL_SPN_CHANGED);
}
}
void fake_sailfish_watch_set_ofono_sim(struct sailfish_watch *self,
struct ofono_sim *sim)
{
if (self->sim != sim) {
self->sim = sim;
fake_sailfish_watch_signal_queue(self,
WATCH_SIGNAL_SIM_CHANGED);
if (!sim) {
fake_sailfish_watch_set_ofono_iccid(self, NULL);
fake_sailfish_watch_set_ofono_imsi(self, NULL);
fake_sailfish_watch_set_ofono_spn(self, NULL);
}
}
}
void fake_sailfish_watch_set_ofono_netreg(struct sailfish_watch *self,
struct ofono_netreg *netreg)
{
if (self->netreg != netreg) {
self->netreg = netreg;
fake_sailfish_watch_signal_queue(self,
WATCH_SIGNAL_NETREG_CHANGED);
}
}
static void sailfish_watch_initialize(struct sailfish_watch *self,
const char *path)
{
struct sailfish_watch_priv *priv = self->priv;
self->path = priv->path = g_strdup(path);
}
static void sailfish_watch_destroyed(gpointer key, GObject* obj)
{
GASSERT(sailfish_watch_table);
DBG("%s", (char*)key);
if (sailfish_watch_table) {
GASSERT(g_hash_table_lookup(sailfish_watch_table, key) == obj);
g_hash_table_remove(sailfish_watch_table, key);
if (g_hash_table_size(sailfish_watch_table) == 0) {
g_hash_table_unref(sailfish_watch_table);
sailfish_watch_table = NULL;
}
}
}
struct sailfish_watch *sailfish_watch_new(const char *path)
{
struct sailfish_watch *watch = NULL;
if (path) {
if (sailfish_watch_table) {
watch = sailfish_watch_ref(g_hash_table_lookup(
sailfish_watch_table, path));
}
if (!watch) {
char* key = g_strdup(path);
watch = g_object_new(SAILFISH_WATCH_TYPE, NULL);
sailfish_watch_initialize(watch, path);
if (!sailfish_watch_table) {
/* Create the table on demand */
sailfish_watch_table =
g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, NULL);
}
g_hash_table_replace(sailfish_watch_table, key, watch);
g_object_weak_ref(G_OBJECT(watch),
sailfish_watch_destroyed, key);
DBG_(watch, "created");
}
}
return watch;
}
struct sailfish_watch *sailfish_watch_ref(struct sailfish_watch *self)
{
if (self) {
g_object_ref(SAILFISH_WATCH(self));
}
return self;
}
void sailfish_watch_unref(struct sailfish_watch *self)
{
if (self) {
g_object_unref(SAILFISH_WATCH(self));
}
}
gulong sailfish_watch_add_modem_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_MODEM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_online_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_sim_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_SIM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_sim_state_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_SIM_STATE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_iccid_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_imsi_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_spn_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
gulong sailfish_watch_add_netreg_changed_handler(struct sailfish_watch *self,
sailfish_watch_cb_t cb, void *user_data)
{
return (self && cb) ? g_signal_connect(self,
SIGNAL_NETREG_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
}
void sailfish_watch_remove_handler(struct sailfish_watch *self, gulong id)
{
if (self && id) {
g_signal_handler_disconnect(self, id);
}
}
void sailfish_watch_remove_handlers(struct sailfish_watch *self, gulong *ids,
int count)
{
gutil_disconnect_handlers(self, ids, count);
}
static void sailfish_watch_init(struct sailfish_watch *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SAILFISH_WATCH_TYPE,
struct sailfish_watch_priv);
}
static void sailfish_watch_finalize(GObject *object)
{
struct sailfish_watch *self = SAILFISH_WATCH(object);
struct sailfish_watch_priv *priv = self->priv;
g_free(priv->path);
g_free(priv->iccid);
g_free(priv->imsi);
g_free(priv->spn);
G_OBJECT_CLASS(sailfish_watch_parent_class)->finalize(object);
}
static void sailfish_watch_class_init(SailfishWatchClass *klass)
{
G_OBJECT_CLASS(klass)->finalize = sailfish_watch_finalize;
g_type_class_add_private(klass, sizeof(struct sailfish_watch_priv));
NEW_SIGNAL(klass, MODEM);
NEW_SIGNAL(klass, ONLINE);
NEW_SIGNAL(klass, SIM);
NEW_SIGNAL(klass, SIM_STATE);
NEW_SIGNAL(klass, ICCID);
NEW_SIGNAL(klass, IMSI);
NEW_SIGNAL(klass, SPN);
NEW_SIGNAL(klass, NETREG);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,55 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef SAILFISH_FAKE_WATCH_H
#define SAILFISH_FAKE_WATCH_H
#include "sailfish_watch.h"
enum sailfish_watch_signal {
WATCH_SIGNAL_MODEM_CHANGED,
WATCH_SIGNAL_ONLINE_CHANGED,
WATCH_SIGNAL_SIM_CHANGED,
WATCH_SIGNAL_SIM_STATE_CHANGED,
WATCH_SIGNAL_ICCID_CHANGED,
WATCH_SIGNAL_IMSI_CHANGED,
WATCH_SIGNAL_SPN_CHANGED,
WATCH_SIGNAL_NETREG_CHANGED,
WATCH_SIGNAL_COUNT
};
void fake_sailfish_watch_signal_queue(struct sailfish_watch *watch,
enum sailfish_watch_signal id);
void fake_sailfish_watch_emit_queued_signals(struct sailfish_watch *watch);
void fake_sailfish_watch_set_ofono_sim(struct sailfish_watch *watch,
struct ofono_sim *sim);
void fake_sailfish_watch_set_ofono_iccid(struct sailfish_watch *watch,
const char *iccid);
void fake_sailfish_watch_set_ofono_imsi(struct sailfish_watch *watch,
const char *imsi);
void fake_sailfish_watch_set_ofono_spn(struct sailfish_watch *watch,
const char *spn);
void fake_sailfish_watch_set_ofono_netreg(struct sailfish_watch *watch,
struct ofono_netreg *netreg);
#endif /* FAKE_SAILFISH_WATCH_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

File diff suppressed because it is too large Load Diff

128
ofono/unit/test-ril_util.c Normal file
View File

@@ -0,0 +1,128 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "drivers/ril/ril_util.h"
#include "ofono.h"
#include "common.h"
void test_parse_tech(void)
{
int tech = 0;
g_assert(ril_parse_tech(NULL, NULL) == -1);
g_assert(ril_parse_tech(NULL, &tech) == -1);
g_assert(tech == -1);
g_assert(ril_parse_tech("-1", &tech) == -1);
g_assert(tech == -1);
g_assert(ril_parse_tech("0", &tech) == -1);
g_assert(tech == -1);
g_assert(ril_parse_tech("1", &tech) == ACCESS_TECHNOLOGY_GSM);
g_assert(tech == RADIO_TECH_GPRS);
g_assert(ril_parse_tech("16", &tech) == ACCESS_TECHNOLOGY_GSM);
g_assert(tech == RADIO_TECH_GSM);
g_assert(ril_parse_tech("2", &tech) == ACCESS_TECHNOLOGY_GSM_EGPRS);
g_assert(tech == RADIO_TECH_EDGE);
g_assert(ril_parse_tech("3", &tech) == ACCESS_TECHNOLOGY_UTRAN);
g_assert(tech == RADIO_TECH_UMTS);
g_assert(ril_parse_tech("9", &tech) == ACCESS_TECHNOLOGY_UTRAN_HSDPA);
g_assert(tech == RADIO_TECH_HSDPA);
g_assert(ril_parse_tech("10", &tech) == ACCESS_TECHNOLOGY_UTRAN_HSUPA);
g_assert(tech == RADIO_TECH_HSUPA);
g_assert(ril_parse_tech("11", &tech) ==
ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA);
g_assert(tech == RADIO_TECH_HSPA);
g_assert(ril_parse_tech("15", &tech) ==
ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA);
g_assert(tech == RADIO_TECH_HSPAP);
g_assert(ril_parse_tech("14", &tech) == ACCESS_TECHNOLOGY_EUTRAN);
g_assert(tech == RADIO_TECH_LTE);
}
void test_parse_mcc_mnc(void)
{
struct ofono_network_operator op;
memset(&op, 0, sizeof(op));
g_assert(!ril_parse_mcc_mnc(NULL, &op));
g_assert(!ril_parse_mcc_mnc("", &op));
g_assert(!ril_parse_mcc_mnc("24x", &op));
g_assert(!ril_parse_mcc_mnc("244", &op));
g_assert(!ril_parse_mcc_mnc("244x", &op));
g_assert(ril_parse_mcc_mnc("24412", &op));
g_assert(!strcmp(op.mcc, "244"));
g_assert(!strcmp(op.mnc, "12"));
g_assert(!op.tech);
g_assert(ril_parse_mcc_mnc("25001+", &op));
g_assert(!strcmp(op.mcc, "250"));
g_assert(!strcmp(op.mnc, "01"));
g_assert(!op.tech);
g_assert(ril_parse_mcc_mnc("25503+14", &op));
g_assert(!strcmp(op.mcc, "255"));
g_assert(!strcmp(op.mnc, "03"));
g_assert(op.tech == ACCESS_TECHNOLOGY_EUTRAN);
/* Not sure if this is right but that's now it currently works: */
op.tech = 0;
g_assert(ril_parse_mcc_mnc("3101500", &op));
g_assert(!strcmp(op.mcc, "310"));
g_assert(!strcmp(op.mnc, "150"));
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));
}
#define TEST_(name) "/ril_util/" 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_("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);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,203 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <sailfish_cell_info.h>
#include <gutil_log.h>
/* Fake sailfish_cell_info */
#define FAKE_HANDLER_ID (1)
static int fake_sailfish_cell_info_ref_count = 0;
static void fake_sailfish_cell_info_ref(struct sailfish_cell_info *info)
{
g_assert(fake_sailfish_cell_info_ref_count >= 0);
fake_sailfish_cell_info_ref_count++;
}
static void fake_sailfish_cell_info_unref(struct sailfish_cell_info *info)
{
g_assert(fake_sailfish_cell_info_ref_count > 0);
fake_sailfish_cell_info_ref_count--;
}
static gulong fake_sailfish_cell_info_add_cells_changed_handler
(struct sailfish_cell_info *info, sailfish_cell_info_cb_t cb, void *arg)
{
return FAKE_HANDLER_ID;
}
static void fake_sailfish_cell_info_remove_handler
(struct sailfish_cell_info *info, gulong id)
{
g_assert(id == FAKE_HANDLER_ID);
}
static const struct sailfish_cell_info_proc fake_sailfish_cell_info_proc = {
fake_sailfish_cell_info_ref,
fake_sailfish_cell_info_unref,
fake_sailfish_cell_info_add_cells_changed_handler,
fake_sailfish_cell_info_remove_handler
};
static struct sailfish_cell_info fake_sailfish_cell_info = {
&fake_sailfish_cell_info_proc,
NULL
};
/* ==== basic ==== */
static void test_basic(void)
{
/* NULL resistance */
g_assert(!sailfish_cell_info_ref(NULL));
sailfish_cell_info_unref(NULL);
g_assert(!sailfish_cell_compare_func(NULL, NULL));
g_assert(!sailfish_cell_info_add_cells_changed_handler(NULL, NULL,
NULL));
sailfish_cell_info_remove_handler(NULL, 0);
/* Make sure that callbacks are being invoked */
g_assert(sailfish_cell_info_ref(&fake_sailfish_cell_info) ==
&fake_sailfish_cell_info);
g_assert(fake_sailfish_cell_info_ref_count == 1);
g_assert(sailfish_cell_info_add_cells_changed_handler(
&fake_sailfish_cell_info, NULL, NULL) == FAKE_HANDLER_ID);
sailfish_cell_info_remove_handler(&fake_sailfish_cell_info,
FAKE_HANDLER_ID);
sailfish_cell_info_unref(&fake_sailfish_cell_info);
g_assert(!fake_sailfish_cell_info_ref_count);
}
/* ==== compare ==== */
static void test_compare(void)
{
struct sailfish_cell c1, c2;
memset(&c1, 0, sizeof(c1));
memset(&c2, 0, sizeof(c2));
g_assert(!sailfish_cell_compare_location(NULL, NULL));
g_assert(sailfish_cell_compare_location(&c1, NULL) > 0);
g_assert(sailfish_cell_compare_location(NULL, &c2) < 0);
c1.type = SAILFISH_CELL_TYPE_GSM;
c2.type = SAILFISH_CELL_TYPE_WCDMA;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
g_assert(sailfish_cell_compare_location(&c2, &c1) > 0);
/* GSM */
c1.type = SAILFISH_CELL_TYPE_GSM;
c2 = c1;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.gsm.mcc++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.gsm.mnc++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.gsm.lac++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.gsm.cid++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
/* Other attributes are not being compared */
c2 = c1; c2.info.gsm.arfcn++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.gsm.bsic++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.gsm.signalStrength++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.gsm.bitErrorRate++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.gsm.bitErrorRate++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
/* WCDMA */
c1.type = SAILFISH_CELL_TYPE_WCDMA;
c2 = c1;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.wcdma.mcc++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.wcdma.mnc++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.wcdma.lac++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.wcdma.cid++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
/* Other attributes are not being compared */
c2 = c1; c2.info.wcdma.psc++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.wcdma.uarfcn++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.wcdma.signalStrength++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.wcdma.bitErrorRate++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
/* LTE */
c1.type = SAILFISH_CELL_TYPE_LTE;
c2 = c1;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.lte.mcc++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.lte.mnc++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.lte.ci++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.lte.pci++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.lte.tac++;
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
/* Other attributes are not being compared */
c2 = c1; c2.info.lte.earfcn++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.lte.signalStrength++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.lte.rsrp++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.lte.rsrq++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.lte.rssnr++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.lte.cqi++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.lte.timingAdvance++;
g_assert(!sailfish_cell_compare_location(&c1, &c2));
}
#define TEST_(name) "/sailfish_cell_info/" 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;
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("compare"), test_compare);
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

@@ -0,0 +1,442 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "sailfish_sim_info.h"
#include "fake_sailfish_watch.h"
#define OFONO_API_SUBJECT_TO_CHANGE
#include "ofono.h"
#include "common.h"
#include <gutil_log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define TEST_PATH "/test"
#define TEST_ICCID "1111111111111111111"
#define TEST_IMSI "244120000000000"
#define TEST_MCC "244"
#define TEST_MNC "12"
#define TEST_DEFAULT_SPN TEST_MCC TEST_MNC
#define TEST_SPN "Test"
#define ICCID_MAP STORAGEDIR "/iccidmap"
#define SIM_CACHE STORAGEDIR "/" TEST_IMSI "/cache"
enum sim_info_signals {
SIM_INFO_SIGNAL_ICCID_CHANGED,
SIM_INFO_SIGNAL_IMSI_CHANGED,
SIM_INFO_SIGNAL_SPN_CHANGED,
SIM_INFO_SIGNAL_COUNT
};
/* Fake ofono_sim */
struct ofono_sim {
const char *mcc;
const char *mnc;
const char *spn;
enum ofono_sim_state state;
};
enum ofono_sim_state ofono_sim_get_state(struct ofono_sim *sim)
{
return sim ? sim->state : OFONO_SIM_STATE_NOT_PRESENT;
}
const char *ofono_sim_get_mcc(struct ofono_sim *sim)
{
return sim ? sim->mcc : NULL;
}
const char *ofono_sim_get_mnc(struct ofono_sim *sim)
{
return sim ? sim->mnc : NULL;
}
/* Fake ofono_netreg */
struct ofono_netreg {
const char *mcc;
const char *mnc;
const char *name;
int location;
int cellid;
enum ofono_radio_access_mode technology;
enum network_registration_status status;
struct ofono_watchlist *status_watches;
};
int ofono_netreg_get_status(struct ofono_netreg *netreg)
{
return netreg ? netreg->status : -1;
}
const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg)
{
return netreg ? netreg->mcc : NULL;
}
const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg)
{
return netreg ? netreg->mnc : NULL;
}
const char *ofono_netreg_get_name(struct ofono_netreg *netreg)
{
return netreg ? netreg->name : NULL;
}
unsigned int __ofono_netreg_add_status_watch(struct ofono_netreg *netreg,
ofono_netreg_status_notify_cb_t notify,
void *data, ofono_destroy_func destroy)
{
struct ofono_watchlist_item *item =
g_new0(struct ofono_watchlist_item, 1);
DBG("%p", netreg);
g_assert(netreg);
g_assert(notify);
item->notify = notify;
item->destroy = destroy;
item->notify_data = data;
return __ofono_watchlist_add_item(netreg->status_watches, item);
}
gboolean __ofono_netreg_remove_status_watch(struct ofono_netreg *netreg,
unsigned int id)
{
return __ofono_watchlist_remove_item(netreg->status_watches, id);
}
/* Utilities */
static int rmdir_r(const char *path)
{
DIR *d = opendir(path);
if (d) {
const struct dirent *p;
int r = 0;
while (!r && (p = readdir(d))) {
char *buf;
struct stat st;
if (!strcmp(p->d_name, ".") ||
!strcmp(p->d_name, "..")) {
continue;
}
buf = g_strdup_printf("%s/%s", path, p->d_name);
if (!stat(buf, &st)) {
r = S_ISDIR(st.st_mode) ? rmdir_r(buf) :
unlink(buf);
}
g_free(buf);
}
closedir(d);
return r ? r : rmdir(path);
} else {
return -1;
}
}
static void netreg_notify_status_watches(struct ofono_netreg *netreg)
{
GSList *l;
const char *mcc = netreg->mcc;
const char *mnc = netreg->mnc;
for (l = netreg->status_watches->items; l; l = l->next) {
struct ofono_watchlist_item *item = l->data;
ofono_netreg_status_notify_cb_t notify = item->notify;
notify(netreg->status, netreg->location, netreg->cellid,
netreg->technology, mcc, mnc, item->notify_data);
}
}
/* Test cases */
static void test_basic(void)
{
struct sailfish_sim_info *si;
/* NULL tolerance */
g_assert(!sailfish_sim_info_new(NULL));
g_assert(!sailfish_sim_info_ref(NULL));
sailfish_sim_info_unref(NULL);
sailfish_sim_info_invalidate(NULL);
g_assert(!sailfish_sim_info_add_iccid_changed_handler(NULL,NULL,NULL));
g_assert(!sailfish_sim_info_add_imsi_changed_handler(NULL,NULL,NULL));
g_assert(!sailfish_sim_info_add_spn_changed_handler(NULL,NULL,NULL));
sailfish_sim_info_remove_handler(NULL, 0);
sailfish_sim_info_remove_handlers(NULL, NULL, 0);
/* Very basic things (mostly to improve code coverage) */
si = sailfish_sim_info_new("/test");
g_assert(si);
sailfish_sim_info_invalidate(si);
g_assert(!sailfish_sim_info_add_iccid_changed_handler(si,NULL,NULL));
g_assert(!sailfish_sim_info_add_imsi_changed_handler(si,NULL,NULL));
g_assert(!sailfish_sim_info_add_spn_changed_handler(si,NULL,NULL));
sailfish_sim_info_remove_handler(si, 0);
sailfish_sim_info_remove_handlers(si, NULL, 0);
sailfish_sim_info_unref(sailfish_sim_info_ref(si));
sailfish_sim_info_unref(si);
}
static void test_signal_count_cb(struct sailfish_sim_info *si, void *data)
{
(*((int*)data))++;
}
static void test_cache(void)
{
struct sailfish_sim_info *si;
struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
struct ofono_sim sim;
struct stat st;
gulong id[SIM_INFO_SIGNAL_COUNT];
int count[SIM_INFO_SIGNAL_COUNT];
memset(id, 0, sizeof(id));
memset(count, 0, sizeof(count));
memset(&sim, 0, sizeof(sim));
sim.state = OFONO_SIM_STATE_INSERTED;
rmdir_r(STORAGEDIR);
si = sailfish_sim_info_new(TEST_PATH);
id[SIM_INFO_SIGNAL_ICCID_CHANGED] =
sailfish_sim_info_add_iccid_changed_handler(si,
test_signal_count_cb, count +
SIM_INFO_SIGNAL_ICCID_CHANGED);
id[SIM_INFO_SIGNAL_IMSI_CHANGED] =
sailfish_sim_info_add_imsi_changed_handler(si,
test_signal_count_cb, count +
SIM_INFO_SIGNAL_IMSI_CHANGED);
id[SIM_INFO_SIGNAL_SPN_CHANGED] =
sailfish_sim_info_add_spn_changed_handler(si,
test_signal_count_cb, count +
SIM_INFO_SIGNAL_SPN_CHANGED);
fake_sailfish_watch_set_ofono_sim(w, &sim);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!g_strcmp0(si->iccid, TEST_ICCID));
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
g_assert(stat(ICCID_MAP, &st) < 0);
count[SIM_INFO_SIGNAL_ICCID_CHANGED] = 0;
fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!g_strcmp0(si->imsi, TEST_IMSI));
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
count[SIM_INFO_SIGNAL_IMSI_CHANGED] = 0;
/* ICCID mape appears */
g_assert(stat(ICCID_MAP, &st) == 0);
g_assert(S_ISREG(st.st_mode));
/* But no cache yet */
g_assert(stat(SIM_CACHE, &st) < 0);
/* This will generate default SPN out of MCC and MNC */
sim.mcc = TEST_MCC;
sim.mnc = TEST_MNC;
sim.state = OFONO_SIM_STATE_READY;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!g_strcmp0(si->spn, TEST_DEFAULT_SPN));
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
count[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
/* Replace default SPN with the real one */
fake_sailfish_watch_set_ofono_spn(w, TEST_SPN);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!g_strcmp0(si->spn, TEST_SPN));
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
count[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
/* Cache file appears */
g_assert(stat(SIM_CACHE, &st) == 0);
g_assert(S_ISREG(st.st_mode));
/* Reset the information */
sim.mcc = NULL;
sim.mnc = NULL;
sim.state = OFONO_SIM_STATE_NOT_PRESENT;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_iccid(w, NULL);
fake_sailfish_watch_set_ofono_imsi(w, NULL);
fake_sailfish_watch_set_ofono_spn(w, NULL);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
memset(count, 0, sizeof(count));
/* Set ICCID again, that will load the cached information */
sim.mcc = NULL;
sim.mnc = NULL;
sim.state = OFONO_SIM_STATE_INSERTED;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!g_strcmp0(si->iccid, TEST_ICCID));
g_assert(!g_strcmp0(si->imsi, TEST_IMSI));
g_assert(!g_strcmp0(si->spn, TEST_SPN));
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
memset(count, 0, sizeof(count));
sailfish_sim_info_remove_handler(si, id[SIM_INFO_SIGNAL_SPN_CHANGED]);
id[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
sailfish_sim_info_invalidate(si);
g_assert(!si->iccid);
g_assert(!si->imsi);
g_assert(!si->iccid);
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]); /* removed ^ */
memset(count, 0, sizeof(count));
sailfish_sim_info_remove_handlers(si, id, G_N_ELEMENTS(id));
sailfish_sim_info_unref(si);
sailfish_watch_unref(w);
}
static void test_netreg(void)
{
struct sailfish_sim_info *si;
struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
struct ofono_sim sim;
struct ofono_netreg netreg;
struct stat st;
gulong id[SIM_INFO_SIGNAL_COUNT];
int count[SIM_INFO_SIGNAL_COUNT];
memset(id, 0, sizeof(id));
memset(count, 0, sizeof(count));
memset(&netreg, 0, sizeof(netreg));
netreg.technology = OFONO_RADIO_ACCESS_MODE_GSM;
netreg.status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
netreg.status_watches = __ofono_watchlist_new(g_free);
memset(&sim, 0, sizeof(sim));
sim.mcc = TEST_MCC;
sim.mnc = TEST_MNC;
sim.state = OFONO_SIM_STATE_READY;
rmdir_r(STORAGEDIR);
si = sailfish_sim_info_new(TEST_PATH);
id[SIM_INFO_SIGNAL_ICCID_CHANGED] =
sailfish_sim_info_add_iccid_changed_handler(si,
test_signal_count_cb, count +
SIM_INFO_SIGNAL_ICCID_CHANGED);
id[SIM_INFO_SIGNAL_IMSI_CHANGED] =
sailfish_sim_info_add_imsi_changed_handler(si,
test_signal_count_cb, count +
SIM_INFO_SIGNAL_IMSI_CHANGED);
id[SIM_INFO_SIGNAL_SPN_CHANGED] =
sailfish_sim_info_add_spn_changed_handler(si,
test_signal_count_cb, count +
SIM_INFO_SIGNAL_SPN_CHANGED);
fake_sailfish_watch_set_ofono_sim(w, &sim);
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!g_strcmp0(si->iccid, TEST_ICCID));
g_assert(!g_strcmp0(si->imsi, TEST_IMSI));
g_assert(!g_strcmp0(si->spn, TEST_DEFAULT_SPN));
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
memset(count, 0, sizeof(count));
g_assert(stat(ICCID_MAP, &st) == 0);
g_assert(S_ISREG(st.st_mode));
/* Default SPN doesn't get cached */
g_assert(stat(SIM_CACHE, &st) < 0);
fake_sailfish_watch_set_ofono_netreg(w, &netreg);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
/* Simulate home registation */
netreg.mcc = TEST_MCC;
netreg.mnc = TEST_MNC;
netreg.name = TEST_SPN;
netreg.status = NETWORK_REGISTRATION_STATUS_REGISTERED;
netreg_notify_status_watches(&netreg);
g_assert(!g_strcmp0(si->spn, TEST_SPN));
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
/* This one does get cached */
g_assert(stat(SIM_CACHE, &st) == 0);
g_assert(S_ISREG(st.st_mode));
fake_sailfish_watch_set_ofono_netreg(w, NULL);
fake_sailfish_watch_emit_queued_signals(w);
__ofono_watchlist_free(netreg.status_watches);
sailfish_sim_info_remove_handlers(si, id, G_N_ELEMENTS(id));
sailfish_sim_info_unref(si);
sailfish_watch_unref(w);
}
#define TEST_(name) "/sailfish_sim_info/" 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_sim_info",
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("cache"), test_cache);
g_test_add_func(TEST_("netreg"), test_netreg);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -178,12 +178,12 @@ static void test_ber_tlv_builder_efpnn(void)
ber_tlv_builder_optimize(&builder, NULL, NULL);
eons_info = sim_eons_new(1);
sim_eons_add_pnn_record(eons_info, 1, efpnn0, sizeof(efpnn0));
sim_eons_add_pnn_record(eons_info, 1, efpnn0, 8 + 10);
g_assert(!sim_eons_pnn_is_empty(eons_info));
sim_eons_free(eons_info);
eons_info = sim_eons_new(1);
sim_eons_add_pnn_record(eons_info, 1, efpnn1, sizeof(efpnn1));
sim_eons_add_pnn_record(eons_info, 1, efpnn1, 8 + 6);
g_assert(!sim_eons_pnn_is_empty(eons_info));
sim_eons_free(eons_info);
}

View File

@@ -1145,6 +1145,8 @@ static void test_assembly(void)
reencoded = sms_decode_text(l);
g_slist_free_full(l, g_free);
if (g_test_verbose())
g_printf("ReEncoded:\n%s\n", reencoded);
@@ -1304,6 +1306,8 @@ static void test_prepare_concat(gconstpointer data)
g_assert(decoded_str);
g_assert(strcmp(decoded_str, test->str) == 0);
g_free(decoded_str);
g_slist_free_full(pdus, g_free);
g_slist_free_full(r, g_free);
sms_assembly_free(assembly);
}
@@ -1334,6 +1338,7 @@ static void test_limit(gunichar uni, int target_size, gboolean use_16bit)
g_assert(g_utf8_strlen(decoded, -1) == target_size);
g_free(decoded);
g_slist_free_full(l, g_free);
memcpy(utf8 + i, utf8_char, stride);
utf8[i+stride] = '\0';

View File

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

View File

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