Compare commits

...

595 Commits

Author SHA1 Message Date
Slava Monich
153eb3a4f3 [ril] Send power off request at startup. JB#46294
Some RILs like to receive power off request at startup even if radio
is already off.
2019-07-10 15:13:12 +03:00
Slava Monich
0efebd16d9 Merge branch 'stk_disable' into 'master'
Make STK functionality configurable

See merge request mer-core/ofono!219
2019-06-05 21:38:10 +00:00
Slava Monich
7a6928c02f [ril] Made STK functionality configurable. JB#42589
With enableSimToolkit option in ril_subscription.conf

Defaults to true.

It's more of a workaround than a solution to the "SIM removed" problem,
but better to have at least that than nothing at all.
2019-06-04 15:21:58 +03:00
Slava Monich
ec134e68d2 [build] Undefine _FORTIFY_SOURCE in debug build
To avoid these compilation warnings with newer gcc:

/usr/include/features.h:381:4: warning:
2019-05-20 18:22:46 +03:00
Slava Monich
a8be769c87 Merge branch 'initial_attach' into 'master'
Set initial attach APN for LTE

See merge request mer-core/ofono!217
2019-05-13 23:04:06 +00:00
Slava Monich
a2d87f64c4 [unit] Added ril_vendor test 2019-05-09 14:51:52 +03:00
Slava Monich
3ecd55a205 [unit] Improved ril_util.c coverage 2019-05-09 14:50:45 +03:00
Slava Monich
d8ea82b2f1 [ril] Set initial attach APN for LTE. JB#45341
Qualcomm doesn't require it but MediaTek apparently does.
Also, slightly refactored RIL vendor support.
2019-05-09 14:50:30 +03:00
Slava Monich
c95fe16a9b Merge branch 'watch' into 'master'
Watch API extension

See merge request mer-core/ofono!216
2019-04-30 13:55:37 +00:00
Slava Monich
55e923250a [ofono] Fixed crash on exit in __ofono_modem_remove_online_watch 2019-04-26 12:26:16 +03:00
Slava Monich
f5653ae240 [ofono] Added gprs field to ofono_watch. JB#45342
And these two new functions:

    ofono_watch_add_gprs_changed_handler
    ofono_watch_add_gprs_settings_changed_handler
2019-04-24 12:23:39 +03:00
Slava Monich
ecf23c1333 [ofono] Added registration info to ofono_watch
Particularly, these four new fields:

  enum ofono_netreg_status reg_status;
  const char *reg_mcc;
  const char *reg_mnc;
  const char *reg_name;

and the corresponding callback registration functions:

  ofono_watch_add_reg_status_changed_handler()
  ofono_watch_add_reg_mcc_changed_handler()
  ofono_watch_add_reg_mnc_changed_handler()
  ofono_watch_add_reg_name_changed_handler()
2019-04-24 12:18:05 +03:00
Slava Monich
e71036f7d7 Merge branch 'context_by_type' into 'master'
Add ofono_gprs_context_settings_by_type() API

See merge request mer-core/ofono!215
2019-04-18 15:08:13 +00:00
Slava Monich
b8e8b930f8 [ofono] Added ofono_gprs_context_settings_by_type() API. JB#44551 2019-04-18 12:50:37 +03:00
Slava Monich
65a3f7ee46 Merge branch 'access' into 'master'
D-Bus access control

See merge request mer-core/ofono!213
2019-04-12 12:04:59 +00:00
Slava Monich
26c5c4bfa3 Merge branch 'plus_0' into 'master'
Add networkSelectionManual0 configuration option

See merge request mer-core/ofono!214
2019-04-12 08:22:28 +00:00
Slava Monich
2d35e5e28d [ril] Added networkSelectionManual0 config option. JB#42812
It makes +0 suffix for RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL
configurable.
2019-04-11 18:44:59 +03:00
Slava Monich
ae78d9a946 [ofono] Access control for RadioSettings interface. JB#44705 2019-04-05 18:06:49 +03:00
Slava Monich
243dd7d17c [ofono] Access control for Modem interface. JB#44705 2019-04-05 18:05:24 +03:00
Slava Monich
acaafafbb9 [ofono] Access control for SimManager interface. JB#44705 2019-04-05 18:04:54 +03:00
Slava Monich
4f378c806b [unit] Test for D-Bus access control plugin. JB#44705 2019-04-05 18:04:54 +03:00
Slava Monich
bd33ff471c [ofono] D-Bus access control plugin. JB#44705 2019-04-05 18:04:54 +03:00
Slava Monich
d423608e46 [unit] Test for access control API. JB#44705 2019-04-05 18:04:54 +03:00
Slava Monich
3b708effd9 [ofono] Access control API. JB#44705 2019-04-05 18:04:26 +03:00
Slava Monich
f01722cca5 [ofono] Don't use __DATE and __TIME__ macros
They make every build unique and we don't want that.
2019-04-05 16:44:11 +03:00
Slava Monich
f62d53fbd0 [ofono] Fixed compilation warnings with gcc 4.9
src/gprs-filter.c:117:56: warning: right-hand operand of comma expression has no effect [-Wunused-value]
 #define gprs_filter_request_ref(req) ((req)->refcount++, req)
                                                        ^
src/voicecall-filter.c:121:61: warning: right-hand operand of comma expression has no effect [-Wunused-value]
 #define voicecall_filter_request_ref(req) ((req)->refcount++, req)
                                                             ^
2019-04-05 16:29:33 +03:00
Slava Monich
942aee3f25 Merge branch 'python3' into 'master'
python => python3

See merge request mer-core/ofono!212
2019-03-21 14:20:37 +00:00
Slava Monich
ecc83568fd [test] python => python3. Fixes JB#45222 2019-03-21 15:17:50 +02:00
Slava Monich
c911c05fcb Merge branch 'tdscdma_dbm' into 'master'
Take TD_SCDMA_SignalStrength into account (when it's present)

See merge request mer-core/ofono!211
2019-03-19 11:22:15 +00:00
Slava Monich
680979f782 [ril] Take TD_SCDMA_SignalStrength into account. JB#44551
And use it when no other signal strength information is available.
2019-03-18 14:14:55 +02:00
Slava Monich
250a6abb71 Hosekeeping
warning: Macro expanded in comment on line 20: %license requires reasonably fresh rpm
2019-03-13 16:38:00 +02:00
Slava Monich
6c5d2ab803 Merge branch 'modem_path' into 'master'
Add "modem" entry to RIL transport parameters

See merge request mer-core/ofono!209
2019-03-05 14:48:53 +00:00
Slava Monich
bf8cb3995c [ril] Add "modem" entry to RIL transport parameters. JB#44551
The value is modem's D-Bus path. RIL transport plugins may (and most
likely will) need it to access per-modem parameters such as SPN, IMSI
and so on.
2019-03-05 15:23:21 +02:00
Slava Monich
8973e52e45 Merge branch 'umts_network_mode' into 'master'
Make UMTS network mode configurable

See merge request mer-core/ofono!208
2019-03-04 22:10:24 +00:00
Slava Monich
0e8dc3605e [ril] Make UMTS network mode configurable. JB#44551
Some devices don't understand GSM_WCDMA_AUTO and want to see
GSM_WCDMA instead. Now we can make those happy by configuring
UMTS mode in /etc/ofono/ril_subscription.conf like this:

  umtsNetworkMode=0
2019-03-04 21:50:07 +02:00
Slava Monich
537a39f94a Merge branch 'jb38580' into 'master'
Delay sending SMS by 0.1s

See merge request mer-core/ofono!207
2019-02-27 12:06:35 +00:00
Santtu Lakkala
c3d93e83d7 [ofono] Delay sending SMS by 0.1s. Contributes to: JB#38580
When sending an SMS message to multiple recipients, multiple calls to
SendMessage are received in rapid succession. Delay sending the first
one in such a batch slightly so that we hopefully have at least the next
one queued up to start sending in "MMS" mode, otherwise it seems
messages can be lost or erroneously sent twice.
2019-02-27 13:25:14 +02:00
Slava Monich
7cdf3db124 Merge branch 'jb44709' into 'master'
Interpret , and . as pause in tone string.

See merge request mer-core/ofono!206
2019-02-25 15:00:37 +00:00
Santtu Lakkala
398942c78e [ofono] Interpret , and . as pause in tone string. Contributes to: JB#44709 2019-02-25 09:35:26 +02:00
Slava Monich
26e39508ad [packaging] Require rpm >= 4.11
For %license macro
2019-01-16 17:17:49 +02:00
Slava Monich
a16fcd0d37 Merge branch 'ofono_watch' into 'master'
sailfish_watch -> ofono_watch

See merge request mer-core/ofono!204
2019-01-16 15:08:28 +00:00
Slava Monich
432e700272 Merge branch 'jb24119' into 'master'
Add ofono-doc subpackage. JB#24119

See merge request mer-core/ofono!205
2019-01-16 15:07:56 +00:00
Tomi Leppänen
aa694b592f [packaging] Add ofono-doc subpackage. Contributes to JB#24119
Signed-off-by: Tomi Leppänen <tomi.leppanen@jolla.com>
2019-01-15 15:17:41 +02:00
Slava Monich
c5c8b72761 [ofono] sailfish_watch -> ofono_watch. JB#44067
This exposes sailfish_watch object to ofono plugins. Also, removed
dependency on glib headers from the header file.

Lots of changes but those are mostly mechanical.

Since upstream ofono started migrating away from glib and losing
its value for us as upstream project, it's ok now to start dropping
sailfish prefixes in the source code. This code is ours now to maintain.
2019-01-15 01:08:12 +02:00
Slava Monich
2ab7aa0f97 Merge branch 'roaming_issues' into 'master'
Roaming issues

See merge request mer-core/ofono!202
2019-01-02 14:06:55 +00:00
Slava Monich
549fe2355f [netreg] Re-assert automatic operator selection at startup. JB#42820
It wasn't done if the status at startup was "searching".
2018-12-23 17:31:51 +01:00
Slava Monich
7493187e47 [ril] Never fail deactivate requests. JB#42820
Failed connection request doesn't release ofono context id but we don't
need to worry about those ids because the real ones are allocated by rild.
We just need to release ofono ids whenever we no longer need them.
2018-12-23 17:30:28 +01:00
Slava Monich
9a3d8d671c [gprs] Make debug trace slightly more informative 2018-12-23 17:29:52 +01:00
Slava Monich
39eac13743 [ril] Retry registration requests. JB#42820
And use a long timeout. It may take a minutes in roaming.
2018-12-23 17:28:14 +01:00
Slava Monich
6329bb8639 [ril] Specify timeout for SETUP_DATA_CALL requests. JB#42820
Completion routine must be invoked even if rild never replies.
The timeout (5 min) may seem ridiculously long but sometimes it
does take minutes in roaming.
2018-12-23 17:26:23 +01:00
Slava Monich
75b07c5c80 Merge branch 'hfp_ag' into 'master'
HFP AG BlueZ5 plugin reconnects to daemon if daemon restarts.

See merge request mer-core/ofono!201
2018-11-30 13:59:21 +00:00
Juho Hämäläinen
4f6f964ca4 [hfp_ag_bluez5] Remove DBUS_TYPE_UNIX_FD check. 2018-11-30 12:46:26 +02:00
Juho Hämäläinen
7af95f6db5 [hfp_ag_bluez5] Follow BlueZ in system bus. JB#42087
Close interface on BlueZ exit and reconnect to BlueZ and re-create
interfaces when the daemon appears again. Now HFP AG is usable with
wanted or crash caused restarts of BlueZ daemon without needing to
restart oFono.
2018-11-30 12:45:43 +02:00
Juho Hämäläinen
99f4667eb7 [handsfree-audio] Set freed agent to NULL on exit. JB#42087 2018-11-29 14:36:27 +02:00
Slava Monich
c1c3ecab31 Merge branch 'context' into 'master'
Added "singleDataContext" configuration option

See merge request mer-core/ofono!200
2018-11-28 17:55:01 +00:00
Slava Monich
83dc99658c [ril] Added "singleDataContext" configuration option. JB#42837
Normally we should be able to have two simultaneously active
data contexts - one for mobile data and one for MMS. However
some devices may require that mobile data is disconnected
before we can send or receive MMS.
2018-11-28 13:54:51 +02:00
Slava Monich
9a7b538087 Merge branch 'jb42297' into 'master'
Handle multi-modem cases better in emulator and plugins.

See merge request mer-core/ofono!199
2018-11-14 23:30:42 +00:00
Juho Hämäläinen
9f7a1ffe3f [bluez5] Use updated emulator. Fixes JB#42297
Instead of using arbitrary modem in multiple modems scenario, pass all
applicaple modems to emulator.
2018-11-13 09:29:46 +02:00
Juho Hämäläinen
1f81ec7d9d [bluez4] Use updated emulator.
Instead of using arbitrary modem in multiple modems scenario, pass all
applicaple modems to emulator.
2018-11-13 09:29:46 +02:00
Juho Hämäläinen
6e833401cc [examples] Use updated emulator. 2018-11-13 09:29:46 +02:00
Juho Hämäläinen
d9c68c4fb9 [ofono] Support multiple modems in emulator. JB#42297
With more than one modem we don't play indicators etc correctly to
headset if the call is coming to a modem we are not watching. As the
modem is picked arbitrarily in hfp plugins, it is better to be able to
follow multiple modems at the same time.

When modems disappear they automatically are removed from the emulator,
with two or more modems it is possible that only one remains for a while
and new modems appear, to handle these cases add functionality to add
modems to the emulator.
2018-11-13 09:29:43 +02:00
Slava Monich
9e6f7721a0 Merge branch 'stray_call' into 'master'
Fix data connection dying after switching radio tech

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

See merge request !167
2018-01-24 09:08:31 +00:00
Slava Monich
096cd04044 [ril] Use the right cid to signal context settings change. Fixes JB#40845 2018-01-23 18:19:35 +02:00
Slava Monich
5eabe96602 [ril] INT_MAX -> SAILFISH_CELL_INVALID_VALUE where appropriate
They are numerically equivalent but the latter has a clearer semantics.
2018-01-23 17:51:56 +02:00
Slava Monich
05dec021c0 [ril] Updated netmon implementation
Report new values which appeared in 1.21
Don't report invalid values
2018-01-23 13:58:46 +02:00
Slava Monich
6f7209b045 Merge branch 'v1.21' into 'master'
Upgrade ofono baseline to 1.21

See merge request !166
2018-01-23 10:49:29 +00:00
Slava Monich
a766281a02 [ofono] Upgrade baseline to 1.21. Fixes JB#40876 2018-01-23 12:28:48 +02:00
Marcel Holtmann
13b4802bec Release 1.21 2018-01-23 12:25:39 +02:00
Christophe Ronco
e1547fdaf4 huawei: add LTE support
Huawei LTE modems use AT^SYSCFGEX and AT^SYSINFOEX instead of
AT^SYSCFG and AT^SYSINFO.
If we want to be able to attach on LTE with this modem, we must use
AT^SYSCFGEX to configure rat mode and band. Using AT^SYSCFG, mode any
means UMTS or GSM.
2018-01-23 12:25:39 +02:00
Ankit Navik
08c36b2885 udevng/xmm7xxx: Allow to detect xmm7xxx series modems
The Intel xmm7xxx series modem uses id as 8087:0930
2018-01-23 12:25:39 +02:00
Ankit Navik
0180c9febf Add support for Intel xmm7xxx series modems
This adds plugin for xmm7xxx series modems

Conflicts:
	ofono/Makefile.am
2018-01-23 12:25:36 +02:00
Denis Kenzior
49034cfc69 ifxmodem: Fix minor style issues 2018-01-23 12:14:49 +02:00
Ankit Navik
4685e3f0de ifxmodem: support automatic context activation
Add support for automatic context activation by adding read_settings.
It also adds detach_shutdown to make sure context is cleaned up when
network registration is lost.
2018-01-23 12:14:49 +02:00
Ankit Navik
72be5bdff2 atutil: Add logic for cgcontrdp to get address and netmask 2018-01-23 12:14:49 +02:00
Jonas Bonn
79c1abfdd3 gobi: create NetworkMonitor atom 2018-01-23 12:14:49 +02:00
Jonas Bonn
c88cffaa2e qmi: add NetworkMonitor interface
This is a rudimentary implementation that contains technology and RSSI
and BitErrorRate, plus RSRQ/RSRP for LTE networks.  More data can be
added as needed.

This implementations uses the 'Get Signal Strength' QMI method to retrieve
the data.  Operator fields (MNC, LAC, etc) can be gotten from the 'Serving
Cell' method if needed, but since this data is already provided in the
NetworkRegistration object it doesn't seem necessary to repeat it here
when an additional communication to the modem is required.
2018-01-23 12:14:49 +02:00
Jonas Bonn
17e66090ec Fix out of tree build 2018-01-23 12:14:49 +02:00
Denis Kenzior
100cf7df1d AUTHORS: Mention Joey's contributions 2018-01-23 12:14:49 +02:00
Joey Hewitt
280ed19215 gobi: enable message waiting atom 2018-01-23 12:14:49 +02:00
Joey Hewitt
ae0f5b0ff6 qmimodem: implement SIM write functions 2018-01-23 12:14:49 +02:00
Nishanth V
dbfc642eb3 netmonagent: fix unnecessary function declaration 2018-01-23 12:14:49 +02:00
Jonas Bonn
e5e5108913 udev: isi modems do not use 'Device' property
Neither the n900 nor u8500 drivers use this property so there's currently
no need to set it in the setup function.
2018-01-23 12:14:49 +02:00
Jonas Bonn
9035db3129 udev: fixes for detection of non-USB modems
This patch fixes up some fallout from the merging of the udev and udevng
modules.

i)  The 'serial' modems in question are not necessarily serial modems at
all; for example, the N900 ISI modems appear as network devices and don't
have a devnode.  This patch relaxes the requirement that a devnode exist.

ii)  The modem driver was being set to 'legacy', which is a remnant of
an earlier approach to merging these modules.  The driver needs to be
properly set to the value of the OFONO_DRIVER property in order for the
setup function to be found.

iii)  The serial modem's private data was being added to the modem
structure incorrectly...

In particular point iii) above shows that there is essentially nobody
using these devices which makes modifications in this area tricky.
2018-01-23 12:14:49 +02:00
Alexander Couzens
81391a4101 qmimodem: register callbacks after netreg_register
When registering callbacks before ofono_netreg_register(), callbacks
will use the netreg api which might lead into undefined behaviour,
because certain fields aren't yet initilized.
2018-01-23 12:14:49 +02:00
Alexander Couzens
60d449c01d network.c: notify_status_watches: check for NULL
In rare cases when ofono_netreg_status_notify() is called before
ofono_netreg_register() netreg->status_watches is NULL.
2018-01-23 12:14:49 +02:00
Nishanth V
b0ccc39866 rilmodem: netmon fix missing notify for g_ril_send 2018-01-23 12:14:49 +02:00
Clayton Craft
bd2aa28405 isimodem: Use correct callback for pin status 2018-01-23 12:14:49 +02:00
Denis Kenzior
67e31bb519 doc: Mark ServingCellInformationChanged as noreply 2018-01-23 12:14:49 +02:00
Denis Kenzior
b848827976 netmonagent: Fix typo 2018-01-23 12:14:49 +02:00
Nishanth V
ab6764dcc0 test: added script to test serving cell agent 2018-01-23 12:14:49 +02:00
Nishanth V
da42039c80 rilmodem: driver changes for netmon agent
Rilmodem driver updated to handle enabling
and disabling periodic serving cell updates
2018-01-23 12:14:49 +02:00
Nishanth V
392c00c65e gril: added RIL constants for cell info list
added RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE and
RIL_UNSOL_CELL_INFO_LIST and corresponding string
conversion
2018-01-23 12:14:49 +02:00
Nishanth V
7a0fe98d95 netmon: core changes for network monitor agent
Added implementation for RegisterAgent and UnregisterAgent in
NetworkMonitor interface and added netmonagent source file for agent
implemention.

Conflicts:
	ofono/src/ofono.conf
2018-01-23 12:14:45 +02:00
Nishanth V
d508a2f2bb include: added NetworkMonitorAgent interface 2018-01-23 12:09:01 +02:00
Nishanth V
8f070cf583 include: added enable_periodic_update in netmon driver
Defining new method in ofono_netmon_driver,
enable_periodic_update useful to get periodic update
on serving cell information.
2018-01-23 12:09:01 +02:00
Nishanth V
d2d8117723 netmon: modified api.txt for network monitor agent
added new DBUS methods RegisterAgent and UnregisterAgent to
Networkmonitor interface so that any client of ofono can register for
serving cell updates. Added new agent interface NetworkMonitorAgent
with two methods, ServingCellInformationChanged and Release.
2018-01-23 12:09:01 +02:00
Denis Kenzior
6897e57353 AUTHORS: Mention Clayton's contributions 2018-01-23 12:09:01 +02:00
Clayton Craft
6a8c2aa9c1 gril: Fix compilation on armhf/Musl
The following patch is needed to successfully build ofono on armhf with
musl (in place of libc)
2018-01-23 12:09:01 +02:00
Clayton Craft
076e388d45 plugins: Fix compilation on armhf/Musl
The following patch is needed to successfully build ofono on armhf with
musl (in place of libc)
2018-01-23 12:09:01 +02:00
Jonas Bonn
bcafe0dc3d udev: fix quectelqmi gps interface
Using location-reporting requires both the 'aux' and 'gps' interfaces;
the GPS interface is interface 1, not 2.
2018-01-23 12:09:01 +02:00
Denis Kenzior
9272075f55 qmimodem: Fix whitespace issue 2018-01-23 12:09:01 +02:00
Jonas Bonn
526072d7a3 doc: RSSI is also an LTE property 2018-01-23 12:09:01 +02:00
Jonas Bonn
0680063527 qmi: provide AvailableTechnologies in radio-settings
This provides the list of available technologies in the radio-settings
atom.  The list is queried by the DMS Get Capabilities method; ofono
takes care of caching the available technologies for us so we don't need
to worry about this method being called excessively.
2018-01-23 12:09:01 +02:00
Alexander Couzens
4e08680e5f voicecall: use ofono_call_status_name in DBG messages
status names are more readable then integer values.
2018-01-23 12:09:01 +02:00
Alexander Couzens
1d85caa7f9 voicecall,common: move call_status_to_string() to common
call_status_to_string() is useful for debug output.
Change signature to contain enum call_status
Replace default case to get compiler warning when new enums added
2018-01-23 12:09:01 +02:00
Alexander Couzens
db0ef91c81 plugins/udevng: use else if instead of if
The same variable is checked in two `if's.
2018-01-23 12:09:01 +02:00
Alexander Couzens
54d8c78a50 gprs: use registration_status_to_string in debug messages 2018-01-23 12:09:01 +02:00
Alexander Couzens
905c886269 qmimodem: extract network time from serving system 2018-01-23 12:09:01 +02:00
Alexander Couzens
f0c7a373ae qmimodem: add strength (in %) to the debug output 2018-01-23 12:09:01 +02:00
Alexander Couzens
4673da16d5 udevng: use first cdc-wdm interface for sierra qmi
Using the voice firmware on a mc7304 the modem
stopped accepting qmi messages on the second
cdc-wdm interface.
2018-01-23 12:09:01 +02:00
Jonas Bonn
0dc2acee4e qmi: add helper to get int16_t result 2018-01-23 12:09:01 +02:00
Jonas Bonn
f749284029 qmi: implement RAT selection
The QMI radio-settings atom was just a skeleton and did not even implement
the mandtory property TechnologyPreference.  As such, it probably should
never even have been registered for the modem.  Nonetheless, this patch
puts this mandatory property into place.

This is implemented via the 'Set System Selection' method by way of the
'mode' parameter.  This seems to best reflect the intention of the Ofono
API and works as expected when tested with a Quectel EC21.

Some notes:
i)  There is an alternative function called 'Set Technology Preference'
    which provides similar functionality.  This 'technology preference'
    is updated automatically when the 'system selection mode' is modified
    so everything seems to be in order.
ii) For the EC21, switching the underlying technology works seamlessly.
    There are indications, however, that some modems _might_ require a
    reset before changes take effect; that bridge will need to be crossed
    if reached.
2018-01-23 12:09:01 +02:00
Christophe Ronco
778b9f08aa atmodem: correctly report lte bearer for huawei modems 2018-01-23 12:09:01 +02:00
Ankit Navik
40db3f7067 Add support for Intel xmm7xxx series modem driver
This adds driver as xmm7modem for radio-settings
2018-01-23 12:09:01 +02:00
Ankit Navik
e198cf04c0 atmodem: Add lte atom driver
Adds atmodem driver for setting the default APN command.
The default APN is manage by config storage.
2018-01-23 12:09:01 +02:00
Alexander Couzens
fbd59ba56f common: move strlen(apn) check into is_valid_apn() 2018-01-23 12:09:01 +02:00
Alexander Couzens
cff9ded7e6 include/gprs-context.h: declare struct ofono_modem
Fix a warning.
./include/gprs-context.h:99:61: error: ‘struct ofono_modem’ declared
inside parameter list will not be visible outside of this definition
or declaration...
2018-01-23 12:09:01 +02:00
Denis Kenzior
c74386b5e6 AUTHORS: Mention Matthijs' contributions 2018-01-23 12:08:51 +02:00
Matthijs Kooijman
028f54c26f at/cdma/ifxmodem: Use /dev/net/tun to check for TUN support
Previously, these drivers would check /sys/devices/virtual/misc/tun to
see if TUN is supported, and bail out otherwise. However, the tun module
can sometimes be autoloaded by opening the /dev/net/tun file. In this
case the /dev file already exists, but the /sys file only gets created
after the modul is loaded.

Additionally, the ppp code does not use the /sys file, but only the
/dev file, so checking for the existence of the latter seems a better
indicator of expected success.
2018-01-23 12:08:50 +02:00
Alexander Couzens
c066f34ea1 qmi/sms: require WMS version >= 1.2 for bearer calls
I've never seen a major 0 service. The gobi2000 comes with
WMS 1.0 and doesn't support the bearer command. Guessing
it's 1.2 required.
2018-01-23 12:08:50 +02:00
Denis Kenzior
b1c79d5cae include: Add a quote from primary source document 2018-01-23 12:08:37 +02:00
Alexander Couzens
0cc61dcfe8 gprs-context: set apn length to 100 bytes
According to ETSI TS 123 003 version 9.15.0 Chapter 9.1
2018-01-23 12:08:37 +02:00
Alexander Couzens
5852bebda0 qmimodem: use a default RAT when registering
When registering to an operator ofono uses the old RAT.
In the case the modem is not connected to any network, this would use
QMI_NAS_NETWORK_RAT_NONE which results in the error OP_DEVICE_UNSUPPORTED.

Use QMI_NAS_NETWORK_RAT_NO_CHANGE instead to not define any preference.
2018-01-23 12:08:21 +02:00
Alexander Couzens
768c028a11 plugins: Remove AllowedAccessPoints interface
Without this patch, a modem that has been removed still shows the
AllowedAccessPoints interface
2018-01-23 12:08:21 +02:00
Alexander Couzens
6b93ea0cc6 voicecall.h: declare struct ofono_modem
Fix a warning when only voicecall.h is included:
'struct ofono_modem declared' inside parameter list will not be visible
outside of this definition or declaration struct ofono_voicecall
*ofono_voicecall_create(struct ofono_modem *modem,...
2018-01-23 12:08:21 +02:00
John Ernberg
4a485a7aa0 radio-settings: Fix typo in radio_band_umts_from_string 2018-01-23 12:08:21 +02:00
Marcel Holtmann
f6fb277cf4 build: Don't report format truncation as warnings 2018-01-23 12:08:21 +02:00
Marcel Holtmann
03f150838b ril_intel: Fix wrong pointer derference for power status 2018-01-23 12:08:21 +02:00
Marcel Holtmann
9731ca1a87 ublox: Add missing break statement 2018-01-23 12:08:21 +02:00
Marcel Holtmann
a09f4c070d u8500: Add missing fall through statement 2018-01-23 12:08:21 +02:00
Marcel Holtmann
f018f5a255 phonebook: Add missing fall through statement 2018-01-23 12:08:21 +02:00
Marcel Holtmann
286396bf91 voicecall: Reword fall through statement to avoid compiler warning 2018-01-23 12:08:21 +02:00
Marcel Holtmann
5d6baccced stk: Add missing break statement for inkey duration 2018-01-23 12:08:21 +02:00
Marcel Holtmann
514f4cf9cc gatchat: Reword the fall through cases to avoid compiler warnings 2018-01-23 12:08:21 +02:00
Marcel Holtmann
ff8408e6dd ifxmodem: Fix GPRS activation command string buffer size 2018-01-23 12:08:21 +02:00
Marcel Holtmann
df1294d77c telitmodem: Fix GPRS activation command string buffer size 2018-01-23 12:08:21 +02:00
Marcel Holtmann
2323ebacb3 atmodem: Fix missing break statement for ublox driver 2018-01-23 12:08:21 +02:00
Alexander Couzens
c780eff0ce qmimodem/sms: don't check for free ME space on receive
If the ME storage is full, the modem will reject new messages
with a SMPP RP-Error 'Protocol error, unspecific'.
It seems the qmimodem is first checking the ME storage for
free space, then deliver the SMS via QMI and not saving it
to the ME anyway.
Using QMI_WMS_STORAGE_TYPE_NONE it doesn't check for free space.

Tested-on: Quectel EC20
2018-01-23 12:07:55 +02:00
Alexander Couzens
373248a35b qmimodem: add debug helper qmi_result_print_tlvs
qmi_result_print_tlvs prints the type and length field
of a result to DBG()
2018-01-23 12:07:55 +02:00
Vincent Cesson
fe219b648d gemalto: Implement HardwareMonitor method
Use Gemalto commands ^SCTM and ^SBV to monitor temperature and voltage.
Use a single method GetStatistics to read and return both values.
2018-01-23 12:07:55 +02:00
Denis Kenzior
33f55c569f build: Add cinterion-hardware-monitor-api.txt 2018-01-23 12:07:55 +02:00
Vincent Cesson
d6cf954354 doc: gemalto: add cinterion.HardwareMonitor api
add documentation about interface cinterion.HardwareMonitor.

This interface exposes a single method to access temperature and supply
voltage of the modem.
2018-01-23 12:07:55 +02:00
Vincent Cesson
d8e852cb5e gemalto: Prepare new interface for hardware monitoring
Gemalto modems have hardware related commands, allowing to monitor voltage
and temperature. These parameters will be accessible on DBus interface:
org.ofono.HardwareMonitor.

 - Create the DBus method table with one entry: GetStatistics. This method
would return temperature and voltage values.
 - Create a dedicated structure to handle the DBus methods.
 - Create enable/disable functions to handle DBus interface registration.
2018-01-23 12:07:55 +02:00
Denis Kenzior
83e3ec0e98 qmi: Fix invalid memory access
When qmi_device_shutdown is used and the callback provided utilizes
qmi_device_unref, an access into already freed memory is triggered.

Sequence of events is:

1. timeout fires
2. glib calls timeout callback (e.g. shutdown_callback) which in turn
calls shutdown_func (gobi shutdown_cb) which in turn calls
qmi_device_unref()
3. qmi_device_unref calls g_source_remove, which doesn't call the
destroy callback (it is blocked)
4. qmi_device_unref then frees the memory used by device
5. glib then calls the source destroy callback (e.g. shutdown_destroy)
which results in just freed memory being used.

glib appears to always call the destroy callback, even if the source has
been removed previously.  So to work around the issue, delay the actual
g_free until the destroy callback is invoked.
2018-01-23 12:06:41 +02:00
Denis Kenzior
e35f537f72 gprs: Don't use pri_set_apn for auto activated cids
There are two problems with using pri_set_apn.  The first issue is that
this function was built to be used by the set_property handler and
assumes the presence of a pending DBusMessage.

The second issue is that it touches the settings store.

In the case of auto-activated contexts no pending message exists.  Also,
we should not be touching the settings store as the APN might
potentially be a value that has not been provisioned.  Or in some cases
bogus.
2018-01-23 12:06:41 +02:00
Denis Kenzior
c7daf5aa43 gprs: Return after releasing pri_ctx 2018-01-23 12:06:41 +02:00
Slava Monich
490a9c06f4 [unit] Improved ril_util.c test coverage 2018-01-22 11:57:17 +02:00
Slava Monich
320b3f4605 Merge branch 'sim_info' into 'master'
A few corner cases for cached SIM info

See merge request !165
2018-01-22 09:40:40 +00:00
Slava Monich
e35dae17d9 Merge branch 'aid_pin' into 'master'
Don't require AID for SIM pin requests

See merge request !164
2018-01-22 09:39:55 +00:00
Slava Monich
f4522f4a00 [unit] Added test-sailfish_sim_info_dbus
Tests sailfish_sim_info_dbus.c

  Lines:     93/96  96.9 %
  Functions: 16/16 100.0 %
  Branches:  16/20  80.0 %
2018-01-22 02:02:29 +02:00
Slava Monich
ce85c94426 [unit] Improved test coverage for sailfish_sim_info.c 2018-01-21 20:03:40 +02:00
Slava Monich
4027bdc04e [ril] A few corner cases for cached SIM info
Cached SPN needs to be reset too when SIM card is removed.
2018-01-21 20:02:10 +02:00
Slava Monich
c57f99bf01 [ril] Don't require AID for SIM pin requests. Fixes JB#40837
Some adaptations (namely, MTK) don't provide AID for GSM app but
don't seem to require it either.
2018-01-19 20:56:15 +02:00
Slava Monich
54d610ce6a Merge branch 'vendor' into 'master'
MTK support

See merge request !156
2018-01-18 21:34:14 +00:00
Slava Monich
f7f9e32743 unit: Improve idmap.c unit test coverage
This brings function, line and branch coverage for idmap.c to 100%
2018-01-18 23:29:21 +02:00
Slava Monich
8c9e370486 [ril] Support for vendor extensions. JB#39612 2018-01-18 17:34:41 +02:00
Slava Monich
19b80236f6 [ofono] gprs: Add __ofono_gprs_context_settings_by_type 2018-01-18 17:34:40 +02:00
Slava Monich
2ec6fc749d [unit] Added test-sailfish_cell_info_dbus
Tests sailfish_cell_info_dbus.c

  Lines:     215/220  97.7 %
  Functions: 25/25   100.0 %
  Branches:  72/88    81.8 %
2018-01-18 13:34:41 +02:00
Slava Monich
0a3bdd20f4 [ril] Validate dbus_bool_t
libdbus crashes and burns when boolean value is not 0 or 1
2018-01-18 13:27:46 +02:00
Slava Monich
284919e76a Merge branch 'jb40756' into 'master'
Don't repeat cell info requests indefinitely

See merge request !163
2018-01-17 15:14:20 +00:00
Slava Monich
ddcbb89fa1 [ril] Don't repeat cell info requests indefinitely. Fixes JB#40756
If they fail, they typically keep on failing forever. Repeating the
requests doesn't do any good, it's just draining the battery.
2018-01-17 17:11:59 +02:00
Slava Monich
5ec6b8e7ec [test] Improve sailfish_manager.c test coverage 2018-01-04 12:09:34 +02:00
Slava Monich
f94681f6f6 Merge branch 'iccid_watch' into 'master'
Properly reset cached SIM info after removal

See merge request !162
2018-01-04 10:08:35 +00:00
Slava Monich
de8edc84fa [ofono] Properly reset cached SIM info after removal. Fixes JB#39810
sailfish_watch expected to be notified by ofono of every ICCID or IMSI
change, however it wasn't happening when SIM card was getting removed.
That messed things up.
2018-01-03 16:45:39 +02:00
Slava Monich
90faf1b3a5 Merge branch 'fac_timeout' into 'master'
Make sure SIM_IO and QUERY_FACILITY_LOCK requests get completed

See merge request !161
2018-01-02 09:40:11 +00:00
Slava Monich
2b139b6974 [ril] Make sure SIM_IO and QUERY_FACILITY_LOCK get completed
ofono becomes very unhappy if they don't. Also, completion
is required in order to eventually reset SIM I/O active flag.
If doesn't make sense to keep it on forever.
2017-12-25 18:23:57 +02:00
Slava Monich
168f193efb Merge branch 'refresh' into 'master'
Handle SIM reset

See merge request !160
2017-12-08 21:09:15 +00:00
Slava Monich
32d8b5ccfc sim: Don't submit parallel EFpl reads
In addition to not doing unnecessary SIM I/O, this fixes memory leaks
like this one:

==10096== 74 (56 direct, 18 indirect) bytes in 2 blocks are definitely lost in loss record 1,252 of 1,342
==10096==    at 0x4841BF0: calloc (vg_replace_malloc.c)
==10096==    by 0x4B03117: g_malloc0 (gmem.c)
==10096==    by 0xF83DF: concat_lang_prefs (sim.c)
==10096==    by 0xF8697: sim_efpl_read_cb (sim.c)
==10096==    by 0x12CBF7: sim_fs_op_read_block_cb (simfs.c)
2017-12-09 00:06:26 +03:00
Slava Monich
f400ceff80 Merge branch 'sms-filter-api-version' into 'master'
sms-filter: Add api_version field

See merge request !159
2017-12-08 12:37:05 +00:00
Slava Monich
2186c60630 [ril] Handle SIM reset. Fixes JB#40010
This happens when we receive a proactive Refresh command from SIM Tookit
which is generated by some SIMs when people are moving between home and
roaming networks.
2017-12-08 15:26:44 +03:00
Slava Monich
d5fb195e2f [ofono] sms-filter: Added api_version field. JB#37478
This makes it possible to keep using old plugins even if
struct ofono_sms_filter gets extended with new callbacks.
2017-12-08 15:22:16 +03:00
Slava Monich
cbb08079d2 [ril] Housekeeping
Removed some unused stuff
2017-12-07 17:23:22 +03:00
Slava Monich
0583a831fb Merge branch 'sfos_bt_crash' into 'master'
Handle multiple EMULATOR_HFP atoms

See merge request !158
2017-12-01 15:02:32 +00:00
Slava Monich
a8a0758e90 [sailfish_bt] Handle multiple EMULATOR_HFP atoms. Fixes JB#40530
It appears that in some rare cases a new (second) instance can be
created before the old one is destroyed. This was causing a crash.
2017-12-01 16:44:57 +02:00
Slava Monich
9e267487f4 Merge branch 'devel' into 'master'
Add more stuff to ofono devel package

See merge request !157
2017-11-27 20:15:16 +00:00
Slava Monich
c8a774dfee [ofono] Add gdbus.h to the devel package. JB#37478
External (dynamically loadable) plugins need it.
2017-11-27 21:53:25 +02:00
Slava Monich
b88518d0f3 [ofono] Adapt Sailfish OS plugins to newly introduced <ofono/storage.h> 2017-11-27 21:53:25 +02:00
Slava Monich
b223ccc675 storage: Implement ofono_config_dir and ofono_storage_dir 2017-11-27 21:53:25 +02:00
Slava Monich
947a41a5fc include: Add storage.h
To expose ofono directories to dynamically loadable plugins.

Conflicts:
	ofono/Makefile.am
2017-11-27 21:53:25 +02:00
Slava Monich
e0b4e8694d [ril] Fixed a few compilation warnings 2017-11-14 12:47:49 +02:00
Slava Monich
c8db770c99 [ril] Don't retry REQUEST_GET_CURRENT_CALLS on RADIO_NOT_AVAILABLE
Assume that in this case there's no active voice calls.
2017-11-14 12:41:08 +02:00
Slava Monich
1534143e31 [ril] Don't retry REQUEST_DATA_CALL_LIST on RADIO_NOT_AVAILABLE
Assume that in this case there's no active calls.
2017-11-14 12:38:49 +02:00
Slava Monich
d9ad9caf30 Merge branch 'get_imei' into 'master'
Add legacyImeiQuery configuration option.

See merge request !155
2017-11-14 10:33:56 +00:00
Slava Monich
71de574e87 [ril] Added legacyImeiQuery configuration option. JB#39612
MTK ril doesn't understand RIL_REQUEST_DEVICE_IDENTITY
2017-11-13 22:28:31 +02:00
Slava Monich
11efbd68e6 Bumped spec version to 1.20 2017-11-08 20:48:38 +03:00
Slava Monich
9981f07797 Merge branch 'v1.20' into 'master'
[ofono] Upgrade baseline to 1.20. Fixes JB#40330

See merge request !153
2017-11-08 17:47:17 +00:00
Marcel Holtmann
24733f776e Release 1.20 2017-11-08 18:20:52 +03:00
Alexander Couzens
50ec234239 plugins/gobi: add the qmi type to the debug output of discover_cb() 2017-11-08 18:20:52 +03:00
Alexander Couzens
b4991076c6 udevng/gobi: allow to detect ec20 tty devices
The Quectel EC20 uses the same usb id as some gobi 2000 modules (05c6:9215).
2017-11-08 18:20:52 +03:00
Alexander Couzens
8b02884696 udevng/gobi: use subsystem as first identification
Using kernel 4.10 with systemd 232 on archlinux the detection of
a gobi 2000 doesn't detect the qmi/cdc-wdm interface.

The device is detected as follows:

[devnode interface number label sysattr subsystem]
/dev/cdc-wdm1 255/255/255 00 (null) (null) usbmisc
wwan1 255/255/255 00 (null) (null) net
/dev/ttyUSB5 255/255/255 01 (null) (null) tty
/dev/ttyUSB6 255/255/255 02 (null) (null) tty
/dev/ttyUSB7 255/255/255 03 (null) (null) tty
2017-11-08 18:20:52 +03:00
Alexander Couzens
8e224a21f6 udevng/gobi: improve debug output
Add info->sysattr and info->subsystem to the log message.
2017-11-08 18:20:52 +03:00
Luiz Augusto von Dentz
96e191b2d2 handsfree-audio: Add Acquire implementation
This adds Acquire method which can be used by agents that require
pulling the fd directly instead of waiting a NewConnection.
2017-11-08 18:20:52 +03:00
Luiz Augusto von Dentz
7ae3aad622 doc/handsfree-audio-api: Add Acquire method
This adds Acquire method which can be used by agents that require
pulling the fd directly instead of waiting a NewConnection.

Note: sounds servers like PulseAudio do auto suspend streams when idle
for a certain amount of time and once anything happens it will resume
the stream, though this all happens in the so called IO thread in a
blocking fashion making it impossible to receive the fd via NewConnetion
causing the stream to fail to resume. There are other forms to work
around but this seems to be most convenient as we do want the auto
suspend feature to work properly but letting the stream to fail to
resume may create unexpected artifacts while the NewConnection is
handled in main thread.
2017-11-08 18:20:52 +03:00
Luiz Augusto von Dentz
3d5d88241e hfp_hf_bluez5: Rework code handling device changes
This splits the handling of device changes and modem registration so
they can be uses separately.
2017-11-08 18:20:52 +03:00
Jonas Bonn
31e62567e6 qmimodem: set APN for LTE default bearer
Apparently, an empty APN in an ofono context means that that the context
cannot be activated.  connman definitely interprets it this way.

This patch sets a default name of "automatic" for the default bearer if
no other LTE APN is supplied (which is currently the case as the LTE
atom is not in place yet).  Without this, connman happily ignores the
context, even though it has been activated by ofono.
2017-11-08 18:20:52 +03:00
Jonas Bonn
8c3127ef21 qmi: activate default bearer context for LTE networks
When the modem attaches to an LTE network, a default bearer is
automatically negotiated using the "defalt profile" settings.  The
QMI modem, however, does not given any explicit indication that
the bearer exists; instead, we must assume its existence based on
the network registration state.

This patch extends the GPRS atom to signal the presence of a
default bearer when it detects network connectivity on an LTE
network.
2017-11-08 18:20:51 +03:00
Jonas Bonn
1c1fc4199e qmi: use named status values 2017-11-08 18:20:51 +03:00
Jonas Bonn
bfe2f95c4c qmi: use shared services
Apparently it's not legal to create a QMI service multiple times for
a device.  I've been testing with a Quectel EC21 and here it works fine
to do so, but the general case would require "shared" services across
atoms.

This patch switches the users of the NAS and WDS services over to using
a "shared" service instead of each instatiating their own instance.
2017-11-08 18:20:51 +03:00
Jonas Bonn
7e4d99236b qmi: watch packet status for spontaneous disconnection only
There are three principal ways for a context to become disconnected:

i)  deactivate_primary() is called
ii)  the network registration is lost and the context is cleaned up
via _detach_shutdown() (via release_all_contexts())
iii) the network decides to disconnect the context

We need to watch the packet status in order to detect case iii).  For
case i) and ii), stop_net will be called, the pkt_handle will be
cleared, and subsequent packet status notifications be ignored.

This patch makes it so that the packet status "disconnected" event
is only propagated when the pkt_handle has not been cleared, indicating
an unrequested disconnection.

This should fix a race reported by Christophe Ronco whereby the packet
status disconnect notification is called between activate_primary
(start_net) and it's callback (start_net_cb).
2017-11-08 18:20:51 +03:00
Luiz Augusto von Dentz
0935a227be hfp_hf: Handle ServicesResolved signal
This adds handling for ServicesResolved signal which tells when BlueZ
is done resolving the device services so the code will no longer ignore
devices that got its services resolved after Paired signal.
2017-11-08 18:20:51 +03:00
Luiz Augusto von Dentz
ffdeb3692c hfp_hf: Fix not creating modem during NewConnection
In case the UUIDs are not updated, as they are still being resolved, when
Paired property changes a modem will never be registered.

In order to fix this problem allow modems to be registered directly
during NewConnection.
2017-11-08 18:20:51 +03:00
Vincent Cesson
627904e382 gemalto: Set vendor for sms atom 2017-11-08 18:20:51 +03:00
Vincent Cesson
0ab0677765 atmodem: Fix SMS reception for Gemalto modems
SMS reception is not working for Gemalto modems because of +CMT parsing.
PDU length is the first argument of +CMT URCs in Gemalto modems.

Add a switch case on vendor info to handle Gemalto case.
Also handle acknowledgment, +CNMA takes only one parameter.

CMT parsing is moved from at_parse_cmt() to at_cmt_notify(). This
function is modified to match the style of at_cmgr_notify() and it
includes a switch case for CINTERION modems.
2017-11-08 18:20:51 +03:00
Jonas Bonn
fe6af108ca Add support for Quectel EC21/25 modems
This follows the same pattern as the Telit QMI modems, routing the
setup through a QMI driver.  I think this can be cleaned up somehow,
but for now this at least provides support for these two modem models
so that others can aid in testing.
2017-11-08 18:20:51 +03:00
Vincent Cesson
650ff3642f gemalto: Use sim_state_query for sim detection
Populate gemalto_data structure.
Add sim_state callbacks.
Fix enable/disable return value.
2017-11-08 18:20:51 +03:00
Jonas Bonn
41d310aa61 qmi: move rat_to_tech() into own module
We want to use this function from multiple atoms so this patch moves
it out to its own module for NAS-related helper functions.
2017-11-08 18:20:51 +03:00
Jonas Bonn
27adf83a4b ofono: add missing header inclusions
This is a "leaf" header and doesn't even have header guards, but
it still seems natural that the header should pull in its own declarations
rather than relying on the including source file to ensure that they
are included.
2017-11-08 18:20:51 +03:00
Jonas Bonn
55d227ba46 qmi: add missing header inclusion 2017-11-08 18:20:51 +03:00
Jonas Bonn
dcc1d366f0 qim: use named status value 2017-11-08 18:20:51 +03:00
Jonas Bonn
83cf94824d qmi: implement detach_shutdown method
The detach_shutdown method is invoked to unconditionally release
an active context.  For QMI, this is equivalent to a call to
deactivate_primary.

This patch makes the callback to deactivate_primary optional and
implements detach_shutdown to simply call it.  When there is no
callback, the stop_net callback notifies ofono about the context
release via an asynchronous ofono_gprs_context_deactivated() call.
2017-11-08 18:20:51 +03:00
Jonas Bonn
3a0c598805 qmi: free cb_data on error
...and move allocation of structure up to variable declarations to
match the pattern used elsewhere in the code.
2017-11-08 18:20:51 +03:00
Jonas Bonn
b098314251 qmi: read_settings needs to call start network
For LTE networks, a default bearer is automatically activated when
the modem registers to the network.  QMI modems, however, do not
automatically enable the network interface just because the bearer
exists; a call to "start network" needs to be made in order to
get the packet handle before get_settings will return any data and
the network interface can be configured.

This patch makes read_settings call "start network" in order to
enable the interface for the default bearer.  No new bearer will
be created with this call and the settings for the bearer will come
from the default profile, irregardless of what parameters are passed
to the "start network" method.
2017-11-08 18:20:51 +03:00
Jonas Bonn
4ae6c6c0b1 gprs: set driver_attached when activating automatic contexts
The ofono_gprs_cid_activated attachment machinery cannot go through
ofono_gprs_status_notify for getting the attached property set because
that would result in the automatic contexts that were just set up
being released.  As such, it needs to call gprs_set_attached_property
manually.  Doing so, however, means that the driver_attached property
never gets set, resulting in all contexts being released when the
network transitions between registered states (roaming/non-roaming).
2017-11-08 18:20:51 +03:00
Jonas Bonn
d5f0f3b32d gprs: _cid_activated is an 'attaching' state
ofono_gprs_status_notify is an asynchronous notification that messes
with the 'attached' state of the GPRS atom.  This method is normally
prevented from running while an attach is in progress because the
attachment machinery wants to finish up and make it's own determination
of attach state.

When automatic context activation is relevant, as for LTE networks,
the ofono_gprs_cid_activated machinery replaces the usual set_attach
machinery for attaching to the network.  The cid_activated variant,
however, does not guard against simulatenous invocations of
ofono_gprs_status_notify.  This causes a race whereby status_notify
sets the state to 'attached' before the context is fully constructed
and set to active.  If the connection manager sees the 'attached'
state before there are any 'active' contexts, it may decide to
activate a context manually which is not the correct behaviour for
this type of network.

This patch makes the *_cid_activated machinery an 'attaching' state,
introducing the same guards that set_attached has to prevent
ofono_gprs_status_notify from running concurrently.
2017-11-08 18:20:51 +03:00
Jonas Bonn
0209e9847b qmi: fix typo 2017-11-08 18:20:51 +03:00
Jonas Bonn
a499ac07ca qmi: duplicate callback data correctly 2017-11-08 18:20:51 +03:00
Vincent Cesson
04342bbe69 gemalto: Change offline mode, keep USIM available
Gemalto has two airplane mode:
CFUN=0 disables USIM
CFUN=4 keeps USIM connected
2017-11-08 18:20:51 +03:00
Vincent Cesson
d0d3e4f2f1 gemalto: Clean post init functions
Remove inappropriate interfaces.
Move GPRS init from post_online to post_sim.
2017-11-08 18:20:51 +03:00
Denis Kenzior
edcbc5c7e3 AUTHORS: Mention Jonas' contributions 2017-11-08 18:20:51 +03:00
Denis Kenzior
1df55e3042 qmi: Use destroy callback for context activate 2017-11-08 18:20:51 +03:00
Denis Kenzior
df93fceb4f qmi: Use destroy callback for context deactivate
This ensures that cbd will be freed even if the device is hot-unplugged.
Also, this fixes a memory leak on the failure path inside stop_net_cb
2017-11-08 18:20:51 +03:00
Jonas Bonn
d21d1a166f qmi: implement read_settings for automatic contexts
For LTE, a context is created automatically when the modem registers
to the network.  The read_settings function is called for these
automatic contexts to get their configuration.
2017-11-08 18:20:51 +03:00
Jonas Bonn
458f905262 qmi: retrieve GPRS context parameters
The GPRS context needs to be configured with connection parameters when
the bearer has been established.  This was only partially implemented, so
this patch adds additional parameters to those passed to the context.
2017-11-08 18:20:51 +03:00
Jonas Bonn
9f474ba723 qmi: add WDS parameter definition 2017-11-08 18:20:51 +03:00
Jonas Bonn
a3b4421422 qmi: NAS definitions adjustment
Calling the ps_state/cs_state alternatives *ATTACH_STATUS* was confusing
because there is also a status field in the *serving_system structure.
This patch does a minor rename and adds the appropriate definitions for
the status field.
2017-11-08 18:20:50 +03:00
Denis Kenzior
28bc1e37ed qmi: Fix qmi_device_shutdown
qmi_device_shutdown allocated a new orphaned data structure and kicked
off a timeout to wait for the shutdown to complete.  The logic was quite
racy, but the main issue was that the timeouts could not be canceled
when the underlying qmi_device object was destroyed.  This resulted in
crashes.

This patch switches to first-past-the-gate mechanism.  Since only the
modem driver should be issuing a qmi_device_shutdown call, this should
not be a limitation.  The shutdown source is then tracked on the
qmi_device object itself and is canceled when the qmi_device object is
freed.

As an added bonus, the shutdown_destroy callback should now actually
function.  Before it was simply never called.
2017-11-08 18:20:50 +03:00
Denis Kenzior
c0b96a4319 qmi: Optimize structure allocations
struct discovery was allocated for every discovery procedure that was
kicked off, which itself allocated a structure.  This patch uses a
class/subclass concept to only allocate a single structure per discovery
procedure.
2017-11-08 18:20:50 +03:00
Jonas Bonn
4296616d00 modem: set_online is valid for AlwaysOnline modems
Calling set_online(TRUE) for an AlwaysOnline modem should succeed; the
modem is, after all, in the requested state when the call returns.
Returning not_implemented is not necessarily wrong, but it's a bit ugly.
2017-11-08 18:20:50 +03:00
Jonas Bonn
3a43f96fe4 qmi: fix bad lookup and double free
This function was never removing discovery instances because it was looking
them up in the wrong list.  This led to some strangeness with the discovery
callbacks being invoked after the "failure" timeout of 5 seconds and
consequent failures with everything getting out of sync.

With this patch we fix the lookup to use the correct queue.  There's also
a double-free in the function that was never being hit before because the
lookups never succeeded; fix that as well.

With this, service discovery and creation work as expected when testing with
an EC21.
2017-11-08 18:20:50 +03:00
Jonas Bonn
b82a1001e2 qmi: add service ID's 2017-11-08 18:20:50 +03:00
Jonas Bonn
84dc7e2016 udevng: remove 'option' driver setup
No driver named 'option' exists so this device can never be instantiated.
2017-11-08 18:20:50 +03:00
Lukasz Nowak
1482728a61 atmodem: telit - re-attach gprs automatically
Telit AT modem firmware (tested with UE910-EUR) generates
+CGREG: 0\r\n\r\n+CGEV: NW DETACH
after a context is de-activated and ppp connection closed.
Then, after a random amount of time (observed from a few seconds
to a few hours), an unsolicited +CGREG: 1 arrives.
Attempt to fix the problem, by sending AT+CGATT=1 once.
This does not re-activate the context, but if a network connection
is still correct, will generate an immediate +CGREG: 1.
2017-11-08 18:20:50 +03:00
Jonas Bonn
428f62041b plugins: remove udev module
This functionality has been moved into the udevng module and was
already disabled in an earlier patch.
2017-11-08 18:20:50 +03:00
Jonas Bonn
4b6ec99973 udevng: get properties from interface
Device properties are generally on the device, on the USB interface
descriptor, or the on the USB device descriptor.
2017-11-08 18:20:50 +03:00
Jonas Bonn
0c01da5378 udevng: hook up legacy devices
...and disable old udev code by shorting it out in it's init() function.

The check_device function is augmented to differentiate between USB
and serial devices:

- if the device sits on a USB bus, the device is handled as before
- if not, an attempt is made to handle the device as a serial device
2017-11-08 18:20:50 +03:00
Jonas Bonn
8004756c3d udevng: match on the hsi subsystem for legacy devices 2017-11-08 18:20:50 +03:00
Jonas Bonn
e01df1a3f1 udevng: add serial device handling functions
This adds, but does not hook up, support for simple serial modems.  These
modems generally have only a single device node so are simpler than the
USB devices which generally have different device nodes for different
functions.  These modems are currently handled by udev.c, but this
functionality will allow to remove that module completely in a later patch.

- A new "device_info" type is created called serial_device_info
- the function add_serial_device sets up a modem_info structure and a
  serial_device_info for the device
- A reference to the device's udev node is saved in the device info
- The device driver is retrieved from the OFONO_DRIVER environment variable
  which needs to be set up by some udev rule
- Setup functions are added for these types of devices: a common function
  setup_serial_modem covers the generic (simple) case, whereas modems
  with special requirements are given their own setup functions to handle
  the special bits
- Modem destroy needs to know the "device_info" type in order to clean
  up properly, so a 'type' value is set on the modem_info structure to
  guide selection of the proper cleanup function
2017-11-08 18:20:50 +03:00
Denis Kenzior
46820a7ba0 qmi: track discovery tasks so clean up is possible
There are various device & service discovery tasks that are initiated
based on a qmi_device object.  qmi_device object does not currently
keep track of these tasks.  Unfortunately the qmi_device object can
go away at any time, and these tasks can become orphaned.

The result of this can lead to crashes.  E.g. a discovery task timeout fires
after the qmi_device object has been destroyed.  Since the object is no
longer valid, any accesses to it will likely result in a SEGFAULT.

This patch attempts to track all discovery tasks on the qmi_device
object itself, so that they can be cleaned up properly.  This patch does
not handle the qmi_device_shutdown functionality.
2017-11-08 18:20:50 +03:00
Lukasz Nowak
0493629a9d unit: rilmodem-test - add missing string.h
Remove warnings of undeclared memcpy, strncpy, etc.
2017-11-08 18:20:50 +03:00
Lukasz Nowak
41b3459a5d udevng: add Telit LE910 V1 support
Tested with LE910-SVG and Verizon.
2017-11-08 18:20:50 +03:00
Jonas Bonn
b27373c8a4 udev: remove extraneous subsystem check
The enumeration construct is already set up with matches for these
subsystems.
2017-11-08 18:20:50 +03:00
Jonas Bonn
b450c8fbe3 udev: simplify wavecom modem registration 2017-11-08 18:20:50 +03:00
Jonas Bonn
1ac24f32e3 udev: simplify ifx modem registration 2017-11-08 18:20:50 +03:00
Jonas Bonn
977fc5bc15 udev: add common modem registration code
Many of these drivers do exactly the same setup when registering
the modem.  Consolidate these setup functions into common code.
2017-11-08 18:20:50 +03:00
Jonas Bonn
787bddf47b udev: simplify add_modem
Adding a modem boils down to finding the device in the hierarchy with
the OFONO_DRIVER property.  The original code special-cased the property
being on the device itself rather than on a parent device.  This patch
combines the two cases.
2017-11-08 18:20:50 +03:00
Jonas Bonn
c32cd532f2 udev: remove unused modem property
The property 'Registered' is not used anywhere.
2017-11-08 18:20:50 +03:00
Jonas Bonn
18f2345124 udev: get udev property via lib function 2017-11-08 18:20:50 +03:00
Jonas Bonn
00b623e8c4 udev: remove extraneous subsystem check
The udev-monitor already guarantees that only devices with these
subsystems will be returned so we don't need to check again.
2017-11-08 18:20:50 +03:00
Jonas Bonn
452108d058 ofono.rules: remove 'change' action
The code doesn't do anything with this action so don't bother setting
extra device properties for it.
2017-11-08 18:20:50 +03:00
Jonas Bonn
6b0712dae4 udevng: simplify logic in check_usb_device
This patch simplifies and cleans up the check_usb_device function a bit
by doing the two following (slightly intertwined) things:

1)  The parent "usb_device" is searched for early in this function and this
device will always have the ID_VENDOR_ID and ID_MODEL_ID properties.
As such, we can get them from this device and thereby be certain that
we _always_ have them available.

2)  The logic of iterating the vendor_list table is cleaned up.  It's
easier to follow and won't be any less efficient.
2017-11-08 18:20:50 +03:00
Jonas Bonn
9a309f499b gobi: query presence of WDA service 2017-11-08 18:20:50 +03:00
Jonas Bonn
a204c993e5 qmimodem: add WDA service string 2017-11-08 18:20:50 +03:00
Jonas Bonn
e881376127 qmimodem: fix typo 2017-11-08 18:20:50 +03:00
Lukasz Nowak
66c98d724c gobi: Do not use low-power modes for some modems
Telit QMI modems have a problem with the low-power operating modes.
After entering and leaving such a state, UIM service does not return.
The sim card is still marked as powered-down. The QMI interface does
not have a way to power it back on.

To avoid this, keep modems with the "AlwaysOnline" flag online
in the disable-modem and offline-modem procedures.
2017-11-08 18:20:49 +03:00
Denis Kenzior
5c38fe6a84 AUTHORS: Mention Lukasz's contributions 2017-11-08 18:20:49 +03:00
Lukasz Nowak
e3bb317504 qmimodem: detect utf-8 string as operator name
Telit QMI modems can return non-utf-8 characters in plmn-desc.
Observed with LE910-SVG and Verizon. When that happens, libdbus
will abort ofono.
If non-utf-8 characters are detected, use mccmnc string.
2017-11-08 18:20:49 +03:00
Lukasz Nowak
713022a7e8 qmimodem: read ss_info at probe time
LTE modems (observed with Telit LE910 V1) can power on
already registered to a network. In that case, the SS_INFO
change notification will never arrive, and the gprs driver
will never be marked as attached.

To avoid this situation, read SS_INFO at probe time, and if
registered, mark the gprs driver as attached.
2017-11-08 18:20:49 +03:00
Denis Kenzior
6b79f32715 qmimodem: Fix warning
This was introduced by the previous patch:
drivers/qmimodem/devinfo.c: In function ‘get_ids_cb’:
drivers/qmimodem/devinfo.c:129:14: error: implicit declaration of function ‘strcmp’ [-Werror=implicit-function-declaration]
  if (!str || strcmp(str, "0") == 0) {
2017-11-08 18:20:49 +03:00
Lukasz Nowak
2386e99ad8 qmimodem: telit LE910 V1 - fix ESN string
Telit QMI modems report "0", rather than a NULL string,
if ESN is not available.
2017-11-08 18:20:49 +03:00
Christophe Ronco
6ca82960c9 huawei: reopen modem channel if it disconnects
On E3372 after a GPRS disconnection, modem AT channel (used by PPP) gets
disconnected (G_IO_HUP and G_IO_ERR are detected in received_data
in gatio.c).
After that all connection attempts fail because we are not able to send
any AT commands on modem channel (it is closed).

With this patch, when this behavior is detected, we close gprs context
driver, reopen AT channel and gprs context driver.
2017-11-08 18:20:49 +03:00
Christophe Ronco
93891578fc provision: add plugin to provision from config file
This plugin allows to provision gprs-context data based on MCC and MNC.
This is useful when provisioning using mbpi fails (either because you
are using a private APN or because there are multiple internet type context
for your operator in mbpi database).
Config file is STORAGEDIR/provisioning.
Config file should look like that:
[operator:MCC1,MNC1]
internet.AccessPointName=apn1
internet.Username=myUsername
internet.Password=myPassword
internet.AuthenticationMethod=pap
internet.Protocol=ipv6
[operator:MCC2,MNC2]
internet.AccessPointName=apn2

The only mandatory parameter for each operator is internet.AccessPointName.

Parameter description:
internet.AccessPointName: APN
internet.Username: Username
internet.Password: Password
internet.AuthenticationMethod: authentication method.
 Possible values are:
  - pap
  - chap
 Default is chap if unset.
internet.Protocol: protocol
 Possible values are:
  - ip: ipv4
  - ipv6
  - dual
 Default is ip if not set.

All parameters are prefixed with internet to be able to extend this plugin
to other type of contexts (MMS, ...).

Conflicts:
	ofono/Makefile.am
	ofono/plugins/file-provision.c
2017-11-08 18:20:49 +03:00
Christophe Ronco
7bcadcd300 qmimodem: fix sim file reading on MC7304
Command read_file_info on MC7304 always fails.
Using qmicli or AT command, I am able to read file info.
Qmicli command is:
qmicli -d /dev/cdc-wdm0 --uim-get-file-attributes=0x3f00,0x7fff,0x6fad
[(null)] Successfully got file '/dev/cdc-wdm0' attributes from the UIM:
Card result:
        SW1: '0x90'
        SW2: '0x00'
File attributes:
        File size: 4
        File ID: 28589
        File type: transparent
        Record size: 0
        Record count: 0
        Read security attributes: (always) (null)
        Write security attributes: (single) adm
        Increase security attributes: (always) (null)
        Deactivate security attributes: (single) adm
        Activate security attributes: (single) adm
        Raw:    62:17:82:02:41:21:83:02:6F:AD:8A:01:05:8B:...

After a check of parameters sent by qmimodem driver and qmicli,
the only difference is on parameter "Session Information".
Session type sent by qmimodem driver is 'Card on slot 1'.
Session type sent by qmicli command is 'primary-gw-provisioning'.
Changing session type in qmimodem driver fixed problem (on this modem).

Comparing with what is done by qmili command
2017-11-08 18:20:49 +03:00
Christophe Ronco
b3f8dc4a24 atmodem: use ATD99 to enter data state when needed
Some modems do not support AT+CGDATA="PPP",X to enter data state.
Use AT+CGDATA=? to detect these modems and for them use ATD*99***X#
to enter data state.
2017-11-08 18:20:49 +03:00
Christophe Ronco
38e3122217 gprs: fix error check of gprs_cid_alloc function
When there is no context id available, idmap_alloc and
gprs_cid_alloc return max + 1.
2017-11-08 18:20:49 +03:00
Piotr Haber
f7de0ab3ef telit: register SIM if it goes straight to ready
SIM without PIN goes straight to state 3 (INSERTED and READY)
on some modem/firmware versions.
2017-11-08 18:20:49 +03:00
Denis Kenzior
defe008062 rilmodem: Fix warning
drivers/rilmodem/stk.c: In function ‘ril_stk_probe’:
drivers/rilmodem/stk.c:210:18: error: ‘data’ is used uninitialized in
this function [-Werror=uninitialized]
  struct cb_data *cbd = cb_data_new(stk, NULL, data);
2017-11-08 18:20:49 +03:00
Denis Kenzior
ec930e17c8 AUTHORS: mention André's contributions 2017-11-08 18:20:49 +03:00
André Draszik
9f1731cffa plugins: telit: send AT&C0 on both channels
At least firmware version 12.00.405 on the UE910-EUR otherwise
closes the AT command port whenever the PPP connection is
dropped, and we'd be left in a funny state.
2017-11-08 18:20:49 +03:00
Antara Borwankar
ed8d55d2d5 ril_intel: Add support for stk 2017-11-08 18:20:49 +03:00
Antara Borwankar
7b6a461b83 rilmodem: Send needed RIL request for stk init
sending RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING after
stk atom is created so that modem will inititialize
sim toolkit by sending terminal profile to sim.
2017-11-08 18:20:49 +03:00
Piotr Haber
3b0ff8fd83 telit: add support for UE866 2017-11-08 18:20:49 +03:00
Piotr Haber
00b5886cf9 udevng: unify telit and xe910
Unified setup for Telit devices using
usbserial and cdc_acm drivers.
2017-11-08 18:20:49 +03:00
Piotr Haber
c16fd4e642 plugins: rename xe910 to telit
Unify old telit and xe910 plugins.
Dropping support for Bluetooth SAP.
Add support for UC864 family.
2017-11-08 18:20:49 +03:00
Christophe Ronco
4b92ac8ba6 qmimodem: change kernel driver data format if needed
During gprs-context driver probe function, check kernel device driver
data format and modem low level data format.
If they are different, align kernel device driver data format on
modem low level data format.
If an error occurs during this process, continue probing without error.
This is inspired by what is done in qmicli and qmi-network (package
libqmi).
2017-11-08 18:20:49 +03:00
Denis Kenzior
5b432b8280 qmi: Fix typo 2017-11-08 18:20:49 +03:00
Christophe Ronco
31aff54463 qmimodem: get/set kernel device driver data format
Add a way to get and set data format expected by kernel device driver.
This is inspired by what is done in qmicli (package libqmi).
It does not use QMI protocol but a sysfs exported by kernel driver.
To use this feature, kernel version must be equal or more than 4.5.
2017-11-08 18:20:49 +03:00
Denis Kenzior
c669ec3c88 tools: Remove unused qmi tool 2017-11-08 18:20:49 +03:00
Piotr Haber
8c2f54abe0 xe910: support for Telit LE910V2 modem
LE910V2 is next generation Telit LTE modem.
It supports 3GPP Rel. 9 LTE Cat. 4 over multiple bands.
2017-11-08 18:20:49 +03:00
Piotr Haber
804121cbed telitmodem: support for CDC-NCM network adapter
Network Control Model is a new Communication Device Class
protocol for exchanging Ethernet frames over USB.
NCM is intended to be used with high-speed network
attachments such as HSDPA and LTE data services.
2017-11-08 18:20:49 +03:00
Piotr Haber
839e626ee6 udevng: setup of Telit LE910V2
Setup LE910V2 in default USB composition (1bc7:0036)
with 6 CDC-ACM serial ports and 1 CDC-NCM network adapter.
2017-11-08 18:20:49 +03:00
Piotr Haber
3a17724136 plugins: Handle HE910 and UE910 variants
Telit modems HE910 and UE910 share the same USB
vendor and device IDs (1bc7:0021) but they are
different devices.
HE910 is HSPA Class 14/6 and UE910 is Class 8/6.
Both come in voice-enabled variants.
HE910 also comes in variants with built-in GPS.
2017-11-08 18:20:49 +03:00
Piotr Haber
7b0c6610e0 plugins: rename he910 to xe910
In preparation for more generic support
of Telit xE910 family.
2017-11-08 18:20:49 +03:00
Piotr Haber
0e0b1e98c5 qmimodem: send authentication credentials
Pass authentication method, user and password
to QMI WDS service.
2017-11-08 18:20:48 +03:00
Piotr Haber
b0975c44b1 doc: description of Telit LE910V2 network setup
NCM network interface on LE910V2 modem needs to be
configured in a specific way after connection is established.
2017-11-08 18:20:48 +03:00
Denis Kenzior
25a6049cf6 doc: Add 'switch' to item M1 2017-11-08 18:20:48 +03:00
Denis Kenzior
02fcbdb245 AUTHORS: Mention Piotr's contributions 2017-11-08 18:20:48 +03:00
Piotr Haber
a3a8ea4183 atmodem: add LTE to Telit #PSNT status parser
Network type of 4 in Telit #PSNT command response
denotes LTE network
2017-11-08 18:20:48 +03:00
Vincent Cesson
92d7fb848b gemalto: Add location reporting support 2017-11-08 18:20:48 +03:00
Vincent Cesson
0b6327a7fc drivers: Add gemaltomodem driver to handle GNSS
Add a new location-reporting driver for Gemalto Cinterion modems based
on telit implementation + use it in gemalto plugin. It supports
activation of GNSS engine (Request) with command AT^SGPSC. This driver
is tested on PHS8. NMEA frames are accessible on /dev/ttyUSB1.
2017-11-08 18:20:48 +03:00
Vincent Cesson
84bd588152 udevng: complete gemalto setup
Complete the Gemalto setup with cdc_wdm and qmi,
so all enumerated devices are associated with gemalto.
2017-11-08 18:20:48 +03:00
Christophe Ronco
9e952cf042 qmimodem: query_passwd_state can be retried
Retry command QMI_UIM_GET_CARD_STATUS during query_passwd_state if a
temporary error status has been detected.
This happens with a MC7430 modem when query_passwd_state is called just
after PIN is entered.
2017-11-08 18:20:48 +03:00
Vincent Cesson
27a1a05aa7 udevng: Add Gemalto P-family detection
Add a new function setup, based on telit, to handle Gemalto P-family
discovery. The setup looks for USB interfaces:
application=/dev/ttyUSB2
gps=/dev/ttyUSB1
modem=/dev/ttyUSB3
2017-11-08 18:20:48 +03:00
Vincent Cesson
657841e2b0 plugins: Add Gemalto plugin for Cinterion P-family
Actual cinterion plugin is not compliant with newer Gemalto modems.
Gemalto plugin is based on cinterion with a custom struct to handle the
interfaces Application and Modem.
2017-11-08 18:20:48 +03:00
Denis Kenzior
02172f6922 AUTHORS: Mention Vincent's contributions 2017-11-08 18:20:48 +03:00
Vincent Cesson
0dd225b594 atmodem: Fix CGDCONT result parsing.
CGDCONT result parsing fails if first list contains several ranges. For
example with modem Cinterion PHS8:

 AT+CGDCONT=?
 +CGDCONT: (1-17,101-116),"IP",,,(0),(0-4)

Solution: read first range and jump to second list instead of trying to
close the brackets.
2017-11-08 18:20:48 +03:00
Christophe Ronco
452d0d4b5a qmimodem: add pin_send feature
Add ability to send PIN to a QMI modem using QMI_UIM_VERIFY_PIN command.
This has been tested on MC7304 and MC7430 modems.
2017-11-08 18:20:48 +03:00
Christophe Ronco
2edae61c0b qmimodem: get password state from modem
Password state and number of retries asked to modem using
QMI_UIM_GET_CARD_STATUS command rather than remembered after initial
QMI_UIM_GET_CARD_STATUS command.
2017-11-08 18:20:48 +03:00
Christophe Ronco
141abd5390 udevng: Sierra modems use SIM driver 2017-11-08 18:20:48 +03:00
Christophe Ronco
22faa0f26a qmimodem: Add read_imsi to qmimodem sim driver
Add read_imsi feature to qmimodem sim driver.
This is based on DMS service.
On MC7430, this is mandatory to be able to use this driver for GPRS
connection because reading IMSI via EF reads fails.
2017-11-08 18:20:48 +03:00
Christophe Ronco
4d2453f3a8 sim: backup driver read_imsi by IMSI via EF read
If read_imsi driver function fails, try to obtain IMSI via EF read
2017-11-08 18:20:48 +03:00
Slava Monich
7a5f52c1f3 sim: Stop facility lock query sequence on removal
SIM card can be removed while the query is in progress. There's
still a remote possibility that SIM card is removed and inserted
back while the query is pending, that would start the second query
sequence and end up invoking sim_initialize() twice. But at least
these checks reduce the probability of something like that happening.
2017-11-08 18:20:48 +03:00
Christophe Ronco
1ad109f8c7 qmimodem: fix QMI notification messages handling
QMI notification messages handlers are never called on MC7430 without this fix.

- Do not test transaction id before calling notification handler.  On MC7430,
notification messages contain a not null transaction id (starts with 1,
increased at each message for a particular client).
- On MC7304 transaction id in notification messages is always 0.
2017-11-08 18:20:48 +03:00
Denis Kenzior
1347755b6f AUTHORS: Mention Christophe's contributions 2017-11-08 18:20:48 +03:00
Christophe Ronco
62253744a7 qmimodem: fix get signal strength
Get current signal strength (type: 0x01), not list of other signals strength
(0x10)

Without this fix:
- I can't get a signal strength on MC7430 because list does not exist
	(only one signal strength).
- On MC7304, result is wrong
2017-11-08 18:20:48 +03:00
Marko Šulejić
9a608210cd atmodem: fix typo 2017-11-08 18:20:48 +03:00
Djalal Harouni
adbfdb23a7 test:netmon: support EARFCN, Eband and CQI in testing scripts 2017-11-08 18:20:48 +03:00
Djalal Harouni
ac5d0abe5e netmon: handle OFONO_NETMON_INFO_{EARFCN|EBAND|CQI} 2017-11-08 18:20:48 +03:00
Djalal Harouni
8dbaaa5efe doc: document netmon EARFCN, EBand and CQI properties
Documentation for:
EARFCN: E-UTRA Absolute Radio Frequency Channel Number.
EBand: E-UTRA operating Band.
CQI: Channel Quality Indicator.
2017-11-08 18:20:48 +03:00
Djalal Harouni
fa1bcc1c19 netmon: add NETMON_INFO_{EARFCN|EBAND|CQI}
Add the following types to use with ublox modems +UCGED command.

EARFCN: E-UTRA Absolute Radio Frequency Channel Number.
EBand: E-UTRA operating Band.
CQI: Channel Quality Indicator.
2017-11-08 18:20:48 +03:00
Antara Borwankar
32138ecd04 ril_intel: changes for lte modem
plugin modified to bring up lte atom and set MODEM_PROP_LTE_CAPABLE
to TRUE
2017-11-08 18:20:48 +03:00
Antara Borwankar
5e999f0b47 ril_intel: renamed ril_sofia3gr to ril_intel
renamed ril_sofia3gr.c to ril_intel.c
2017-11-08 18:20:47 +03:00
Ankit Navik
5c74095f44 rilmodem: set LTE preferred in rat mode 2017-11-08 18:20:47 +03:00
Ankit Navik
55befb87cd rilmodem: Add lte atom driver
Adds rilmodem driver for setting the default APN command.
The default APN is manage by config storage.
2017-11-08 18:20:47 +03:00
Denis Kenzior
9d7a0f8615 ubloxmodem: Fixup minor style issues
- useless return at the end of a function
- mixed tabs & spaces for indentation
- over 80 characters for the comment
- line > 80 characters due to access technology conversion.  Replaced
  with a direct assignment.
2017-11-08 18:20:47 +03:00
Denis Kenzior
974100732c ubloxmodem: Fix warning
drivers/ubloxmodem/netmon.c: In function ‘req_cb_data_unref’:
drivers/ubloxmodem/netmon.c:131:10: error: ‘return’ with a value, in
function returning void [-Werror]
   return NULL;
2017-11-08 18:20:47 +03:00
Djalal Harouni
35a6a4d8d0 build: build the ublox netmon driver 2017-11-08 18:20:47 +03:00
Djalal Harouni
f2a64c4d15 ubloxmodem: register and initialize the netmon driver 2017-11-08 18:20:47 +03:00
Djalal Harouni
ed1e90990e ubloxmodem: add the netmon driver
This adds a netmon driver for ublox. The driver support both +COPS and
+CESQ commands to return the previously added ofono netmon types:

RSCP: Received Signal Code Power
ECN0: Received Energy Ratio
RSRQ: Reference Signal Received Quality
RSRP: Reference Signal Received Power

Current revision makes the driver use ref countig when chaining multiple
AT commands.
2017-11-08 18:20:47 +03:00
Denis Kenzior
c8a4727243 AUTHORS: Mention Djalal's contributions 2017-11-08 18:20:47 +03:00
Djalal Harouni
2ccabbbdef test: support NETMON_INFO_{RXLEV|RSCP|ECN0|RSRQ|RSRP}
Display the following fields if they are returned.

RXLEV:  Received Signal Strength
RSCP:   Received Signal Code Power
ECN0:   Received Energy Ratio
RSRQ:   Reference Signal Received Quality
RSRP:   Reference Signal Received Power
2017-11-08 18:20:47 +03:00
Djalal Harouni
7c3638143d netmon: handle NETMON_INFO_{RSCP|ECN0|RSRQ|RSRP}
Handle the newly added netmon info types.
2017-11-08 18:20:47 +03:00
Djalal Harouni
a0e8b24c70 doc: Add additional netmon properties
This adds documentation for the following fields in
networkmonitor-api.txt

RSCP: Received Signal Code Power
ECN0: Received Energy Ratio
RSRQ: Reference Signal Received Quality
RSRP: Reference Signal Received Power
2017-11-08 18:20:47 +03:00
Djalal Harouni
41d432211e include: add NETMON_INFO_{RSCP|ECN0|RSRQ|RSRP}
Add more ofono netmon info types that will be served through the netmon
interface. The main user of this now will be the ublox modem.

RSCP: Received Signal Code Power
ECN0: Received Energy Ratio
RSRQ: Reference Signal Received Quality
RSRP: Reference Signal Received Power
2017-11-08 18:20:47 +03:00
Denis Kenzior
94f6138e23 netmon: Fix style issue 2017-11-08 18:20:47 +03:00
Denis Kenzior
e82ce81858 netmon: No need to initialize mcc/mnc 2017-11-08 18:20:47 +03:00
Dragos Tatulea
c18fa5e038 gprs: lte: set attached after successful activation
Otherwise the attached state gets to be set before the actual LTE
automatic context is ready. This triggers a race between connman
and ofono: connman sees status attached before the context is active
so connman will try to activate another context with same apn and will
fail over and over again.
2017-11-08 18:20:47 +03:00
Dragos Tatulea
c7c53adbb5 lte: fix early imsi free
storage_close was creating an empty sync file in /var/lib/ofono/lte
when it should have been closing the proper file
/var/lig/ofono/<imsi>/lte.
2017-11-08 18:20:47 +03:00
Slava Monich
30a9ef7e7a Sync whitespaces with upstream
Conflicts:
	ofono/src/smsutil.c
2017-11-08 18:20:47 +03:00
Dragos Tatulea
064181f903 ubloxmodem: tweak to work on different firmware
The U-Blox documentation specifies the following:
* get interface ip and dns from +CGDCONTRDP
* get gw ip and netmask from +UIPADDR

However, different firmware versions have different befaviour:

* On newer firmware, +UIPADDR returns error. But it's possible to configure
gateway ip == ipterface ip (read from CGDCONTRDP).

* On older firmware, we can actually use the commands specified in the
docs.

This patch runs +CGDCONTRDP, configures everything and then tries to run
+UIPADDR. In that works, reconfigures gw ip and netmask.
2017-11-08 18:20:47 +03:00
Dragos Tatulea
7d22ed86f8 plugins: ublox: enable lte driver for tobyl2 2017-11-08 18:20:47 +03:00
Dragos Tatulea
0641a981d1 build: add support for ublox lte atom driver 2017-11-08 18:20:47 +03:00
Dragos Tatulea
ceb6741a67 ubloxmodem: add lte atom driver
Adds U-Blox Toby L2 driver for setting the default APN via the
+UCGDFLT command. Currently only IPv4 is supported. APN is
not stored to modem's non-volatile memory. oFono will manage this
default APN via it's config storage.

When receiving an empty default APN, the value is reset.
2017-11-08 18:20:47 +03:00
Denis Kenzior
4797cab10b lte: If method is NULL, return not implemented 2017-11-08 18:20:47 +03:00
Denis Kenzior
fbf001bbec lte: Relax condition to g_free imsi
imsi malloc is not directly tied to l_settings being valid
2017-11-08 18:20:47 +03:00
Dragos Tatulea
8e90e96509 build: add lte atom support
Conflicts:
	ofono/Makefile.am
2017-11-08 18:20:47 +03:00
Dragos Tatulea
80e9b97036 lte: add implementation for LTE atom
This implementation can only get/set the default APN setting. But
anything expected for this atom is there:
* D-Bus interface
* sync-ing settings to/from file
* interaction with driver

Conflicts:
	ofono/src/ofono.h
2017-11-08 18:20:47 +03:00
Dragos Tatulea
01103f32ae ubloxmodem: fix memory leak in gprs_context_remove 2017-11-08 18:20:47 +03:00
Denis Kenzior
4bef0c7b33 include: Fix return signature in lte methods
Only the probe method returns a value.  All other methods use a void
return signature and report errors via the callback.
2017-11-08 18:20:47 +03:00
Denis Kenzior
693d5a77bd build: add test/set-lte-property 2017-11-08 18:20:47 +03:00
Denis Kenzior
a2333ead45 build: Add lte-api.txt 2017-11-08 18:20:46 +03:00
Dragos Tatulea
aa6a436af5 doc: add lte atom documentation 2017-11-08 18:20:46 +03:00
Dragos Tatulea
ee350d6b4b test: add script for setting lte atom properties 2017-11-08 18:20:46 +03:00
Denis Kenzior
26b85c0606 include: Make lte method const correct 2017-11-08 18:20:46 +03:00
Dragos Tatulea
068190a7a5 include: add header file for lte atom 2017-11-08 18:20:46 +03:00
Dragos Tatulea
1b292f7cf2 include: add LTE dbus service define 2017-11-08 18:20:46 +03:00
Kuba Pawlak
cd9a19c090 bluez5: fix crash on DBus transport disconnection
Do not register dbus notification if message failed to be sent out
because transport was already disconnected
2017-11-08 18:20:46 +03:00
Kuba Pawlak
6d357e70a4 gatchat: Fix parsing fields with odd number of quotation marks
Events like +CLCC and +CCWA can have contact name attached to the
end of line. If this field contains odd number of quotation marks,
parser will eventually reject such message as malformatted.
2017-11-08 18:20:46 +03:00
Dragos Tatulea
8f4817106d src: add LTE atom define 2017-11-08 18:20:46 +03:00
Slava Monich
d2ce689008 [ofono] Moved ofono_gprs_get_roaming_allowed declaration from gprs.h to ofono.h
.. primarily to make gprs.h identical to upstream. Besides, it's an internal
function, it doesn't have to be defined in gprs.h and exported from ofono in
the first place.
2017-11-08 18:12:15 +03:00
Slava Monich
b470166c87 [ril] Fixed -Wsign-compare compilation warnings
Upstream doesn't have those, let's keep our code clean, too.
2017-11-03 12:12:37 +03:00
Slava Monich
158a0da0b2 sim: Move atom registration to the end of ofono_sim_register
The state needs to be checked prior to calling __ofono_atom_register
because atom registration calls OFONO_ATOM_WATCH_CONDITION_REGISTERED
callbacks each of which may call ofono_sim_inserted_notify. Should
that happen, by the time __ofono_atom_register returns, ofono_sim
will be in OFONO_SIM_STATE_INSERTED state and sim_initialize will
be called twice if the initial state was OFONO_SIM_STATE_NOT_PRESENT.
If nothing else, that results in memory leaks like this one (because
IMSI will be queried twice, among other things):

==3017== 16 bytes in 1 blocks are definitely lost in loss record 187 of 475
==3017==    at 0x483F380: malloc (vg_replace_malloc.c:296)
==3017==    by 0x4AFB0DF: g_malloc (gmem.c:94)
==3017==    by 0x4B12185: g_strdup (gstrfuncs.c:363)
==3017==    by 0xF79D3: sim_imsi_obtained (sim.c:1535)
==3017==    by 0xF7BB3: sim_imsi_cb (sim.c:1594)
==3017==    by 0x66C23: at_cimi_cb (sim.c:441)
==3017==    by 0xA6B53: at_chat_finish_command (gatchat.c:459)
==3017==    by 0xA6D9F: at_chat_handle_command_response (gatchat.c:521)
==3017==    by 0xA70AF: have_line (gatchat.c:600)
==3017==    by 0xA76DF: new_bytes (gatchat.c:759)
==3017==    by 0xABACF: received_data (gatio.c:122)
==3017==    by 0xAD093: watch_dispatch (gatmux.c:461)
==3017==    by 0xAC5D3: dispatch_sources (gatmux.c:180)
==3017==    by 0xAC98F: received_data (gatmux.c:265)
==3017==    by 0x4AF606F: g_main_dispatch (gmain.c:3154)
==3017==    by 0x4AF606F: g_main_context_dispatch (gmain.c:3769)
==3017==    by 0x4AF631D: g_main_context_iterate.isra.4 (gmain.c:3840)
==3017==    by 0x4AF658F: g_main_loop_run (gmain.c:4034)
==3017==    by 0xBE8AF: main (main.c:261)
2017-10-27 19:10:19 +03:00
Slava Monich
b4bbf0462c gatchat: Removed unused GAtPPP field 2017-10-27 01:09:42 +03:00
Slava Monich
d80b96790f atmodem: Query the list of supported <fac>s from the modem
Not all modems support all <fac>s (particularly, "PS"), let's be polite
and not ask them for the ones they don't support.
2017-10-24 02:07:17 +03:00
Slava Monich
accb571fd6 gatmux: Remove write watch source at shutdown
Otherwise write_watcher_destroy_notify can be invoked after
GAtMux has been deallocated which results in write after free:

==3952== Invalid write of size 4
==3952==    at 0xABF54: write_watcher_destroy_notify (gatmux.c:285)
==3952==    by 0x4AF21E7: g_source_callback_unref (gmain.c:1561)
==3952==    by 0x4AF2E53: g_source_destroy_internal.constprop.8 (gmain.c:1207)
==3952==    by 0x4AF61CF: g_main_dispatch (gmain.c:3177)
==3952==    by 0x4AF61CF: g_main_context_dispatch (gmain.c:3769)
==3952==    by 0x4AF658F: g_main_loop_run (gmain.c:4034)
==3952==    by 0xBDDBB: main (main.c:261)
==3952==  Address 0x50c6cb0 is 8 bytes inside a block of size 4,396 free'd
==3952==    at 0x4840B28: free (vg_replace_malloc.c:530)
==3952==    by 0xACB53: g_at_mux_unref (gatmux.c:642)
==3952==  Block was alloc'd at
==3952==    at 0x4841BF0: calloc (vg_replace_malloc.c:711)
==3952==    by 0xAC9DF: g_at_mux_new (gatmux.c:603)
==3952==    by 0xADF2F: g_at_mux_new_gsm0710_basic (gatmux.c:1160)
2017-10-24 02:07:16 +03:00
Slava Monich
523a4b6a81 gatmux: Remove finalized watches from the list
Leaving them there may result in invalid reads like this:

==2312== Invalid read of size 4
==2312==    at 0xAB8C0: dispatch_sources (gatmux.c:134)
==2312==    by 0xAC5D3: channel_close (gatmux.c:479)
==2312==    by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523)
==2312==    by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240)
==2312==    by 0xAC423: watch_finalize (gatmux.c:426)
==2312==    by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048)
==2312==    by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230)
==2312==    by 0x4AF44E1: g_source_destroy (gmain.c:1256)
==2312==    by 0x4AF5257: g_source_remove (gmain.c:2282)
==2312==    by 0xAB5CB: io_shutdown (gatio.c:325)
==2312==    by 0xAB667: g_at_io_unref (gatio.c:345)
==2312==    by 0xA72C7: at_chat_unref (gatchat.c:972)
==2312==    by 0xA829B: g_at_chat_unref (gatchat.c:1446)
==2312==  Address 0x51420f0 is 56 bytes inside a block of size 60 free'd
==2312==    at 0x4840B28: free (vg_replace_malloc.c:530)
==2312==    by 0x4AF2D33: g_source_unref_internal (gmain.c:2075)
==2312==    by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230)
==2312==    by 0x4AF44E1: g_source_destroy (gmain.c:1256)
==2312==    by 0x4AF5257: g_source_remove (gmain.c:2282)
==2312==    by 0xAB46B: g_at_io_set_write_handler (gatio.c:283)
==2312==    by 0xA713F: at_chat_suspend (gatchat.c:938)
==2312==    by 0xA72B7: at_chat_unref (gatchat.c:971)
==2312==    by 0xA829B: g_at_chat_unref (gatchat.c:1446)
==2312==  Block was alloc'd at
==2312==    at 0x4841BF0: calloc (vg_replace_malloc.c:711)
==2312==    by 0x4AFB117: g_malloc0 (gmem.c:124)
==2312==    by 0x4AF401F: g_source_new (gmain.c:892)
==2312==    by 0xAC6A7: channel_create_watch (gatmux.c:506)
==2312==    by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649)
==2312==    by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297)
==2312==    by 0xA7103: chat_wakeup_writer (gatchat.c:931)
==2312==    by 0xA753F: at_chat_send_common (gatchat.c:1045)
==2312==    by 0xA850F: g_at_chat_send (gatchat.c:1502)

It's also necessary to add additional references to the sources
for the duration of the dispatch_sources loop because any source
can be removed when any callback is invoked (and not necessarily
the one being dispatched).
2017-10-24 00:07:47 +03:00
Slava Monich
9d8a6a4978 Fixed -Wsign-compare warnings
unit/test-sailfish_sim_info.c:86:33: signed and unsigned type in conditional expression
drivers/ril/ril_netmon.c:46:12: comparison between signed and unsigned integer expressions
2017-10-23 23:56:29 +03:00
Slava Monich
f2fa85aa47 [ril] Housekeeping
Took out some leftovers of the past
2017-10-20 18:13:17 +03:00
Slava Monich
a189d13b4a Merge branch 'dbus-queue' into 'master'
Generic queueing of D-Bus requests

See merge request !151
2017-10-19 08:17:38 +00:00
Slava Monich
3b79a77d78 [ofono] radio-settings: Use ofono_dbus_queue for queuing D-Bus requests
Instead of failing with org.ofono.Error.InProgress, requests
are queued and handled in the order they are received.
2017-10-18 23:56:40 +03:00
Slava Monich
c2ee34e51c [ofono] network: Use ofono_dbus_queue for queuing D-Bus requests 2017-10-18 22:39:51 +03:00
Slava Monich
c3bead1c9b [ofono] Generic queueing of D-Bus requests
Instead of failing with org.ofono.Error.InProgress, requests may be queued.
2017-10-18 22:39:21 +03:00
Slava Monich
a26f1a4b5c [ril] Removed a few unused things 2017-10-18 12:43:31 +03:00
Slava Monich
1eacfdf592 [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:28:42 +03:00
Slava Monich
ba14ed43e4 Merge branch 'perm' into 'master'
Fix storage directory permissions at startup

See merge request !150
2017-10-13 14:33:21 +00:00
Slava Monich
802b3008be [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 17:16:24 +03:00
Slava Monich
3b0191d145 [test] Added test-ril_util 2017-10-13 17:07:26 +03:00
Slava Monich
282d32f70d [ril] Added ril_parse_int utility 2017-10-13 17:05:43 +03:00
Slava Monich
e0c349a18c Merge branch 'smsfilter' into 'master'
SMS filter plugin

See merge request !138
2017-10-10 13:00:08 +00:00
Slava Monich
69d65dc002 [ofono] Support for SMS filter plugins. JB#37478 2017-10-10 15:49:28 +03:00
Slava Monich
33e70ddce4 [ofono] Allow older versions of plugins.
Let's assume that plugin API is going to be backward compatible. If
we start to actually use binary ofono plugins (possibly, 3rd-party),
backward compatibility becomes a must.
2017-10-10 15:49:28 +03:00
Slava Monich
d3ada8fcb3 [ofono] Fixed setting/clearing debug flags for binary plugins
They were added to the list of debug categories but their flags
were not actually getting updated on client's requests.
2017-10-10 15:48:59 +03:00
Slava Monich
4c21ca4e26 atmodem: Fix use after free in sim_state_cb
==2941== Invalid read of size 4
==2941==    at 0x69338: sim_state_cb (sim.c:1301)
==2941==    by 0x71DCB: cpin_check_cb (atutil.c:567)
==2941==    by 0xA602B: at_chat_finish_command (gatchat.c:459)
==2941==    by 0xA6277: at_chat_handle_command_response (gatchat.c:521)
==2941==    by 0xA6587: have_line (gatchat.c:600)
==2941==    by 0xA6BB7: new_bytes (gatchat.c:759)
==2941==    by 0xAAFAF: received_data (gatio.c:124)
==2941==    by 0x4AF606F: g_main_dispatch (gmain.c:3154)
==2941==    by 0x4AF606F: g_main_context_dispatch (gmain.c:3769)
==2941==    by 0x4AF658F: g_main_loop_run (gmain.c:4034)
==2941==    by 0xBDDBB: main (main.c:261)
==2941==  Address 0x519c344 is 4 bytes inside a block of size 12 free'd
==2941==    at 0x4840B28: free (vg_replace_malloc.c:530)
==2941==    by 0x71F33: at_util_sim_state_query_free (atutil.c:613)
==2941==    by 0x6930B: sim_state_cb (sim.c:1297)
==2941==    by 0x71DCB: cpin_check_cb (atutil.c:567)
==2941==    by 0xA602B: at_chat_finish_command (gatchat.c:459)
==2941==    by 0xA6277: at_chat_handle_command_response (gatchat.c:521)
==2941==    by 0xA6587: have_line (gatchat.c:600)
==2941==    by 0xA6BB7: new_bytes (gatchat.c:759)
==2941==    by 0xAAFAF: received_data (gatio.c:124)
==2941==    by 0x4AF606F: g_main_dispatch (gmain.c:3154)
==2941==    by 0x4AF606F: g_main_context_dispatch (gmain.c:3769)
==2941==    by 0x4AF658F: g_main_loop_run (gmain.c:4034)
==2941==    by 0xBDDBB: main (main.c:261)
2017-10-05 19:46:32 +03:00
Slava Monich
a3301ec1d2 modem: Implement ofono_modem_get_sim 2017-10-05 19:46:31 +03:00
Slava Monich
6f11bfc632 include: Add ofono_modem_get_sim 2017-10-05 19:46:31 +03:00
Slava Monich
74262b9ef8 [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-02 17:31:47 +03:00
Slava Monich
199a610607 [ril] Fixed erroneous assert 2017-10-02 16:34:33 +03:00
Slava Monich
af2d223f0f [ofono] Moved gutil_log_func initialization from ril_plugin_init()
.. to debuglog_init(). There's no reason for it to be in RIL specific code.
2017-10-02 13:31:26 +03:00
Slava Monich
0b6fcf8b71 [mbpi] Use PROVIDER_DATABASE from config.h as the default
It's pulled from mobile-broadband-provider-info.pc by the
configure script, we should trust it.
2017-10-02 12:48:23 +03:00
Slava Monich
cc05aeccd1 Merge branch 'debug' into 'master'
Fix logging issues with external plugins

See merge request !149
2017-10-01 22:14:36 +00:00
Slava Monich
5728444ad3 [iofono] Allow to manage logs of binary plugins
External (binary) plugins have __debug section of their own.
2017-09-30 00:28:54 +03:00
Slava Monich
4cbb6b5919 [ofono] Added __ofono_plugin_foreach()
Invokes a callback for each registered plugin. It's needed by debuglog
plugin because external plugins have __debug section of their own and
debuglog needs access to debug_start and debug_stop of such plugins
in order to enable or disable plugin logs.
2017-09-29 21:27:35 +03:00
Slava Monich
5699bb4932 [build] Fixed configure check for libmce-glib
Version 1.0.5 is required for mce_display_remove_all_handlers macro
2017-09-29 13:06:34 +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
267 changed files with 40481 additions and 8539 deletions

61
.gitignore vendored
View File

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

View File

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

36
ofono/.gitignore vendored
View File

@@ -32,6 +32,8 @@ src/ofono.service
dundee/dundee
dundee/dundee.service
test-driver
test-suite.log
unit/test-common
unit/test-util
unit/test-idmap
@@ -42,13 +44,47 @@ unit/test-mux
unit/test-caif
unit/test-stkutil
unit/test-cdmasms
unit/test-dbus-access
unit/test-dbus-queue
unit/test-gprs-filter
unit/test-ril_config
unit/test-ril_util
unit/test-ril_vendor
unit/test-ril-transport
unit/test-rilmodem-cb
unit/test-rilmodem-cs
unit/test-rilmodem-gprs
unit/test-rilmodem-sms
unit/test-sailfish_access
unit/test-sailfish_cell_info
unit/test-sailfish_cell_info_dbus
unit/test-sailfish_manager
unit/test-sailfish_sim_info
unit/test-sailfish_sim_info_dbus
unit/test-watch
unit/test-sms-filter
unit/test-voicecall-filter
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
plugins/*/*.gcda
plugins/*/*.gcno
plugins/*/*.gcov
*/*.gcda
*/*.gcno
*/*.gcov
tools/huawei-audio
tools/auto-enable
tools/get-location

View File

@@ -116,3 +116,13 @@ Martin Chaplet <m.chaplet@kerlink.fr>
Suman Mallela <suman.m@intel.com>
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
Antoine Aubert <a.aubert@overkiz.com>
Djalal Harouni <djalal@endocode.com>
Christophe Ronco <c.ronco@kerlink.fr>
Vincent Cesson <vincent.cesson@smile.fr>
Piotr Haber <gluedig@gmail.com>
André Draszik <git@andred.net>
Lukasz Nowak <lnowak@tycoint.com>
Jonas Bonn <jonas@southpole.se>
Matthijs Kooijman <matthijs@stdin.nl>
Clayton Craft <clayton@craftyguy.net>
Joey Hewitt <joey@joeyhewitt.com>

View File

@@ -1,3 +1,36 @@
ver 1.21:
Fix issue with USSD notification received handling.
Fix issue with crashing SIM filesystem notifications.
Fix issue with LTE bearer reporting and Huawei modems.
Fix issue with invalid memory access and QMI.
Add support for QMI SIM writing functionality.
Add support for RAT selection for QMI modems.
Add support for network monitor agent interface.
Add support for Cinterion Hardware Monitor interface.
Add support for LTE atom driver for Huawei modems.
Add support for LTE atom driver for AT modems.
Add support for Intel xmm7xxx series modems.
ver 1.20:
Fix issue with context removal before activation.
Fix issue with update during GPRS context activation.
Fix issue with receiving UTF-16 encoded messages.
Fix issue with invalid access in CBS decoding.
Fix issue with signal strength on QMI modems.
Fix issue with PIN handling with QMI modems.
Fix issue with QMI notification message handling.
Fix issue with facility lock query on SIM removal.
Fix issue with parsing +CLCC and +CCWA fields.
Add support for obtaining IMSI via EF reading.
Add support for additional netmon info types.
Add support for provisioning via configuration files.
Add support for Gemalto P-family series of modems.
Add support for Telit HE910 and UE910 variants.
Add support for Intel SoFIA SIM Toolkit interfaces.
Add support for Intel SoFIA LTE features.
Add support for U-Blox TOBY-L2 LTE feature.
Add support for dedicated LTE atom.
ver 1.19:
Fix issue with DHCP parsing and Huawei modems.
Fix issue with detecting Huawei E3372 modem.

View File

@@ -23,10 +23,20 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
include/cdma-provision.h include/handsfree.h \
include/sim-mnclength.h \
include/handsfree-audio.h include/siri.h \
include/netmon.h
include/sms-filter.h include/gprs-filter.h \
include/voicecall-filter.h include/dbus-access.h \
include/ril-constants.h include/ril-transport.h \
include/netmon.h include/lte.h \
include/storage.h include/watch.h \
gdbus/gdbus.h
nodist_pkginclude_HEADERS = include/version.h
if SAILFISH_MANAGER
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
include/sailfish_manager.h
endif
local_headers = $(foreach file,$(pkginclude_HEADERS) \
$(nodist_pkginclude_HEADERS), \
include/ofono/$(notdir $(file)))
@@ -107,8 +117,6 @@ gril_sources = gril/gril.h gril/gril.c \
btio_sources = btio/btio.h btio/btio.c
if UDEV
builtin_modules += udev
builtin_sources += plugins/udev.c
builtin_cflags += @UDEV_CFLAGS@
builtin_libadd += @UDEV_LIBS@
@@ -116,8 +124,24 @@ 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
endif
if SAILFISH_ACCESS
builtin_modules += sailfish_access
builtin_sources += plugins/sailfish_access.c
endif
if RILMODEM
if JOLLA_RILMODEM
if SAILFISH_RILMODEM
builtin_modules += ril
builtin_sources += drivers/ril/ril_call_barring.c \
@@ -125,7 +149,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,27 +157,28 @@ 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 \
drivers/ril/ril_ussd.c \
drivers/ril/ril_util.c \
drivers/ril/ril_vendor.c \
drivers/ril/ril_voicecall.c
# Vendor specific extensions
builtin_sources += drivers/ril/ril_vendor_mtk.c
if DATAFILES
dist_conf_DATA += drivers/ril/ril_subscription.conf
endif
@@ -172,8 +196,8 @@ builtin_sources += plugins/ril.c plugins/ril.h
builtin_modules += infineon
builtin_sources += plugins/infineon.c
builtin_modules += ril_sofia3gr
builtin_sources += plugins/ril_sofia3gr.c
builtin_modules += ril_intel
builtin_sources += plugins/ril_intel.c
builtin_modules += rilmodem
builtin_sources += drivers/rilmodem/rilmodem.h \
@@ -198,7 +222,8 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
drivers/rilmodem/netmon.c \
drivers/rilmodem/stk.c \
drivers/rilmodem/cbs.c \
drivers/infineonmodem/infineon_constants.h
drivers/infineonmodem/infineon_constants.h \
drivers/rilmodem/lte.c
endif
endif
@@ -257,11 +282,13 @@ qmi_sources = drivers/qmimodem/qmi.h drivers/qmimodem/qmi.c \
drivers/qmimodem/ctl.h \
drivers/qmimodem/dms.h \
drivers/qmimodem/nas.h \
drivers/qmimodem/nas.c \
drivers/qmimodem/uim.h \
drivers/qmimodem/wms.h \
drivers/qmimodem/wds.h \
drivers/qmimodem/pds.h \
drivers/qmimodem/common.h
drivers/qmimodem/common.h \
drivers/qmimodem/wda.h
builtin_modules += qmimodem
builtin_sources += $(qmi_sources) \
@@ -278,7 +305,8 @@ builtin_sources += $(qmi_sources) \
drivers/qmimodem/gprs.c \
drivers/qmimodem/gprs-context.c \
drivers/qmimodem/radio-settings.c \
drivers/qmimodem/location-reporting.c
drivers/qmimodem/location-reporting.c \
drivers/qmimodem/netmon.c
builtin_modules += gobi
builtin_sources += plugins/gobi.c
@@ -309,7 +337,8 @@ builtin_sources += drivers/atmodem/atmodem.h \
drivers/atmodem/gprs.c \
drivers/atmodem/gprs-context.c \
drivers/atmodem/sim-auth.c \
drivers/atmodem/gnss.c
drivers/atmodem/gnss.c \
drivers/atmodem/lte.c
builtin_modules += nwmodem
builtin_sources += drivers/atmodem/atutil.h \
@@ -366,7 +395,8 @@ builtin_modules += telitmodem
builtin_sources += drivers/atmodem/atutil.h \
drivers/telitmodem/telitmodem.h \
drivers/telitmodem/telitmodem.c \
drivers/telitmodem/location-reporting.c
drivers/telitmodem/location-reporting.c \
drivers/telitmodem/gprs-context-ncm.c
builtin_modules += hsomodem
builtin_sources += drivers/atmodem/atutil.h \
@@ -428,9 +458,23 @@ builtin_modules += ubloxmodem
builtin_sources += drivers/atmodem/atutil.h \
drivers/ubloxmodem/ubloxmodem.h \
drivers/ubloxmodem/ubloxmodem.c \
drivers/ubloxmodem/gprs-context.c
drivers/ubloxmodem/gprs-context.c \
drivers/ubloxmodem/netmon.c \
drivers/ubloxmodem/lte.c
builtin_modules += gemaltomodem
builtin_sources += drivers/atmodem/atutil.h \
drivers/gemaltomodem/gemaltomodem.h \
drivers/gemaltomodem/gemaltomodem.c \
drivers/gemaltomodem/location-reporting.c
builtin_modules += xmm7modem
builtin_sources += drivers/atmodem/atutil.h \
drivers/xmm7modem/xmm7modem.h \
drivers/xmm7modem/xmm7modem.c \
drivers/xmm7modem/radio-settings.c
if PHONESIM
builtin_modules += phonesim
builtin_sources += plugins/phonesim.c
@@ -495,6 +539,9 @@ builtin_sources += plugins/caif.c
builtin_modules += cinterion
builtin_sources += plugins/cinterion.c
builtin_modules += gemalto
builtin_sources += plugins/gemalto.c
builtin_modules += nokia
builtin_sources += plugins/nokia.c
@@ -522,24 +569,30 @@ builtin_sources += plugins/samsung.c
builtin_modules += sim900
builtin_sources += plugins/sim900.c
builtin_modules += connman
builtin_sources += plugins/connman.c
builtin_modules += telit
builtin_sources += plugins/telit.c
builtin_modules += quectel
builtin_sources += plugins/quectel.c
builtin_modules += ublox
builtin_sources += plugins/ublox.c
builtin_modules += he910
builtin_sources += plugins/he910.c
builtin_modules += xmm7xxx
builtin_sources += plugins/xmm7xxx.c
endif
builtin_modules += connman
builtin_sources += plugins/connman.c
builtin_modules += mnclength
builtin_sources += plugins/mnclength.c
if BLUETOOTH
if BLUEZ4
builtin_modules += telit
builtin_sources += plugins/telit.c plugins/bluez4.h
builtin_modules += sap
builtin_sources += plugins/sap.c plugins/bluez4.h
@@ -576,9 +629,9 @@ builtin_sources += plugins/bluez5.c plugins/bluez5.h
builtin_modules += hfp_ag_bluez5
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
if SAILFISHFOS
if SAILFISH_BT
builtin_modules += sfos_bt
builtin_sources += plugins/sfos_bt.c
builtin_sources += plugins/sailfish_bt.c
endif
endif
@@ -593,17 +646,32 @@ 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
builtin_modules += mnclength
builtin_sources += plugins/mnclength.c
builtin_modules += file_provision
builtin_sources += plugins/file-provision.c
endif
if MAINTAINER_MODE
@@ -635,16 +703,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
@@ -656,6 +717,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 \
@@ -681,8 +743,12 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/cdma-provision.c src/handsfree.c \
src/handsfree-audio.c src/bluetooth.h \
src/sim-mnclength.c src/voicecallagent.c \
src/hfp.h src/siri.c \
src/netmon.c
src/sms-filter.c src/gprs-filter.c \
src/dbus-queue.c src/dbus-access.c \
src/voicecall-filter.c src/ril-transport.c \
src/hfp.h src/siri.c src/watchlist.c \
src/netmon.c src/lte.c \
src/netmonagent.c src/netmonagent.h
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
@@ -692,7 +758,8 @@ src_ofonod_LDFLAGS = -Wl,--export-dynamic \
BUILT_SOURCES = $(local_headers) src/builtin.h
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA)
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA) \
$(shell find . -name "*.gcda") $(shell find . -name "*.gcno")
plugindir = $(pkglibdir)/plugins
@@ -730,7 +797,9 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
doc/certification.txt doc/siri-api.txt \
doc/telit-modem.txt \
doc/networkmonitor-api.txt \
doc/allowed-apns-api.txt
doc/allowed-apns-api.txt \
doc/lte-api.txt \
doc/cinterion-hardware-monitor-api.txt
test_scripts = test/backtrace \
@@ -837,7 +906,10 @@ test_scripts = test/backtrace \
test/get-serving-cell-info \
test/list-allowed-access-points \
test/enable-throttling \
test/disable-throttling
test/disable-throttling \
test/set-lte-property \
test/test-serving-cell-info
if TEST
testdir = $(pkglibdir)/test
@@ -849,17 +921,126 @@ 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 =
unit_tests = unit/test-common unit/test-util unit/test-idmap \
unit/test-simutil unit/test-stkutil \
unit/test-sms unit/test-cdmasms \
unit/test-provision
unit/test-sms unit/test-cdmasms
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_manager
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_cell_info_dbus_SOURCES = unit/test-dbus.c \
unit/test-sailfish_cell_info_dbus.c \
unit/fake_sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
gdbus/object.c \
src/dbus.c src/log.c
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
@DBUS_GLIB_CFLAGS@ -Iplugins/sailfish_manager
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
unit_tests += unit/test-sailfish_cell_info_dbus
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
unit/fake_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
src/storage.c src/watchlist.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_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
unit/test-dbus.c unit/fake_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
gdbus/object.c \
src/dbus.c src/storage.c src/watchlist.c src/log.c
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"' \
-Iplugins/sailfish_manager
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
unit_tests += unit/test-sailfish_sim_info_dbus
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
unit/fake_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
unit_test_watch_SOURCES = unit/test-watch.c src/watch.c \
src/log.c src/watchlist.c
unit_test_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
unit_test_watch_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_watch_OBJECTS)
unit_tests += unit/test-watch
endif
if SAILFISH_ACCESS
unit_test_sailfish_access_SOURCES = unit/test-sailfish_access.c \
plugins/sailfish_access.c src/dbus-access.c src/log.c
unit_test_sailfish_access_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
unit_test_sailfish_access_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_access_OBJECTS)
unit_tests += unit/test-sailfish_access
endif
unit_test_dbus_access_SOURCES = unit/test-dbus-access.c src/dbus-access.c \
src/log.c
unit_test_dbus_access_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
unit_test_dbus_access_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_dbus_access_OBJECTS)
unit_tests += unit/test-dbus-access
if RILMODEM
if JOLLA_RILMODEM
if SAILFISH_RILMODEM
unit_test_ril_config_SOURCES = unit/test-ril_config.c drivers/ril/ril_util.c \
drivers/ril/ril_config.c src/log.c
unit_test_ril_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_config_OBJECTS)
unit_tests += unit/test-ril_config
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
src/log.c
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_util_OBJECTS)
unit_tests += unit/test-ril_util
unit_test_ril_vendor_SOURCES = unit/test-ril_vendor.c unit/fake_watch.c \
drivers/ril/ril_vendor.c drivers/ril/ril_vendor_mtk.c \
drivers/ril/ril_util.c src/log.c
unit_test_ril_vendor_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_vendor_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_vendor_OBJECTS)
unit_tests += unit/test-ril_vendor
else
unit_tests += unit/test-rilmodem-cs \
unit/test-rilmodem-cs \
unit/test-rilmodem-sms \
@@ -873,19 +1054,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)
@@ -893,19 +1078,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)
@@ -916,15 +1105,55 @@ 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_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
src/dbus-queue.c gdbus/object.c \
src/dbus.c src/log.c
unit_test_dbus_queue_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_dbus_queue_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_dbus_queue_OBJECTS)
unit_tests += unit/test-dbus-queue
unit_test_provision_SOURCES = unit/test-provision.c \
plugins/provision.h plugins/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)
unit_tests += unit/test-provision
unit_test_ril_transport_SOURCES = unit/test-ril-transport.c \
src/ril-transport.c src/log.c
unit_test_ril_transport_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_transport_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_transport_OBJECTS)
unit_tests += unit/test-ril-transport
unit_test_sms_filter_SOURCES = unit/test-sms-filter.c \
src/sms-filter.c src/log.c
unit_test_sms_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_sms_filter_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sms_filter_OBJECTS)
unit_tests += unit/test-sms-filter
unit_test_gprs_filter_SOURCES = unit/test-gprs-filter.c \
src/gprs-filter.c src/log.c
unit_test_gprs_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_gprs_filter_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_gprs_filter_OBJECTS)
unit_tests += unit/test-gprs-filter
unit_test_voicecall_filter_SOURCES = unit/test-voicecall-filter.c \
src/voicecall-filter.c src/log.c \
src/common.c src/util.c
unit_test_voicecall_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_voicecall_filter_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_voicecall_filter_OBJECTS)
unit_tests += unit/test-voicecall-filter
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
gatchat/ringbuffer.h gatchat/ringbuffer.c \
@@ -989,13 +1218,6 @@ tools_lookup_provider_name_LDADD = @GLIB_LIBS@
tools_tty_redirector_SOURCES = tools/tty-redirector.c
tools_tty_redirector_LDADD = @GLIB_LIBS@
if QMIMODEM
noinst_PROGRAMS += tools/qmi
tools_qmi_SOURCES = $(qmi_sources) tools/qmi.c
tools_qmi_LDADD = @GLIB_LIBS@
endif
if MAINTAINER_MODE
noinst_PROGRAMS += tools/stktest
@@ -1064,6 +1286,10 @@ include/ofono/version.h: include/version.h
$(AM_V_at)$(MKDIR_P) include/ofono
$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
include/ofono/gdbus.h: $(abs_top_srcdir)/gdbus/gdbus.h
$(AM_V_at)$(MKDIR_P) include/ofono
$(AM_V_GEN)$(LN_S) $< $@
include/ofono/%.h: $(abs_top_srcdir)/include/%.h
$(AM_V_at)$(MKDIR_P) include/ofono
$(AM_V_GEN)$(LN_S) $< $@

View File

@@ -22,6 +22,7 @@ AC_DEFUN([COMPILER_FLAGS], [
CFLAGS="$CFLAGS -Wmissing-declarations"
CFLAGS="$CFLAGS -Wredundant-decls"
CFLAGS="$CFLAGS -Wcast-align"
CFLAGS="$CFLAGS -Wno-format-truncation"
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
fi
])

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(ofono, 1.19)
AC_INIT(ofono, 1.21)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)
@@ -33,7 +33,7 @@ AC_PROG_LIBTOOL
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
[disable code optimization through compiler]), [
if (test "${enableval}" = "no"); then
CFLAGS="$CFLAGS -O0"
CFLAGS="$CFLAGS -O0 -U_FORTIFY_SOURCE"
fi
])
@@ -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,20 +177,36 @@ 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))
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"
if (test "${enable_sailfish_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.25, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.25 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.30, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.30 is required))
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
AC_MSG_ERROR(libmce-glib >= 1.0.5 is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
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")
if (test "${enable_sailfish_manager}" = "yes"); then
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
AC_MSG_ERROR(dbus-glib is required by unit tests))
AC_SUBST(DBUS_GLIB_CFLAGS)
AC_SUBST(DBUS_GLIB_LIBS)
fi
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
@@ -190,6 +216,12 @@ AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-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}])
@@ -213,9 +245,15 @@ fi
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
AC_ARG_ENABLE(sailfishos, AC_HELP_STRING([--enable-sailfishos],
[enable sailfishos plugin]), [enable_sailfishos=${enableval}])
AM_CONDITIONAL(SAILFISHFOS, test "${enable_sailfishos}" = "yes")
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]),
@@ -259,28 +297,51 @@ 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-access, AC_HELP_STRING([--enable-sailfish-access],
[enable Sailfish OS access plugin]),
[enable_sailfish_access=${enableval}],
[enable_sailfish_access="no"])
AM_CONDITIONAL(SAILFISH_ACCESS, test "${enable_sailfish_access}" != "no")
if (test "${enable_sailfish_access}" == "yes"); then
PKG_CHECK_MODULES(DBUSACCESS, libdbusaccess, dummy=yes,
AC_MSG_ERROR(libdbusaccess is required))
CFLAGS="$CFLAGS $DBUSACCESS_CFLAGS"
LIBS="$LIBS $DBUSACCESS_LIBS"
fi
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
@@ -295,7 +356,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

@@ -0,0 +1,16 @@
HardwareMonitor hierarchy
=========================
Service org.ofono
Interface org.ofono.cinterion.HardwareMonitor
Object path /{device0,device1,...}
Methods array{string,variant} GetStatistics
Returns an array of dict entries representing the
current temperature and supply voltage of the modem.
Units:
Temperature: Celsius
Voltage: mV

View File

@@ -19,7 +19,7 @@ Besides the kernel coding style above, oFono has special flavors for its own.
Some of them are mandatory (marked as 'M'), while some others are optional
(marked as 'O'), but generally preferred.
M1: Blank line before and after an if/while/do/for statement
M1: Blank line before and after an if/while/do/for/switch statement
============================================================
There should be a blank line before if statement unless the if is nested and
not preceded by an expression or variable declaration.

View File

@@ -76,6 +76,22 @@ Methods dict GetProperties()
[service].Error.NotImplemented
[service].Error.NotAllowed
fd, byte Acquire()
Attempts to establish the SCO audio connection
returning the filedescriptor of the connection and the
codec in use.
Note: Contrary to Connect this does not call
NewConnection so it can be called in a blocking
manner.
Possible Errors: [service].Error.InProgress
[service].Error.Failed
[service].Error.NotAvailable
[service].Error.NotImplemented
[service].Error.NotAllowed
Signals PropertyChanged(string name, variant value)
This signal indicates a changed value of the given

35
ofono/doc/lte-api.txt Normal file
View File

@@ -0,0 +1,35 @@
LongTermEvolution Hierarchy
Service org.ofono
Interface org.ofono.LongTermEvolution
Object path [variable prefix]/{modem0,modem1,...}
Methods dict GetProperties()
Returns all LongTermEvolution configuration properties.
void SetProperty(string property, variant value)
Changes the value of the specified property. Only
properties that are listed as readwrite are
changeable. On success a PropertyChanged signal
will be emitted.
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.Failed
Signals PropertyChanged(string property, variant value)
This signal indicates a changed value of the given
property.
Properties string DefaultAccessPointName [readwrite]
On LongTermEvolution, contexts activate automatically.
This property allows selection of an APN to be used on
next automatic activation.
Setting this property to an empty string clears the
default APN from the modem.

View File

@@ -22,6 +22,34 @@ Methods a{sv} GetServingCellInformation()
are available, their valid value ranges and
applicability to different cell types.
void RegisterAgent(object path)
Registers an agent which will be called whenever the
modem registers to or moves to a new cell.
void UnregisterAgent(object path)
Unregisters an agent.
NetworkMonitorAgent Hierarchy [experimental]
=============================
Service unique name
Interface org.ofono.NetworkMonitorAgent
Object path freely definable
Methods void ServingCellInformationChanged(a{sv}) [noreply]
This method is called whenever the serving cell
information has been updated.
Possible Errors: None
void Release() [noreply]
Agent is being released, possibly because of oFono
terminating, NetworkMonitor interface is being torn
down or modem off. No UnregisterAgent call is needed.
Network Monitor Property Types
==============================
@@ -77,7 +105,46 @@ byte TimingAdvance [optional, gsm]
Contains the Timing Advance. Valid range of values is 0-219.
byte Strength [optional, gsm, umts]
byte Strength [optional, gsm, umts, lte]
Contains the signal strength. Valid values are 0-31. Refer to <rssi>
in 27.007, Section 8.5.
byte ReceivedSignalCodePower [optional, umts]
Contains the Received Signal Code Power. Valid range of values
is 0-96. Refer to <rscp> in 27.007, Section 8.69 for more details.
byte ReceivedEnergyRatio [optional, umts]
Contains the Ratio of received energy per PN chip to the total
received power spectral density. Valid range of values is 0-49.
Refer to <ecno> in 27.007, Section 8.69 for more details.
byte ReferenceSignalReceivedQuality [optional, lte]
Contains the Reference Signal Received Quality. Valid range of
values is 0-34. Refer to <rsrq> in 27.007, Section 8.69 for more
details.
byte ReferenceSignalReceivedPower [optional, lte]
Contains the Reference Signal Received Power. Valid range of values
is 0-97. Refer to <rsrp> in 27.007, Section 8.69 for more details.
uint16 EARFCN [optional, lte]
Contains E-UTRA Absolute Radio Frequency Channel Number. Valid
range of values is 0-65535. Refer to Carrier frequency and
EARFCN in 36.101, Section 5.7.3 for more details.
byte EBand [optional, lte]
Contains E-UTRA operating Band. Valid range of values is 1-43.
Refer to Operating bands in 36.101, Section 5.5 for more
details.
byte ChannelQualityIndicator [optional, lte]
Contains Channel Quality Indicator. Refer to Channel Quality
Indicator definition in 36.213, Section 7.2.3 for more details.

View File

@@ -17,3 +17,30 @@ GPS:
After setting the configuration, a power cycle is required.
Port Configiuration #8 is available since firmware 12.00.004. Firmware version
can be checked using 'AT+CGMR'.
LE910 V2
========
Default USB composition of LE910V2 uses PID 0x36 (AT#PORTCFG=0)
and consists of 6 serial ports (CDC-ACM standard, /dev/ttyACMx)
and 1 network adapter using CDC-NCM standard (wwanx or usbx).
NCM interface configuration follows Telit documentation
(both documents available on Telit Download Zone - registration required)
"GE/HE/UE910, UL865, LE910 V2 Linux USB Driver - User Guide r0"
(document 1VV0301255 Rev.0 - 2016-01-22)
and "Telit LE910-V2 NCM SETUP r3"
(document 1VV0301246 Rev.3 - 2016-11-29).
After context is setup, NCM mode activated and PDP context activated
connection configuration can be read using
AT+CGPADDR=context_id and AT+CGCONTRDP=context_id commands.
This is done automatically and results available via
org.ofono.ConnectionContext.GetProperties DBus method.
Then Linux network interface needs to be configured:
ifconfig <Interface> <Address> netmask <Netmask> up
route add default gw <Gateway>
arp -s <Gateway> 11:22:33:44:55:66
Only after these steps network interface is usable.

View File

@@ -52,6 +52,7 @@ static int atmodem_init(void)
at_gprs_context_init();
at_sim_auth_init();
at_gnss_init();
at_lte_init();
return 0;
}
@@ -76,6 +77,7 @@ static void atmodem_exit(void)
at_gprs_exit();
at_gprs_context_exit();
at_gnss_exit();
at_lte_exit();
}
OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION,

View File

@@ -74,3 +74,6 @@ extern void at_sim_auth_exit(void);
extern void at_gnss_init(void);
extern void at_gnss_exit(void);
extern void at_lte_init(void);
extern void at_lte_exit(void);

View File

@@ -27,6 +27,7 @@
#include <gatchat.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/log.h>
@@ -614,3 +615,42 @@ void at_util_sim_state_query_free(struct at_util_sim_state_query *req)
g_free(req);
}
/*
* CGCONTRDP returns addr + netmask in the same string in the form
* of "a.b.c.d.m.m.m.m" for IPv4.
* address/netmask must be able to hold
* 255.255.255.255 + null = 16 characters
*/
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
char *address, char *netmask)
{
const char *s = addrnetmask;
const char *net = NULL;
int ret = -EINVAL;
int i;
/* Count 7 dots for ipv4, less or more means error. */
for (i = 0; i < 9; i++, s++) {
s = strchr(s, '.');
if (!s)
break;
if (i == 3) {
/* set netmask ptr and break the string */
net = s + 1;
}
}
if (i == 7) {
memcpy(address, addrnetmask, net - addrnetmask);
address[net - addrnetmask - 1] = '\0';
strcpy(netmask, net);
ret = 0;
}
return ret;
}

View File

@@ -83,6 +83,9 @@ struct at_util_sim_state_query *at_util_sim_state_query_new(GAtChat *chat,
GDestroyNotify destroy);
void at_util_sim_state_query_free(struct at_util_sim_state_query *req);
int at_util_get_ipv4_address_and_netmask(const char *addrnetmask,
char *address, char *netmask);
struct cb_data {
void *cb;
void *data;

View File

@@ -43,10 +43,11 @@
#include "atmodem.h"
#include "vendor.h"
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
#define TUN_DEV "/dev/net/tun"
#define STATIC_IP_NETMASK "255.255.255.255"
static const char *cgdata_prefix[] = { "+CGDATA:", NULL };
static const char *none_prefix[] = { NULL };
enum state {
@@ -67,6 +68,7 @@ struct gprs_context_data {
ofono_gprs_context_cb_t cb;
void *cb_data; /* Callback data */
unsigned int vendor;
gboolean use_atd99;
};
static void ppp_debug(const char *str, void *data)
@@ -210,7 +212,7 @@ static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
return;
}
if (gcd->vendor == OFONO_VENDOR_SIMCOM_SIM900)
if (gcd->use_atd99)
sprintf(buf, "ATD*99***%u#", gcd->active_context);
else
sprintf(buf, "AT+CGDATA=\"PPP\",%u", gcd->active_context);
@@ -247,6 +249,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 +298,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);
@@ -378,6 +384,43 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
g_at_ppp_shutdown(gcd->ppp);
}
static void at_cgdata_test_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct ofono_gprs_context *gc = user_data;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
GAtResultIter iter;
const char *data_type;
gboolean found = FALSE;
gcd->use_atd99 = TRUE;
if (!ok) {
DBG("not ok");
goto error;
}
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CGDATA:")) {
DBG("no +CGDATA line");
goto error;
}
if (!g_at_result_iter_open_list(&iter)) {
DBG("no list found");
goto error;
}
while (!found && g_at_result_iter_next_string(&iter, &data_type)) {
if (g_str_equal(data_type, "PPP")) {
found = TRUE;
gcd->use_atd99 = FALSE;
}
}
error:
DBG("use_atd99:%d", gcd->use_atd99);
}
static int at_gprs_context_probe(struct ofono_gprs_context *gc,
unsigned int vendor, void *data)
{
@@ -387,7 +430,7 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
DBG("");
if (stat(TUN_SYSFS_DIR, &st) < 0) {
if (stat(TUN_DEV, &st) < 0) {
ofono_error("Missing support for TUN/TAP devices");
return -ENODEV;
}
@@ -405,6 +448,15 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
if (chat == NULL)
return 0;
switch (vendor) {
case OFONO_VENDOR_SIMCOM_SIM900:
gcd->use_atd99 = FALSE;
break;
default:
g_at_chat_send(chat, "AT+CGDATA=?", cgdata_prefix,
at_cgdata_test_cb, gc, NULL);
}
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
return 0;

View File

@@ -50,6 +50,8 @@ struct gprs_data {
GAtChat *chat;
unsigned int vendor;
unsigned int last_auto_context_id;
gboolean telit_try_reattach;
int attached;
};
static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
@@ -73,8 +75,10 @@ static void at_gprs_set_attached(struct ofono_gprs *gprs, int attached,
snprintf(buf, sizeof(buf), "AT+CGATT=%i", attached ? 1 : 0);
if (g_at_chat_send(gd->chat, buf, none_prefix,
at_cgatt_cb, cbd, g_free) > 0)
at_cgatt_cb, cbd, g_free) > 0) {
gd->attached = attached;
return;
}
g_free(cbd);
@@ -194,6 +198,28 @@ static void cgreg_notify(GAtResult *result, gpointer user_data)
NULL, NULL, NULL, gd->vendor) == FALSE)
return;
/*
* Telit AT modem firmware (tested with UE910-EUR) generates
* +CGREG: 0\r\n\r\n+CGEV: NW DETACH
* after a context is de-activated and ppp connection closed.
* Then, after a random amount of time (observed from a few seconds
* to a few hours), an unsolicited +CGREG: 1 arrives.
* Attempt to fix the problem, by sending AT+CGATT=1 once.
* This does not re-activate the context, but if a network connection
* is still correct, will generate an immediate +CGREG: 1.
*/
if (gd->vendor == OFONO_VENDOR_TELIT) {
if (gd->attached && !status && !gd->telit_try_reattach) {
DBG("Trying to re-attach gprs network");
gd->telit_try_reattach = TRUE;
g_at_chat_send(gd->chat, "AT+CGATT=1", none_prefix,
NULL, NULL, NULL);
return;
}
gd->telit_try_reattach = FALSE;
}
ofono_gprs_status_notify(gprs, status);
}
@@ -214,6 +240,11 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
if (g_str_equal(event, "NW DETACH") ||
g_str_equal(event, "ME DETACH")) {
if (gd->vendor == OFONO_VENDOR_TELIT &&
gd->telit_try_reattach)
return;
gd->attached = FALSE;
ofono_gprs_detached_notify(gprs);
return;
} else if (g_str_has_prefix(event, "ME PDN ACT")) {
@@ -296,6 +327,26 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
ofono_gprs_bearer_notify(gprs, bearer);
}
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
{
struct ofono_gprs *gprs = user_data;
GAtResultIter iter;
const char *mode;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
return;
if (!g_at_result_iter_next_string(&iter, &mode))
return;
if (!strcmp("LTE", mode))
ofono_gprs_bearer_notify(gprs, 7); /* LTE */
/* in other modes, notification ^MODE is used */
}
static void telit_mode_notify(GAtResult *result, gpointer user_data)
{
struct ofono_gprs *gprs = user_data;
@@ -323,6 +374,9 @@ static void telit_mode_notify(GAtResult *result, gpointer user_data)
case 3:
bearer = 5; /* HSDPA */
break;
case 4:
bearer = 7; /* LTE */
break;
default:
bearer = 0;
break;
@@ -398,6 +452,8 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
case OFONO_VENDOR_HUAWEI:
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
FALSE, gprs, NULL);
g_at_chat_register(gd->chat, "^HCSQ:", huawei_hcsq_notify,
FALSE, gprs, NULL);
break;
case OFONO_VENDOR_UBLOX:
case OFONO_VENDOR_UBLOX_TOBY_L2:
@@ -411,6 +467,7 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
FALSE, gprs, NULL);
g_at_chat_send(gd->chat, "AT#PSNT=1", none_prefix,
NULL, NULL, NULL);
break;
default:
g_at_chat_register(gd->chat, "+CPSB:", cpsb_notify,
FALSE, gprs, NULL);
@@ -522,7 +579,7 @@ static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
continue;
if (!g_at_result_iter_close_list(&iter))
if (!g_at_result_iter_skip_next(&iter))
continue;
if (g_at_result_iter_open_list(&iter))

142
ofono/drivers/atmodem/lte.c Normal file
View File

@@ -0,0 +1,142 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <glib.h>
#include <ofono/modem.h>
#include <ofono/gprs-context.h>
#include <ofono/log.h>
#include <ofono/lte.h>
#include "gatchat.h"
#include "gatresult.h"
#include "atmodem.h"
struct lte_driver_data {
GAtChat *chat;
};
static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_lte_cb_t cb = cbd->cb;
struct ofono_error error;
DBG("ok %d", ok);
decode_at_error(&error, g_at_result_final_response(result));
cb(&error, cbd->data);
}
static void at_lte_set_default_attach_info(const struct ofono_lte *lte,
const struct ofono_lte_default_attach_info *info,
ofono_lte_cb_t cb, void *data)
{
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
char buf[32 + OFONO_GPRS_MAX_APN_LENGTH + 1];
struct cb_data *cbd = cb_data_new(cb, data);
DBG("LTE config with APN: %s", info->apn);
if (strlen(info->apn) > 0)
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\",\"%s\"",
info->apn);
else
snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\"");
/* We can't do much in case of failure so don't check response. */
if (g_at_chat_send(ldd->chat, buf, NULL,
at_lte_set_default_attach_info_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, data);
}
static gboolean lte_delayed_register(gpointer user_data)
{
struct ofono_lte *lte = user_data;
ofono_lte_register(lte);
return FALSE;
}
static int at_lte_probe(struct ofono_lte *lte, void *data)
{
GAtChat *chat = data;
struct lte_driver_data *ldd;
DBG("at lte probe");
ldd = g_try_new0(struct lte_driver_data, 1);
if (!ldd)
return -ENOMEM;
ldd->chat = g_at_chat_clone(chat);
ofono_lte_set_data(lte, ldd);
g_idle_add(lte_delayed_register, lte);
return 0;
}
static void at_lte_remove(struct ofono_lte *lte)
{
struct lte_driver_data *ldd = ofono_lte_get_data(lte);
DBG("at lte remove");
g_at_chat_unref(ldd->chat);
ofono_lte_set_data(lte, NULL);
g_free(ldd);
}
static struct ofono_lte_driver driver = {
.name = "atmodem",
.probe = at_lte_probe,
.remove = at_lte_remove,
.set_default_attach_info = at_lte_set_default_attach_info,
};
void at_lte_init(void)
{
ofono_lte_driver_register(&driver);
}
void at_lte_exit(void)
{
ofono_lte_driver_unregister(&driver);
}

View File

@@ -1088,6 +1088,27 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data)
}
}
static void huawei_hcsq_notify(GAtResult *result, gpointer user_data)
{
struct ofono_netreg *netreg = user_data;
struct netreg_data *nd = ofono_netreg_get_data(netreg);
GAtResultIter iter;
const char *mode;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "^HCSQ:"))
return;
if (!g_at_result_iter_next_string(&iter, &mode))
return;
if (!strcmp("LTE", mode))
nd->tech = ACCESS_TECHNOLOGY_EUTRAN;
/* for other technologies, notification ^MODE is used */
}
static void huawei_nwtime_notify(GAtResult *result, gpointer user_data)
{
struct ofono_netreg *netreg = user_data;
@@ -1896,6 +1917,10 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify,
FALSE, netreg, NULL);
/* Register for 4G system mode reports */
g_at_chat_register(nd->chat, "^HCSQ:", huawei_hcsq_notify,
FALSE, netreg, NULL);
/* Register for network time reports */
g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
FALSE, netreg, NULL);

View File

@@ -51,6 +51,7 @@ struct sim_data {
GAtChat *chat;
unsigned int vendor;
guint ready_id;
guint passwd_type_mask;
struct at_util_sim_state_query *sim_state_query;
};
@@ -1293,14 +1294,15 @@ static void sim_state_cb(gboolean present, gpointer user_data)
struct cb_data *cbd = user_data;
struct sim_data *sd = cbd->user;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
void *data = cbd->data;
at_util_sim_state_query_free(sd->sim_state_query);
sd->sim_state_query = NULL;
if (present == 1)
CALLBACK_WITH_SUCCESS(cb, cbd->data);
CALLBACK_WITH_SUCCESS(cb, data);
else
CALLBACK_WITH_FAILURE(cb, cbd->data);
CALLBACK_WITH_FAILURE(cb, data);
}
static void at_pin_send_cb(gboolean ok, GAtResult *result,
@@ -1458,9 +1460,8 @@ static void at_pin_enable(struct ofono_sim *sim,
struct cb_data *cbd = cb_data_new(cb, data);
char buf[64];
int ret;
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
if (!(sd->passwd_type_mask & (1 << passwd_type)))
goto error;
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
@@ -1489,10 +1490,8 @@ static void at_change_passwd(struct ofono_sim *sim,
struct cb_data *cbd = cb_data_new(cb, data);
char buf[64];
int ret;
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
if (passwd_type >= len ||
at_clck_cpwd_fac[passwd_type] == NULL)
if (!(sd->passwd_type_mask & (1 << passwd_type)))
goto error;
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
@@ -1549,9 +1548,8 @@ static void at_query_clck(struct ofono_sim *sim,
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[64];
unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
if (!(sd->passwd_type_mask & (1 << passwd_type)))
goto error;
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
@@ -1567,13 +1565,42 @@ error:
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static gboolean at_sim_register(gpointer user)
static void at_clck_query_cb(gboolean ok, GAtResult *result, gpointer user)
{
struct ofono_sim *sim = user;
struct sim_data *sd = ofono_sim_get_data(sim);
GAtResultIter iter;
const char *fac;
if (!ok)
goto done;
g_at_result_iter_init(&iter, result);
/* e.g. +CLCK: ("SC","FD","PN","PU","PP","PC","PF") */
if (!g_at_result_iter_next(&iter, "+CLCK:") ||
!g_at_result_iter_open_list(&iter))
goto done;
/* Clear the default mask */
sd->passwd_type_mask = 0;
/* Set the bits for <fac>s that are actually supported */
while (g_at_result_iter_next_string(&iter, &fac)) {
unsigned int i;
/* Find it in the list of known <fac>s */
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++) {
if (!g_strcmp0(at_clck_cpwd_fac[i], fac)) {
sd->passwd_type_mask |= (1 << i);
DBG("found %s", fac);
break;
}
}
}
done:
ofono_sim_register(sim);
return FALSE;
}
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
@@ -1581,6 +1608,7 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
{
GAtChat *chat = data;
struct sim_data *sd;
unsigned int i;
sd = g_new0(struct sim_data, 1);
sd->chat = g_at_chat_clone(chat);
@@ -1590,9 +1618,15 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
ofono_sim_set_data(sim, sd);
g_idle_add(at_sim_register, sim);
return 0;
/* <fac>s supported by default */
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++)
if (at_clck_cpwd_fac[i])
sd->passwd_type_mask |= (1 << i);
/* Query supported <fac>s */
return g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
at_clck_query_cb, sim, NULL) ? 0 : -1;
}
static void at_sim_remove(struct ofono_sim *sim)

View File

@@ -319,26 +319,6 @@ static void at_cnma_cb(gboolean ok, GAtResult *result, gpointer user_data)
"Further SMS reception is not guaranteed");
}
static gboolean at_parse_cmt(GAtResult *result, const char **pdu, int *pdulen)
{
GAtResultIter iter;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CMT:"))
return FALSE;
if (!g_at_result_iter_skip_next(&iter))
return FALSE;
if (!g_at_result_iter_next_number(&iter, pdulen))
return FALSE;
*pdu = g_at_result_pdu(result);
return TRUE;
}
static inline void at_ack_delivery(struct ofono_sms *sms)
{
struct sms_data *data = ofono_sms_get_data(sms);
@@ -347,11 +327,21 @@ static inline void at_ack_delivery(struct ofono_sms *sms)
DBG("");
/* We must acknowledge the PDU using CNMA */
if (data->cnma_ack_pdu)
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
data->cnma_ack_pdu_len, data->cnma_ack_pdu);
else /* Should be a safe fallback */
if (data->cnma_ack_pdu) {
switch (data->vendor) {
case OFONO_VENDOR_CINTERION:
snprintf(buf, sizeof(buf), "AT+CNMA=1");
break;
default:
snprintf(buf, sizeof(buf), "AT+CNMA=1,%d\r%s",
data->cnma_ack_pdu_len,
data->cnma_ack_pdu);
break;
}
} else {
/* Should be a safe fallback */
snprintf(buf, sizeof(buf), "AT+CNMA=0");
}
g_at_chat_send(data->chat, buf, none_prefix, at_cnma_cb, NULL, NULL);
}
@@ -409,16 +399,34 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
{
struct ofono_sms *sms = user_data;
struct sms_data *data = ofono_sms_get_data(sms);
GAtResultIter iter;
const char *hexpdu;
unsigned char pdu[176];
long pdu_len;
int tpdu_len;
unsigned char pdu[176];
if (!at_parse_cmt(result, &hexpdu, &tpdu_len)) {
ofono_error("Unable to parse CMT notification");
return;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CMT:"))
goto err;
switch (data->vendor) {
case OFONO_VENDOR_CINTERION:
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
goto err;
break;
default:
if (!g_at_result_iter_skip_next(&iter))
goto err;
if (!g_at_result_iter_next_number(&iter, &tpdu_len))
goto err;
break;
}
hexpdu = g_at_result_pdu(result);
if (strlen(hexpdu) > sizeof(pdu) * 2) {
ofono_error("Bad PDU length in CMT notification");
return;
@@ -431,6 +439,9 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
if (data->vendor != OFONO_VENDOR_SIMCOM)
at_ack_delivery(sms);
err:
ofono_error("Unable to parse CMT notification");
}
static void at_cmgr_notify(GAtResult *result, gpointer user_data)
@@ -742,7 +753,7 @@ static void at_sms_initialized(struct ofono_sms *sms)
static void at_sms_not_supported(struct ofono_sms *sms)
{
ofono_error("SMS not supported by this modem. If this is in error"
ofono_error("SMS not supported by this modem. If this is an error"
" please submit patches to support this hardware");
ofono_sms_remove(sms);

View File

@@ -47,4 +47,5 @@ enum ofono_vendor {
OFONO_VENDOR_UBLOX,
OFONO_VENDOR_UBLOX_TOBY_L2,
OFONO_VENDOR_CINTERION,
OFONO_VENDOR_XMM,
};

View File

@@ -43,7 +43,7 @@
#include "cdmamodem.h"
#include "drivers/atmodem/vendor.h"
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
#define TUN_DEV "/dev/net/tun"
#define STATIC_IP_NETMASK "255.255.255.255"
@@ -285,7 +285,7 @@ static int cdma_connman_probe(struct ofono_cdma_connman *cm,
DBG("");
if (stat(TUN_SYSFS_DIR, &st) < 0) {
if (stat(TUN_DEV, &st) < 0) {
ofono_error("Missing support for TUN/TAP devices");
return -ENODEV;
}

View File

@@ -0,0 +1,49 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib.h>
#include <gatchat.h>
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include <ofono/types.h>
#include "gemaltomodem.h"
static int gemaltomodem_init(void)
{
gemalto_location_reporting_init();
return 0;
}
static void gemaltomodem_exit(void)
{
gemalto_location_reporting_exit();
}
OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT,
gemaltomodem_init, gemaltomodem_exit)

View File

@@ -2,7 +2,7 @@
*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2017 Vincent Cesson. 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
@@ -19,11 +19,7 @@
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <drivers/atmodem/atutil.h>
int main(int argc, char **argv)
{
return 0;
}
extern void gemalto_location_reporting_init();
extern void gemalto_location_reporting_exit();

View File

@@ -0,0 +1,237 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Vincent Cesson. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <glib.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/location-reporting.h>
#include "gatchat.h"
#include "gatresult.h"
#include "gattty.h"
#include "gemaltomodem.h"
static const char *sgpsc_prefix[] = { "^SGPSC:", NULL };
struct gps_data {
GAtChat *chat;
};
static void gemalto_gps_disable_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
struct ofono_location_reporting *lr = cbd->user;
ofono_location_reporting_disable_cb_t cb = cbd->cb;
DBG("lr=%p, ok=%d", lr, ok);
if (!ok) {
struct ofono_error error;
decode_at_error(&error, g_at_result_final_response(result));
cb(&error, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void gemalto_location_reporting_disable(
struct ofono_location_reporting *lr,
ofono_location_reporting_disable_cb_t cb,
void *data)
{
struct gps_data *gd = ofono_location_reporting_get_data(lr);
struct cb_data *cbd = cb_data_new(cb, data);
DBG("lr=%p", lr);
cbd->user = lr;
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",0", sgpsc_prefix,
gemalto_gps_disable_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
}
static int enable_data_stream(struct ofono_location_reporting *lr)
{
struct ofono_modem *modem;
const char *gps_dev;
GHashTable *options;
GIOChannel *channel;
int fd;
modem = ofono_location_reporting_get_modem(lr);
gps_dev = ofono_modem_get_string(modem, "GPS");
options = g_hash_table_new(g_str_hash, g_str_equal);
if (options == NULL)
return -1;
g_hash_table_insert(options, "Baud", "115200");
channel = g_at_tty_open(gps_dev, options);
g_hash_table_destroy(options);
if (channel == NULL)
return -1;
fd = g_io_channel_unix_get_fd(channel);
g_io_channel_set_close_on_unref(channel, FALSE);
g_io_channel_unref(channel);
return fd;
}
static void gemalto_sgpsc_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_location_reporting_enable_cb_t cb = cbd->cb;
struct ofono_location_reporting *lr = cbd->user;
struct ofono_error error;
int fd;
DBG("lr=%p ok=%d", lr, ok);
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, -1, cbd->data);
return;
}
fd = enable_data_stream(lr);
if (fd < 0) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
return;
}
cb(&error, fd, cbd->data);
close(fd);
}
static void gemalto_location_reporting_enable(struct ofono_location_reporting *lr,
ofono_location_reporting_enable_cb_t cb,
void *data)
{
struct gps_data *gd = ofono_location_reporting_get_data(lr);
struct cb_data *cbd = cb_data_new(cb, data);
DBG("lr=%p", lr);
cbd->user = lr;
if (g_at_chat_send(gd->chat, "AT^SGPSC=\"Engine\",2", sgpsc_prefix,
gemalto_sgpsc_cb, cbd, NULL) > 0)
return;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
g_free(cbd);
}
static void gemalto_location_reporting_support_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct ofono_location_reporting *lr = user_data;
if (!ok) {
ofono_location_reporting_remove(lr);
return;
}
ofono_location_reporting_register(lr);
}
static int gemalto_location_reporting_probe(struct ofono_location_reporting *lr,
unsigned int vendor, void *data)
{
GAtChat *chat = data;
struct gps_data *gd;
gd = g_try_new0(struct gps_data, 1);
if (gd == NULL)
return -ENOMEM;
gd->chat = g_at_chat_clone(chat);
ofono_location_reporting_set_data(lr, gd);
g_at_chat_send(gd->chat, "AT^SGPSC=?", sgpsc_prefix,
gemalto_location_reporting_support_cb,
lr, NULL);
return 0;
}
static void gemalto_location_reporting_remove(struct ofono_location_reporting *lr)
{
struct gps_data *gd = ofono_location_reporting_get_data(lr);
ofono_location_reporting_set_data(lr, NULL);
g_at_chat_unref(gd->chat);
g_free(gd);
}
static struct ofono_location_reporting_driver driver = {
.name = "gemaltomodem",
.type = OFONO_LOCATION_REPORTING_TYPE_NMEA,
.probe = gemalto_location_reporting_probe,
.remove = gemalto_location_reporting_remove,
.enable = gemalto_location_reporting_enable,
.disable = gemalto_location_reporting_disable,
};
void gemalto_location_reporting_init()
{
ofono_location_reporting_driver_register(&driver);
}
void gemalto_location_reporting_exit()
{
ofono_location_reporting_driver_unregister(&driver);
}

View File

@@ -42,11 +42,13 @@
static const char *none_prefix[] = { NULL };
static const char *syscfg_prefix[] = { "^SYSCFG:", NULL };
static const char *syscfgex_prefix[] = { "^SYSCFGEX:", NULL };
#define HUAWEI_BAND_ANY 0x3FFFFFFF
struct radio_settings_data {
GAtChat *chat;
ofono_bool_t syscfgex_cap;
};
static const struct huawei_band_gsm_table {
@@ -176,20 +178,76 @@ error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
static void syscfgex_query_mode_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
enum ofono_radio_access_mode mode;
struct ofono_error error;
GAtResultIter iter;
const char *acqorder;
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, -1, cbd->data);
return;
}
g_at_result_iter_init(&iter, result);
if (g_at_result_iter_next(&iter, "^SYSCFGEX:") == FALSE)
goto error;
if (g_at_result_iter_next_string(&iter, &acqorder) == FALSE)
goto error;
if ((strcmp(acqorder, "00") == 0) ||
(strstr(acqorder, "01") &&
strstr(acqorder, "02") &&
strstr(acqorder, "03")))
mode = OFONO_RADIO_ACCESS_MODE_ANY;
else if (strstr(acqorder, "03"))
mode = OFONO_RADIO_ACCESS_MODE_LTE;
else if (strstr(acqorder, "02"))
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
else if (strstr(acqorder, "01"))
mode = OFONO_RADIO_ACCESS_MODE_GSM;
else
goto error;
cb(&error, mode, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
static void huawei_query_rat_mode(struct ofono_radio_settings *rs,
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
{
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
struct cb_data *cbd = cb_data_new(cb, data);
if (g_at_chat_send(rsd->chat, "AT^SYSCFG?", syscfg_prefix,
syscfg_query_mode_cb, cbd, g_free) == 0) {
CALLBACK_WITH_FAILURE(cb, -1, data);
g_free(cbd);
}
if (rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFGEX?",
syscfgex_prefix,
syscfgex_query_mode_cb,
cbd, g_free) > 0)
return;
if (!rsd->syscfgex_cap && g_at_chat_send(rsd->chat, "AT^SYSCFG?",
syscfg_prefix,
syscfg_query_mode_cb,
cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, -1, data);
g_free(cbd);
}
static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
static void syscfgxx_modify_mode_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -200,12 +258,11 @@ static void syscfg_modify_mode_cb(gboolean ok, GAtResult *result,
cb(&error, cbd->data);
}
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
static void syscfg_set_rat_mode(struct radio_settings_data *rsd,
enum ofono_radio_access_mode mode,
ofono_radio_settings_rat_mode_set_cb_t cb,
void *data)
{
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[40];
unsigned int value = 2, acq_order = 0;
@@ -231,7 +288,7 @@ static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
value, acq_order);
if (g_at_chat_send(rsd->chat, buf, none_prefix,
syscfg_modify_mode_cb, cbd, g_free) > 0)
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
return;
error:
@@ -239,7 +296,55 @@ error:
g_free(cbd);
}
static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
static void syscfgex_set_rat_mode(struct radio_settings_data *rsd,
enum ofono_radio_access_mode mode,
ofono_radio_settings_rat_mode_set_cb_t cb,
void *data)
{
struct cb_data *cbd = cb_data_new(cb, data);
char buf[50];
char *atcmd = "AT^SYSCFGEX=\"%s\",40000000,2,4,40000000,,";
char *acqorder = "030201";
switch (mode) {
case OFONO_RADIO_ACCESS_MODE_ANY:
acqorder = "00";
break;
case OFONO_RADIO_ACCESS_MODE_GSM:
acqorder = "01";
break;
case OFONO_RADIO_ACCESS_MODE_UMTS:
acqorder = "02";
break;
case OFONO_RADIO_ACCESS_MODE_LTE:
acqorder = "03";
break;
}
snprintf(buf, sizeof(buf), atcmd, acqorder);
if (g_at_chat_send(rsd->chat, buf, none_prefix,
syscfgxx_modify_mode_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
}
static void huawei_set_rat_mode(struct ofono_radio_settings *rs,
enum ofono_radio_access_mode mode,
ofono_radio_settings_rat_mode_set_cb_t cb,
void *data)
{
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
if (rsd->syscfgex_cap)
syscfgex_set_rat_mode(rsd, mode, cb, data);
else
syscfg_set_rat_mode(rsd, mode, cb, data);
}
static void syscfgxx_modify_band_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -250,13 +355,54 @@ static void syscfg_modify_band_cb(gboolean ok, GAtResult *result,
cb(&error, cbd->data);
}
static void huawei_set_band(struct ofono_radio_settings *rs,
static void syscfgex_set_band(struct radio_settings_data *rsd,
enum ofono_radio_band_gsm band_gsm,
enum ofono_radio_band_umts band_umts,
ofono_radio_settings_band_set_cb_t cb,
void *data)
{
struct cb_data *cbd = cb_data_new(cb, data);
char buf[50];
char *atcmd = "AT^SYSCFGEX=\"99\",%x,2,4,40000000,,";
unsigned int huawei_band;
if (band_gsm == OFONO_RADIO_BAND_GSM_ANY
&& band_umts == OFONO_RADIO_BAND_UMTS_ANY) {
huawei_band = HUAWEI_BAND_ANY;
} else {
unsigned int huawei_band_gsm;
unsigned int huawei_band_umts;
huawei_band_gsm = band_gsm_to_huawei(band_gsm);
if (!huawei_band_gsm)
goto error;
huawei_band_umts = band_umts_to_huawei(band_umts);
if (!huawei_band_umts)
goto error;
huawei_band = huawei_band_gsm | huawei_band_umts;
}
snprintf(buf, sizeof(buf), atcmd, huawei_band);
if (g_at_chat_send(rsd->chat, buf, none_prefix,
syscfgxx_modify_band_cb, cbd, g_free) > 0)
return;
error:
CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
}
static void syscfg_set_band(struct radio_settings_data *rsd,
enum ofono_radio_band_gsm band_gsm,
enum ofono_radio_band_umts band_umts,
ofono_radio_settings_band_set_cb_t cb,
void *data)
{
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[40];
unsigned int huawei_band;
@@ -284,7 +430,7 @@ static void huawei_set_band(struct ofono_radio_settings *rs,
snprintf(buf, sizeof(buf), "AT^SYSCFG=16,3,%x,2,4", huawei_band);
if (g_at_chat_send(rsd->chat, buf, none_prefix,
syscfg_modify_band_cb, cbd, g_free) > 0)
syscfgxx_modify_band_cb, cbd, g_free) > 0)
return;
error:
@@ -292,6 +438,20 @@ error:
g_free(cbd);
}
static void huawei_set_band(struct ofono_radio_settings *rs,
enum ofono_radio_band_gsm band_gsm,
enum ofono_radio_band_umts band_umts,
ofono_radio_settings_band_set_cb_t cb,
void *data)
{
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
if (rsd->syscfgex_cap)
syscfgex_set_band(rsd, band_gsm, band_umts, cb, data);
else
syscfg_set_band(rsd, band_gsm, band_umts, cb, data);
}
static void syscfg_query_band_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
@@ -364,6 +524,21 @@ static void syscfg_support_cb(gboolean ok, GAtResult *result,
ofono_radio_settings_register(rs);
}
static void syscfgex_support_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct ofono_radio_settings *rs = user_data;
struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
if (!ok) {
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
syscfg_support_cb, rs, NULL);
}
rsd->syscfgex_cap = 1;
ofono_radio_settings_register(rs);
}
static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
unsigned int vendor, void *data)
{
@@ -378,8 +553,8 @@ static int huawei_radio_settings_probe(struct ofono_radio_settings *rs,
ofono_radio_settings_set_data(rs, rsd);
g_at_chat_send(rsd->chat, "AT^SYSCFG=?", syscfg_prefix,
syscfg_support_cb, rs, NULL);
g_at_chat_send(rsd->chat, "AT^SYSCFGEX=?", syscfgex_prefix,
syscfgex_support_cb, rs, NULL);
return 0;
}
@@ -400,8 +575,8 @@ static struct ofono_radio_settings_driver driver = {
.remove = huawei_radio_settings_remove,
.query_rat_mode = huawei_query_rat_mode,
.set_rat_mode = huawei_set_rat_mode,
.query_band = huawei_query_band,
.set_band = huawei_set_band,
.query_band = huawei_query_band,
.set_band = huawei_set_band,
};
void huawei_radio_settings_init(void)

View File

@@ -42,13 +42,14 @@
#include "ifxmodem.h"
#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
#define TUN_DEV "/dev/net/tun"
#define STATIC_IP_NETMASK "255.255.255.255"
static const char *none_prefix[] = { NULL };
static const char *xdns_prefix[] = { "+XDNS:", NULL };
static const char *cgpaddr_prefix[] = { "+CGPADDR:", NULL };
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
enum state {
STATE_IDLE,
@@ -59,17 +60,20 @@ enum state {
struct gprs_context_data {
GAtChat *chat;
unsigned int vendor;
unsigned int active_context;
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
GAtRawIP *rawip;
enum state state;
enum ofono_gprs_proto proto;
char address[32];
char dns1[32];
char dns2[32];
char address[64];
char gateway[64];
char netmask[64];
char dns1[64];
char dns2[64];
ofono_gprs_context_cb_t cb;
void *cb_data; /* Callback data */
void *cb_data;
};
static void rawip_debug(const char *str, void *data)
@@ -257,11 +261,136 @@ error:
failed_setup(gc, NULL, TRUE);
}
static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_gprs_context *gc = user_data;
struct ofono_modem *modem = ofono_gprs_context_get_modem(gc);
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
GAtResultIter iter;
const char *laddrnetmask = NULL;
const char *gw = NULL;
const char *interface;
const char *dns[3];
DBG("ok %d", ok);
if (!ok) {
struct ofono_error error;
decode_at_error(&error, g_at_result_final_response(result));
gcd->cb(&error, gcd->cb_data);
return;
}
g_at_result_iter_init(&iter, result);
while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) {
/* skip cid, bearer_id, apn */
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
if (!g_at_result_iter_next_string(&iter, &laddrnetmask))
break;
if (!g_at_result_iter_next_string(&iter, &gw))
break;
if (!g_at_result_iter_next_string(&iter, &dns[0]))
break;
if (!g_at_result_iter_next_string(&iter, &dns[1]))
break;
}
strncpy(gcd->dns1, dns[0], sizeof(gcd->dns1));
strncpy(gcd->dns2, dns[1], sizeof(gcd->dns2));
dns[2] = 0;
DBG("DNS: %s, %s\n", gcd->dns1, gcd->dns2);
if (!laddrnetmask || at_util_get_ipv4_address_and_netmask(laddrnetmask,
gcd->address, gcd->netmask) < 0) {
failed_setup(gc, NULL, TRUE);
return;
}
if (gw)
strncpy(gcd->gateway, gw, sizeof(gcd->gateway));
gcd->state = STATE_ACTIVE;
DBG("address: %s\n", gcd->address);
DBG("netmask: %s\n", gcd->netmask);
DBG("DNS1: %s\n", gcd->dns1);
DBG("DNS2: %s\n", gcd->dns2);
DBG("Gateway: %s\n", gcd->gateway);
interface = ofono_modem_get_string(modem, "NetworkInterface");
ofono_gprs_context_set_interface(gc, interface);
ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
if (gcd->netmask[0])
ofono_gprs_context_set_ipv4_netmask(gc, gcd->netmask);
if (gcd->gateway[0])
ofono_gprs_context_set_ipv4_gateway(gc, gcd->gateway);
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
}
static void ifx_read_settings(struct ofono_gprs_context *gc)
{
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
char buf[64];
gcd->address[0] = '\0';
gcd->gateway[0] = '\0';
gcd->netmask[0] = '\0';
gcd->dns1[0] = '\0';
gcd->dns2[0] = '\0';
/* read IP configuration info */
if(gcd->vendor == OFONO_VENDOR_XMM) {
snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%u",
gcd->active_context);
if (g_at_chat_send(gcd->chat, buf, cgcontrdp_prefix,
cgcontrdp_cb, gc, NULL) > 0)
return;
} else {
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
address_cb, gc, NULL) > 0)
return;
}
failed_setup(gc, NULL, TRUE);
}
static void ifx_gprs_read_settings(struct ofono_gprs_context *gc,
unsigned int cid,
ofono_gprs_context_cb_t cb, void *data)
{
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
DBG("cid %u", cid);
gcd->active_context = cid;
gcd->cb = cb;
gcd->cb_data = data;
ifx_read_settings(gc);
}
static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_gprs_context *gc = user_data;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
char buf[64];
DBG("ok %d", ok);
@@ -271,19 +400,14 @@ static void activate_cb(gboolean ok, GAtResult *result, gpointer user_data)
return;
}
sprintf(buf, "AT+CGPADDR=%u", gcd->active_context);
if (g_at_chat_send(gcd->chat, buf, cgpaddr_prefix,
address_cb, gc, NULL) > 0)
return;
failed_setup(gc, NULL, TRUE);
ifx_read_settings(gc);
}
static void setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_gprs_context *gc = user_data;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
char buf[128];
char buf[384];
DBG("ok %d", ok);
@@ -387,7 +511,8 @@ static void deactivate_cb(gboolean ok, GAtResult *result, gpointer user_data)
gcd->active_context = 0;
gcd->state = STATE_IDLE;
g_at_chat_resume(gcd->chat);
if (gcd->vendor != OFONO_VENDOR_XMM)
g_at_chat_resume(gcd->chat);
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
}
@@ -409,11 +534,25 @@ static void ifx_gprs_deactivate_primary(struct ofono_gprs_context *gc,
g_at_rawip_shutdown(gcd->rawip);
sprintf(buf, "AT+CGACT=0,%u", gcd->active_context);
if (g_at_chat_send(chat, buf, none_prefix,
deactivate_cb, gc, NULL) > 0)
return;
CALLBACK_WITH_SUCCESS(cb, data);
if (gcd->vendor == OFONO_VENDOR_XMM) {
if (g_at_chat_send(gcd->chat, buf, none_prefix,
deactivate_cb, gc, NULL) > 0)
return;
} else {
if (g_at_chat_send(chat, buf, none_prefix,
deactivate_cb, gc, NULL) > 0)
return;
}
CALLBACK_WITH_FAILURE(cb, data);
}
static void ifx_gprs_detach_shutdown(struct ofono_gprs_context *gc,
unsigned int cid)
{
DBG("");
ifx_gprs_deactivate_primary(gc, cid, NULL, NULL);
}
static void cgev_notify(GAtResult *result, gpointer user_data)
@@ -451,14 +590,13 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
g_at_rawip_unref(gcd->rawip);
gcd->rawip = NULL;
g_at_chat_resume(gcd->chat);
}
ofono_gprs_context_deactivated(gc, gcd->active_context);
gcd->active_context = 0;
gcd->state = STATE_IDLE;
g_at_chat_resume(gcd->chat);
}
static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
@@ -470,23 +608,27 @@ static int ifx_gprs_context_probe(struct ofono_gprs_context *gc,
DBG("");
if (stat(TUN_SYSFS_DIR, &st) < 0) {
if (stat(TUN_DEV, &st) < 0) {
ofono_error("Missing support for TUN/TAP devices");
return -ENODEV;
}
if (g_at_chat_get_slave(chat) == NULL)
return -EINVAL;
if (vendor != OFONO_VENDOR_XMM) {
if (g_at_chat_get_slave(chat) == NULL)
return -EINVAL;
}
gcd = g_try_new0(struct gprs_context_data, 1);
if (gcd == NULL)
return -ENOMEM;
gcd->vendor = vendor;
gcd->chat = g_at_chat_clone(chat);
ofono_gprs_context_set_data(gc, gcd);
chat = g_at_chat_get_slave(gcd->chat);
if (vendor != OFONO_VENDOR_XMM)
chat = g_at_chat_get_slave(gcd->chat);
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
@@ -516,6 +658,8 @@ static struct ofono_gprs_context_driver driver = {
.remove = ifx_gprs_context_remove,
.activate_primary = ifx_gprs_activate_primary,
.deactivate_primary = ifx_gprs_deactivate_primary,
.read_settings = ifx_gprs_read_settings,
.detach_shutdown = ifx_gprs_detach_shutdown
};
void ifx_gprs_context_init(void)

View File

@@ -20,6 +20,7 @@
*/
#include <drivers/atmodem/atutil.h>
#include <drivers/atmodem/vendor.h>
extern void ifx_voicecall_init(void);
extern void ifx_voicecall_exit(void);

View File

@@ -646,8 +646,31 @@ error:
/* ISI callback: PIN state (enabled/disabled) query */
static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
{
check_sec_response(msg, opaque, SEC_CODE_STATE_OK_RESP,
SEC_CODE_STATE_FAIL_RESP);
struct isi_cb_data *cbd = opaque;
ofono_query_facility_lock_cb_t cb = cbd->cb;
int locked;
uint8_t state;
uint8_t status;
if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
!g_isi_msg_data_get_byte(msg, 1, &status))
goto error;
if (state != SEC_CODE_STATE_OK_RESP)
goto error;
if (status == SEC_CODE_ENABLE)
locked = 1;
else if (status == SEC_CODE_DISABLE)
locked = 0;
else
goto error;
CALLBACK_WITH_SUCCESS(cb, locked, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
static void isi_query_locked(struct ofono_sim *sim,

View File

@@ -23,6 +23,8 @@
#include <config.h>
#endif
#include <string.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/devinfo.h>
@@ -125,7 +127,8 @@ static void get_ids_cb(struct qmi_result *result, void *user_data)
}
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
if (!str) {
/* Telit qmi modems return a "0" string when ESN is not available. */
if (!str || strcmp(str, "0") == 0) {
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
if (!str) {
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);

View File

@@ -24,18 +24,22 @@
#endif
#include <string.h>
#include <arpa/inet.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/gprs-context.h>
#include "qmi.h"
#include "wda.h"
#include "wds.h"
#include "qmimodem.h"
struct gprs_context_data {
struct qmi_service *wds;
struct qmi_service *wda;
struct qmi_device *dev;
unsigned int active_context;
uint32_t pkt_handle;
};
@@ -61,8 +65,12 @@ static void pkt_status_notify(struct qmi_result *result, void *user_data)
switch (status->status) {
case QMI_WDS_CONN_STATUS_DISCONNECTED:
ofono_gprs_context_deactivated(gc, data->active_context);
data->active_context = 0;
if (data->pkt_handle) {
/* The context has been disconnected by the network */
ofono_gprs_context_deactivated(gc, data->active_context);
data->pkt_handle = 0;
data->active_context = 0;
}
break;
}
}
@@ -75,18 +83,68 @@ static void get_settings_cb(struct qmi_result *result, void *user_data)
struct ofono_modem *modem;
const char *interface;
uint8_t pdp_type, ip_family;
uint32_t ip_addr;
struct in_addr addr;
char* straddr;
char* apn;
const char *dns[3] = { NULL, NULL, NULL };
DBG("");
if (qmi_result_set_error(result, NULL))
goto done;
apn = qmi_result_get_string(result, QMI_WDS_RESULT_APN);
if (apn) {
DBG("APN: %s", apn);
g_free(apn);
}
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_PDP_TYPE, &pdp_type))
DBG("PDP type %d", pdp_type);
if (qmi_result_get_uint8(result, QMI_WDS_RESULT_IP_FAMILY, &ip_family))
DBG("IP family %d", ip_family);
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_IP_ADDRESS, &ip_addr)) {
addr.s_addr = htonl(ip_addr);
straddr = inet_ntoa(addr);
DBG("IP addr: %s", straddr);
ofono_gprs_context_set_ipv4_address(gc, straddr, 1);
}
if (qmi_result_get_uint32(result,QMI_WDS_RESULT_GATEWAY, &ip_addr)) {
addr.s_addr = htonl(ip_addr);
straddr = inet_ntoa(addr);
DBG("Gateway: %s", straddr);
ofono_gprs_context_set_ipv4_gateway(gc, straddr);
}
if (qmi_result_get_uint32(result,
QMI_WDS_RESULT_GATEWAY_NETMASK, &ip_addr)) {
addr.s_addr = htonl(ip_addr);
straddr = inet_ntoa(addr);
DBG("Gateway netmask: %s", straddr);
ofono_gprs_context_set_ipv4_netmask(gc, straddr);
}
if (qmi_result_get_uint32(result,
QMI_WDS_RESULT_PRIMARY_DNS, &ip_addr)) {
addr.s_addr = htonl(ip_addr);
dns[0] = inet_ntoa(addr);
DBG("Primary DNS: %s", dns[0]);
}
if (qmi_result_get_uint32(result,
QMI_WDS_RESULT_SECONDARY_DNS, &ip_addr)) {
addr.s_addr = htonl(ip_addr);
dns[1] = inet_ntoa(addr);
DBG("Secondary DNS: %s", dns[1]);
}
if (dns[0])
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
done:
modem = ofono_gprs_context_get_modem(gc);
interface = ofono_modem_get_string(modem, "NetworkInterface");
@@ -94,8 +152,6 @@ done:
ofono_gprs_context_set_interface(gc, interface);
CALLBACK_WITH_SUCCESS(cb, cbd->data);
g_free(cbd);
}
static void start_net_cb(struct qmi_result *result, void *user_data)
@@ -120,8 +176,12 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
data->pkt_handle = handle;
/* Duplicate cbd, the old one will be freed when this method returns */
cbd = cb_data_new(cb, cbd->data);
cbd->user = gc;
if (qmi_service_send(data->wds, QMI_WDS_GET_SETTINGS, NULL,
get_settings_cb, cbd, NULL) > 0)
get_settings_cb, cbd, g_free) > 0)
return;
modem = ofono_gprs_context_get_modem(gc);
@@ -131,12 +191,39 @@ static void start_net_cb(struct qmi_result *result, void *user_data)
CALLBACK_WITH_SUCCESS(cb, cbd->data);
g_free(cbd);
return;
error:
data->active_context = 0;
CALLBACK_WITH_FAILURE(cb, cbd->data);
}
/*
* This function gets called for "automatic" contexts, those which are
* not activated via activate_primary. For these, we will still need
* to call start_net in order to get the packet handle for the context.
* The process for automatic contexts is essentially identical to that
* for others.
*/
static void qmi_gprs_read_settings(struct ofono_gprs_context* gc,
unsigned int cid,
ofono_gprs_context_cb_t cb,
void *user_data)
{
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
struct cb_data *cbd = cb_data_new(cb, user_data);
DBG("cid %u", cid);
data->active_context = cid;
cbd->user = gc;
if (qmi_service_send(data->wds, QMI_WDS_START_NET, NULL,
start_net_cb, cbd, g_free) > 0)
return;
data->active_context = 0;
CALLBACK_WITH_FAILURE(cb, cbd->data);
@@ -151,6 +238,7 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
struct cb_data *cbd = cb_data_new(cb, user_data);
struct qmi_param *param;
uint8_t ip_family;
uint8_t auth;
DBG("cid %u", ctx->cid);
@@ -178,8 +266,31 @@ static void qmi_activate_primary(struct ofono_gprs_context *gc,
qmi_param_append_uint8(param, QMI_WDS_PARAM_IP_FAMILY, ip_family);
switch (ctx->auth_method) {
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = QMI_WDS_AUTHENTICATION_CHAP;
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = QMI_WDS_AUTHENTICATION_PAP;
break;
default:
auth = QMI_WDS_AUTHENTICATION_NONE;
break;
}
qmi_param_append_uint8(param, QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE,
auth);
if (ctx->username[0] != '\0')
qmi_param_append(param, QMI_WDS_PARAM_USERNAME,
strlen(ctx->username), ctx->username);
if (ctx->password[0] != '\0')
qmi_param_append(param, QMI_WDS_PARAM_PASSWORD,
strlen(ctx->password), ctx->password);
if (qmi_service_send(data->wds, QMI_WDS_START_NET, param,
start_net_cb, cbd, NULL) > 0)
start_net_cb, cbd, g_free) > 0)
return;
qmi_param_free(param);
@@ -202,17 +313,19 @@ static void stop_net_cb(struct qmi_result *result, void *user_data)
DBG("");
if (qmi_result_set_error(result, NULL)) {
CALLBACK_WITH_FAILURE(cb, cbd->data);
if (cb)
CALLBACK_WITH_FAILURE(cb, cbd->data);
return;
}
data->active_context = 0;
data->pkt_handle = 0;
CALLBACK_WITH_SUCCESS(cb, cbd->data);
if (cb)
CALLBACK_WITH_SUCCESS(cb, cbd->data);
else
ofono_gprs_context_deactivated(gc, data->active_context);
g_free(cbd);
data->active_context = 0;
}
static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
@@ -233,17 +346,26 @@ static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
goto error;
if (qmi_service_send(data->wds, QMI_WDS_STOP_NET, param,
stop_net_cb, cbd, NULL) > 0)
stop_net_cb, cbd, g_free) > 0)
return;
qmi_param_free(param);
error:
CALLBACK_WITH_FAILURE(cb, cbd->data);
if (cb)
CALLBACK_WITH_FAILURE(cb, user_data);
g_free(cbd);
}
static void qmi_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
unsigned int cid)
{
DBG("");
qmi_deactivate_primary(gc, cid, NULL, NULL);
}
static void create_wds_cb(struct qmi_service *service, void *user_data)
{
struct ofono_gprs_context *gc = user_data;
@@ -263,6 +385,69 @@ static void create_wds_cb(struct qmi_service *service, void *user_data)
pkt_status_notify, gc, NULL);
}
static void get_data_format_cb(struct qmi_result *result, void *user_data)
{
struct ofono_gprs_context *gc = user_data;
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
uint32_t llproto;
enum qmi_device_expected_data_format expected_llproto;
DBG("");
if (qmi_result_set_error(result, NULL))
goto done;
if (!qmi_result_get_uint32(result, QMI_WDA_LL_PROTOCOL, &llproto))
goto done;
expected_llproto = qmi_device_get_expected_data_format(data->dev);
if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_802_3) &&
(expected_llproto ==
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP)) {
if (!qmi_device_set_expected_data_format(data->dev,
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3))
DBG("Fail to set expected data to 802.3");
else
DBG("expected data set to 802.3");
} else if ((llproto == QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP) &&
(expected_llproto ==
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3)) {
if (!qmi_device_set_expected_data_format(data->dev,
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP))
DBG("Fail to set expected data to raw-ip");
else
DBG("expected data set to raw-ip");
}
done:
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
NULL);
}
static void create_wda_cb(struct qmi_service *service, void *user_data)
{
struct ofono_gprs_context *gc = user_data;
struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
DBG("");
if (!service) {
DBG("Failed to request WDA service, continue initialization");
goto error;
}
data->wda = qmi_service_ref(service);
if (qmi_service_send(data->wda, QMI_WDA_GET_DATA_FORMAT, NULL,
get_data_format_cb, gc, NULL) > 0)
return;
error:
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS, create_wds_cb, gc,
NULL);
}
static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
unsigned int vendor, void *user_data)
{
@@ -274,8 +459,9 @@ static int qmi_gprs_context_probe(struct ofono_gprs_context *gc,
data = g_new0(struct gprs_context_data, 1);
ofono_gprs_context_set_data(gc, data);
data->dev = device;
qmi_service_create(device, QMI_SERVICE_WDS, create_wds_cb, gc, NULL);
qmi_service_create(device, QMI_SERVICE_WDA, create_wda_cb, gc, NULL);
return 0;
}
@@ -288,9 +474,15 @@ static void qmi_gprs_context_remove(struct ofono_gprs_context *gc)
ofono_gprs_context_set_data(gc, NULL);
qmi_service_unregister_all(data->wds);
if (data->wds) {
qmi_service_unregister_all(data->wds);
qmi_service_unref(data->wds);
}
qmi_service_unref(data->wds);
if (data->wda) {
qmi_service_unregister_all(data->wda);
qmi_service_unref(data->wda);
}
g_free(data);
}
@@ -301,6 +493,8 @@ static struct ofono_gprs_context_driver driver = {
.remove = qmi_gprs_context_remove,
.activate_primary = qmi_activate_primary,
.deactivate_primary = qmi_deactivate_primary,
.read_settings = qmi_gprs_read_settings,
.detach_shutdown = qmi_gprs_context_detach_shutdown,
};
void qmi_gprs_context_init(void)

View File

@@ -30,16 +30,18 @@
#include "qmi.h"
#include "nas.h"
#include "src/common.h"
#include "qmimodem.h"
struct gprs_data {
struct qmi_service *nas;
};
static bool extract_ss_info(struct qmi_result *result, int *status)
static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
{
const struct qmi_nas_serving_system *ss;
uint16_t len;
int i;
DBG("");
@@ -47,14 +49,46 @@ static bool extract_ss_info(struct qmi_result *result, int *status)
if (!ss)
return false;
if (ss->ps_state == QMI_NAS_ATTACH_STATUS_ATTACHED)
*status = 0x01;
if (ss->ps_state == QMI_NAS_ATTACH_STATE_ATTACHED)
*status = NETWORK_REGISTRATION_STATUS_REGISTERED;
else
*status = 0x00;
*status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
*tech = -1;
for (i = 0; i < ss->radio_if_count; i++) {
DBG("radio in use %d", ss->radio_if[i]);
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
}
return true;
}
static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
{
int status;
int tech;
DBG("");
if (!extract_ss_info(result, &status, &tech))
return -1;
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED)
if (tech == ACCESS_TECHNOLOGY_EUTRAN) {
/* On LTE we are effectively always attached; and
* the default bearer is established as soon as the
* network is joined.
*/
/* FIXME: query default profile number and APN
* instead of assuming profile 1 and ""
*/
ofono_gprs_cid_activated(gprs, 1 , "automatic");
}
return status;
}
static void ss_info_notify(struct qmi_result *result, void *user_data)
{
struct ofono_gprs *gprs = user_data;
@@ -62,10 +96,10 @@ static void ss_info_notify(struct qmi_result *result, void *user_data)
DBG("");
if (!extract_ss_info(result, &status))
return;
status = handle_ss_info(result, gprs);
ofono_gprs_status_notify(gprs, status);
if (status >= 0)
ofono_gprs_status_notify(gprs, status);
}
static void attach_detach_cb(struct qmi_result *result, void *user_data)
@@ -124,22 +158,26 @@ error:
static void get_ss_info_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
struct ofono_gprs *gprs = cbd->user;
ofono_gprs_status_cb_t cb = cbd->cb;
int status;
DBG("");
if (qmi_result_set_error(result, NULL)) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
return;
}
if (qmi_result_set_error(result, NULL))
goto error;
if (!extract_ss_info(result, &status)) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
return;
}
status = handle_ss_info(result, gprs);
if (status < 0)
goto error;
CALLBACK_WITH_SUCCESS(cb, status, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
static void qmi_attached_status(struct ofono_gprs *gprs,
@@ -150,6 +188,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
DBG("");
cbd->user = gprs;
if (qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
get_ss_info_cb, cbd, g_free) > 0)
return;
@@ -174,6 +213,13 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
data->nas = qmi_service_ref(service);
/*
* First get the SS info - the modem may already be connected,
* and the state-change notification may never arrive
*/
qmi_service_send(data->nas, QMI_NAS_GET_SS_INFO, NULL,
ss_info_notify, gprs, NULL);
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
ss_info_notify, gprs, NULL);
@@ -194,7 +240,8 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
ofono_gprs_set_data(gprs, data);
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, gprs, NULL);
qmi_service_create_shared(device, QMI_SERVICE_NAS,
create_nas_cb, gprs, NULL);
return 0;
}

View File

@@ -0,0 +1,38 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jonas Bonn. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "nas.h"
#include "src/common.h"
int qmi_nas_rat_to_tech(uint8_t rat)
{
switch (rat) {
case QMI_NAS_NETWORK_RAT_GSM:
return ACCESS_TECHNOLOGY_GSM;
case QMI_NAS_NETWORK_RAT_UMTS:
return ACCESS_TECHNOLOGY_UTRAN;
case QMI_NAS_NETWORK_RAT_LTE:
return ACCESS_TECHNOLOGY_EUTRAN;
}
return -1;
}

View File

@@ -19,6 +19,8 @@
*
*/
#include <stdint.h>
#define QMI_NAS_RESET 0 /* Reset NAS service state variables */
#define QMI_NAS_ABORT 1 /* Abort previously issued NAS command */
#define QMI_NAS_EVENT 2 /* Connection state report indication */
@@ -33,6 +35,8 @@
#define QMI_NAS_SS_INFO_IND 36 /* Current serving system info indication */
#define QMI_NAS_GET_HOME_INFO 37 /* Get info about home network */
#define QMI_NAS_SET_SYSTEM_SELECTION_PREF 51
#define QMI_NAS_GET_SYSTEM_SELECTION_PREF 52
/* Set NAS state report conditions */
#define QMI_NAS_PARAM_REPORT_SIGNAL_STRENGTH 0x10
@@ -63,7 +67,7 @@ struct qmi_nas_rf_info {
} __attribute__((__packed__));
/* Get the signal strength */
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x10
#define QMI_NAS_RESULT_SIGNAL_STRENGTH 0x01
/* Scan for visible network */
#define QMI_NAS_PARAM_NETWORK_MASK 0x10 /* uint8 bitmask */
@@ -95,6 +99,7 @@ struct qmi_nas_network_rat {
} __attribute__((__packed__)) info[0];
} __attribute__((__packed__));
#define QMI_NAS_NETWORK_RAT_NONE 0x00
#define QMI_NAS_NETWORK_RAT_GSM 0x04
#define QMI_NAS_NETWORK_RAT_UMTS 0x05
#define QMI_NAS_NETWORK_RAT_LTE 0x08
@@ -140,9 +145,29 @@ struct qmi_nas_current_plmn {
#define QMI_NAS_RESULT_LOCATION_AREA_CODE 0x1d /* uint16 */
#define QMI_NAS_RESULT_CELL_ID 0x1e /* uint32 */
#define QMI_NAS_ATTACH_STATUS_INVALID 0x00
#define QMI_NAS_ATTACH_STATUS_ATTACHED 0x01
#define QMI_NAS_ATTACH_STATUS_DETACHED 0x02
/* qmi_nas_serving_system.status */
#define QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED 0x00
#define QMI_NAS_REGISTRATION_STATE_REGISTERED 0x01
#define QMI_NAS_REGISTRATION_STATE_SEARCHING 0x02
#define QMI_NAS_REGISTRATION_STATE_DENIED 0x03
#define QMI_NAS_REGISTRATION_STATE_UNKNOWN 0x04
#define QMI_NAS_RESULT_3GGP_DST 0x1b
#define QMI_NAS_RESULT_3GPP_TIME 0x1c
struct qmi_nas_3gpp_time {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t timezone;
} __attribute__((__packed__));
/* cs_state/ps_state */
#define QMI_NAS_ATTACH_STATE_INVALID 0x00
#define QMI_NAS_ATTACH_STATE_ATTACHED 0x01
#define QMI_NAS_ATTACH_STATE_DETACHED 0x02
/* Get info about home network */
#define QMI_NAS_RESULT_HOME_NETWORK 0x01
@@ -152,3 +177,14 @@ struct qmi_nas_home_network {
uint8_t desc_len;
char desc[0];
} __attribute__((__packed__));
#define QMI_NAS_RAT_MODE_PREF_ANY (-1)
#define QMI_NAS_RAT_MODE_PREF_GSM (1 << 2)
#define QMI_NAS_RAT_MODE_PREF_UMTS (1 << 3)
#define QMI_NAS_RAT_MODE_PREF_LTE (1 << 4)
#define QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE 0x11
#define QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE 0x11
int qmi_nas_rat_to_tech(uint8_t rat);

View File

@@ -0,0 +1,286 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jonas Bonn. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <glib.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/netmon.h>
#include "qmi.h"
#include "nas.h"
#include "qmimodem.h"
#include "src/common.h"
struct netmon_data {
struct qmi_service *nas;
};
static void get_rssi_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
struct ofono_netmon *netmon = cbd->user;
ofono_netmon_cb_t cb = cbd->cb;
struct {
enum ofono_netmon_cell_type type;
int rssi;
int ber;
int rsrq;
int rsrp;
} props;
uint16_t len;
int16_t rsrp;
const struct {
int8_t value;
int8_t rat;
} __attribute__((__packed__)) *rsrq;
const struct {
uint16_t count;
struct {
uint8_t rssi;
int8_t rat;
} __attribute__((__packed__)) info[0];
} __attribute__((__packed__)) *rssi;
const struct {
uint16_t count;
struct {
uint16_t rate;
int8_t rat;
} __attribute__((__packed__)) info[0];
} __attribute__((__packed__)) *ber;
int i;
uint16_t num;
DBG("");
if (qmi_result_set_error(result, NULL)) {
CALLBACK_WITH_FAILURE(cb, cbd->data);
return;
}
/* RSSI */
rssi = qmi_result_get(result, 0x11, &len);
num = GUINT16_FROM_LE(rssi->count);
if (rssi) {
for (i = 0; i < num; i++) {
DBG("RSSI: %hhu on RAT %hhd",
rssi->info[i].rssi,
rssi->info[i].rat);
}
/* Get cell type from RSSI info... it will be the same
* for all the other entries
*/
props.type = qmi_nas_rat_to_tech(rssi->info[0].rat);
switch (rssi->info[0].rat) {
case QMI_NAS_NETWORK_RAT_GSM:
props.type = OFONO_NETMON_CELL_TYPE_GSM;
break;
case QMI_NAS_NETWORK_RAT_UMTS:
props.type = OFONO_NETMON_CELL_TYPE_UMTS;
break;
case QMI_NAS_NETWORK_RAT_LTE:
props.type = OFONO_NETMON_CELL_TYPE_LTE;
break;
default:
props.type = OFONO_NETMON_CELL_TYPE_GSM;
break;
}
props.rssi = (rssi->info[0].rssi + 113) / 2;
if (props.rssi > 31) props.rssi = 31;
if (props.rssi < 0) props.rssi = 0;
} else {
props.type = QMI_NAS_NETWORK_RAT_GSM;
props.rssi = -1;
}
/* Bit error rate */
ber = qmi_result_get(result, 0x15, &len);
num = GUINT16_FROM_LE(ber->count);
if (ber) {
for (i = 0; i < ber->count; i++) {
DBG("Bit error rate: %hu on RAT %hhd",
GUINT16_FROM_LE(ber->info[i].rate),
ber->info[i].rat);
}
props.ber = GUINT16_FROM_LE(ber->info[0].rate);
if (props.ber > 7)
props.ber = -1;
} else {
props.ber = -1;
}
/* LTE RSRQ */
rsrq = qmi_result_get(result, 0x16, &len);
if (rsrq) {
DBG("RSRQ: %hhd on RAT %hhd",
rsrq->value,
rsrq->rat);
if (rsrq->value == 0) {
props.rsrq = -1;
} else {
props.rsrq = (rsrq->value + 19) * 2;
if (props.rsrq > 34) props.rsrq = 34;
if (props.rsrq < 0) props.rsrq = 0;
}
} else {
props.rsrq = -1;
}
/* LTE RSRP */
if (qmi_result_get_int16(result, 0x18, &rsrp)) {
DBG("Got LTE RSRP: %hd", rsrp);
if (rsrp == 0) {
props.rsrp = -1;
} else {
props.rsrp = rsrp + 140;
if (props.rsrp > 97) props.rsrp = 97;
if (props.rsrp < 0) props.rsrp = 0;
}
} else {
props.rsrp = -1;
}
ofono_netmon_serving_cell_notify(netmon,
props.type,
OFONO_NETMON_INFO_RSSI, props.rssi,
OFONO_NETMON_INFO_BER, props.ber,
OFONO_NETMON_INFO_RSRQ, props.rsrq,
OFONO_NETMON_INFO_RSRP, props.rsrp,
OFONO_NETMON_INFO_INVALID);
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void qmi_netmon_request_update(struct ofono_netmon *netmon,
ofono_netmon_cb_t cb,
void *user_data)
{
struct netmon_data *data = ofono_netmon_get_data(netmon);
struct cb_data *cbd = cb_data_new(cb, user_data);
struct qmi_param *param;
DBG("");
cbd->user = netmon;
param = qmi_param_new();
if (!param)
goto out;
/* Request all signal strength items: mask=0xff */
qmi_param_append_uint16(param, 0x10, 255);
if (qmi_service_send(data->nas, QMI_NAS_GET_RSSI, param,
get_rssi_cb, cbd, g_free) > 0)
return;
qmi_param_free(param);
out:
CALLBACK_WITH_FAILURE(cb, cbd->data);
g_free(cbd);
}
static void create_nas_cb(struct qmi_service *service, void *user_data)
{
struct ofono_netmon *netmon = user_data;
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
DBG("");
if (!service) {
ofono_error("Failed to request NAS service");
ofono_netmon_remove(netmon);
return;
}
nmd->nas = qmi_service_ref(service);
ofono_netmon_register(netmon);
}
static int qmi_netmon_probe(struct ofono_netmon *netmon,
unsigned int vendor, void *user_data)
{
struct qmi_device *device = user_data;
struct netmon_data *nmd;
DBG("");
nmd = g_new0(struct netmon_data, 1);
ofono_netmon_set_data(netmon, nmd);
qmi_service_create_shared(device, QMI_SERVICE_NAS,
create_nas_cb, netmon, NULL);
return 0;
}
static void qmi_netmon_remove(struct ofono_netmon *netmon)
{
struct netmon_data *nmd = ofono_netmon_get_data(netmon);
DBG("");
ofono_netmon_set_data(netmon, NULL);
qmi_service_unregister_all(nmd->nas);
qmi_service_unref(nmd->nas);
g_free(nmd);
}
static struct ofono_netmon_driver driver = {
.name = "qmimodem",
.probe = qmi_netmon_probe,
.remove = qmi_netmon_remove,
.request_update = qmi_netmon_request_update,
};
void qmi_netmon_init(void)
{
ofono_netmon_driver_register(&driver);
}
void qmi_netmon_exit(void)
{
ofono_netmon_driver_unregister(&driver);
}

View File

@@ -23,6 +23,7 @@
#include <config.h>
#endif
#include <endian.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -43,18 +44,36 @@ struct netreg_data {
uint8_t current_rat;
};
static int rat_to_tech(uint8_t rat)
static bool extract_ss_info_time(
struct qmi_result *result,
struct ofono_network_time *time)
{
switch (rat) {
case QMI_NAS_NETWORK_RAT_GSM:
return ACCESS_TECHNOLOGY_GSM;
case QMI_NAS_NETWORK_RAT_UMTS:
return ACCESS_TECHNOLOGY_UTRAN;
case QMI_NAS_NETWORK_RAT_LTE:
return ACCESS_TECHNOLOGY_EUTRAN;
const struct qmi_nas_3gpp_time *time_3gpp = NULL;
uint8_t dst_3gpp;
bool dst_3gpp_valid;
uint16_t len;
/* parse 3gpp time & dst */
dst_3gpp_valid = qmi_result_get_uint8(result, QMI_NAS_RESULT_3GGP_DST,
&dst_3gpp);
time_3gpp = qmi_result_get(result, QMI_NAS_RESULT_3GPP_TIME, &len);
if (time_3gpp && len == sizeof(struct qmi_nas_3gpp_time) &&
dst_3gpp_valid) {
time->year = le16toh(time_3gpp->year);
time->mon = time_3gpp->month;
time->mday = time_3gpp->day;
time->hour = time_3gpp->hour;
time->min = time_3gpp->minute;
time->sec = time_3gpp->second;
time->utcoff = time_3gpp->timezone * 15 * 60;
time->dst = dst_3gpp;
return true;
}
return -1;
/* TODO: 3gpp2 */
return false;
}
static bool extract_ss_info(struct qmi_result *result, int *status,
@@ -64,7 +83,7 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
const struct qmi_nas_serving_system *ss;
const struct qmi_nas_current_plmn *plmn;
uint8_t i, roaming;
uint16_t value16, len;
uint16_t value16, len, opname_len;
uint32_t value32;
DBG("");
@@ -82,13 +101,13 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
for (i = 0; i < ss->radio_if_count; i++) {
DBG("radio in use %d", ss->radio_if[i]);
*tech = rat_to_tech(ss->radio_if[i]);
*tech = qmi_nas_rat_to_tech(ss->radio_if[i]);
}
if (qmi_result_get_uint8(result, QMI_NAS_RESULT_ROAMING_STATUS,
&roaming)) {
if (ss->status == 1 && roaming == 0)
*status = 5;
*status = NETWORK_REGISTRATION_STATUS_ROAMING;
}
if (!operator)
@@ -100,8 +119,21 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
GUINT16_FROM_LE(plmn->mcc));
snprintf(operator->mnc, OFONO_MAX_MNC_LENGTH + 1, "%02d",
GUINT16_FROM_LE(plmn->mnc));
strncpy(operator->name, plmn->desc, plmn->desc_len);
operator->name[plmn->desc_len] = '\0';
opname_len = plmn->desc_len;
if (opname_len > OFONO_MAX_OPERATOR_NAME_LENGTH)
opname_len = OFONO_MAX_OPERATOR_NAME_LENGTH;
/*
* Telit QMI modems can return non-utf-8 characters in
* plmn-desc. When that happens, libdbus will abort ofono.
* If non-utf-8 characters are detected, use mccmnc string.
*/
if (g_utf8_validate(plmn->desc, opname_len, NULL)) {
strncpy(operator->name, plmn->desc, opname_len);
operator->name[opname_len] = '\0';
} else
snprintf(operator->name, OFONO_MAX_OPERATOR_NAME_LENGTH,
"%s%s", operator->mcc, operator->mnc);
DBG("%s (%s:%s)", operator->name, operator->mcc, operator->mnc);
}
@@ -125,11 +157,15 @@ static bool extract_ss_info(struct qmi_result *result, int *status,
static void ss_info_notify(struct qmi_result *result, void *user_data)
{
struct ofono_netreg *netreg = user_data;
struct ofono_network_time net_time;
struct netreg_data *data = ofono_netreg_get_data(netreg);
int status, lac, cellid, tech;
DBG("");
if (extract_ss_info_time(result, &net_time))
ofono_netreg_time_notify(netreg, &net_time);
if (!extract_ss_info(result, &status, &lac, &cellid, &tech,
&data->operator))
return;
@@ -265,7 +301,7 @@ static void scan_nets_cb(struct qmi_result *result, void *user_data)
DBG("%03d:%02d %d", netrat->info[i].mcc, netrat->info[i].mnc,
netrat->info[i].rat);
list[i].tech = rat_to_tech(netrat->info[i].rat);
list[i].tech = qmi_nas_rat_to_tech(netrat->info[i].rat);
}
done:
@@ -357,7 +393,7 @@ static void qmi_register_manual(struct ofono_netreg *netreg,
info.mcc = atoi(mcc);
info.mnc = atoi(mnc);
info.rat = data->current_rat;
info.rat = QMI_NAS_NETWORK_RAT_NO_CHANGE;
qmi_param_append(param, QMI_NAS_PARAM_REGISTER_MANUAL_INFO,
sizeof(info), &info);
@@ -451,10 +487,11 @@ static void event_notify(struct qmi_result *result, void *user_data)
if (ss) {
int strength;
DBG("signal with %d dBm on %d", ss->dbm, ss->rat);
strength = dbm_to_strength(ss->dbm);
DBG("signal with %d%%(%d dBm) on %d",
strength, ss->dbm, ss->rat);
ofono_netreg_strength_notify(netreg, strength);
}
@@ -474,10 +511,17 @@ static void event_notify(struct qmi_result *result, void *user_data)
static void set_event_cb(struct qmi_result *result, void *user_data)
{
struct ofono_netreg *netreg = user_data;
struct netreg_data *data = ofono_netreg_get_data(netreg);
DBG("");
ofono_netreg_register(netreg);
qmi_service_register(data->nas, QMI_NAS_EVENT,
event_notify, netreg, NULL);
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
ss_info_notify, netreg, NULL);
}
static void create_nas_cb(struct qmi_service *service, void *user_data)
@@ -499,12 +543,6 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
data->nas = qmi_service_ref(service);
qmi_service_register(data->nas, QMI_NAS_EVENT,
event_notify, netreg, NULL);
qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND,
ss_info_notify, netreg, NULL);
param = qmi_param_new();
if (!param)
goto done;
@@ -543,7 +581,7 @@ static int qmi_netreg_probe(struct ofono_netreg *netreg,
ofono_netreg_set_data(netreg, data);
qmi_service_create(device, QMI_SERVICE_NAS,
qmi_service_create_shared(device, QMI_SERVICE_NAS,
create_nas_cb, netreg, NULL);
return 0;

View File

@@ -26,6 +26,8 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
@@ -33,12 +35,18 @@
#include <glib.h>
#include <ofono/log.h>
#include "qmi.h"
#include "ctl.h"
typedef void (*qmi_message_func_t)(uint16_t message, uint16_t length,
const void *buffer, void *user_data);
struct discovery {
qmi_destroy_func_t destroy;
};
struct qmi_device {
int ref_count;
int fd;
@@ -49,6 +57,7 @@ struct qmi_device {
GQueue *req_queue;
GQueue *control_queue;
GQueue *service_queue;
GQueue *discovery_queue;
uint8_t next_control_tid;
uint16_t next_service_tid;
qmi_debug_func_t debug_func;
@@ -60,6 +69,12 @@ struct qmi_device {
uint8_t version_count;
GHashTable *service_list;
unsigned int release_users;
qmi_shutdown_func_t shutdown_func;
void *shutdown_user_data;
qmi_destroy_func_t shutdown_destroy;
guint shutdown_source;
bool shutting_down : 1;
bool destroyed : 1;
};
struct qmi_service {
@@ -209,6 +224,14 @@ static gint __request_compare(gconstpointer a, gconstpointer b)
return req->tid - tid;
}
static void __discovery_free(gpointer data, gpointer user_data)
{
struct discovery *d = data;
qmi_destroy_func_t destroy = d->destroy;
destroy(d);
}
static void __notify_free(gpointer data, gpointer user_data)
{
struct qmi_notify *notify = data;
@@ -313,8 +336,12 @@ static const char *__service_type_to_string(uint8_t type)
return "UIM";
case QMI_SERVICE_PBM:
return "PBM";
case QMI_SERVICE_QCHAT:
return "QCHAT";
case QMI_SERVICE_RMTFS:
return "RMTFS";
case QMI_SERVICE_TEST:
return "TEST";
case QMI_SERVICE_LOC:
return "LOC";
case QMI_SERVICE_SAR:
@@ -326,9 +353,21 @@ static const char *__service_type_to_string(uint8_t type)
case QMI_SERVICE_TS:
return "TS";
case QMI_SERVICE_TMD:
return "TMS";
return "TMD";
case QMI_SERVICE_WDA:
return "WDA";
case QMI_SERVICE_CSVT:
return "CSVT";
case QMI_SERVICE_COEX:
return "COEX";
case QMI_SERVICE_PDC:
return "PDC";
case QMI_SERVICE_RFRPE:
return "RFRPE";
case QMI_SERVICE_DSD:
return "DSD";
case QMI_SERVICE_SSCTL:
return "SSCTL";
case QMI_SERVICE_CAT_OLD:
return "CAT";
case QMI_SERVICE_RMS:
@@ -758,7 +797,7 @@ static void handle_packet(struct qmi_device *device,
tid = GUINT16_FROM_LE(service->transaction);
if (service->type == 0x04 && tid == 0x0000) {
if (service->type == 0x04) {
handle_indication(device, hdr->service, hdr->client,
message, length, data);
return;
@@ -838,6 +877,21 @@ static void read_watch_destroy(gpointer user_data)
device->read_watch = 0;
}
static void __qmi_device_discovery_started(struct qmi_device *device,
struct discovery *d)
{
g_queue_push_tail(device->discovery_queue, d);
}
static void __qmi_device_discovery_complete(struct qmi_device *device,
struct discovery *d)
{
if (g_queue_remove(device->discovery_queue, d) != TRUE)
return;
__discovery_free(d, NULL);
}
static void service_destroy(gpointer data)
{
struct qmi_service *service = data;
@@ -891,6 +945,7 @@ struct qmi_device *qmi_device_new(int fd)
device->req_queue = g_queue_new();
device->control_queue = g_queue_new();
device->service_queue = g_queue_new();
device->discovery_queue = g_queue_new();
device->service_list = g_hash_table_new_full(g_direct_hash,
g_direct_equal, NULL, service_destroy);
@@ -927,6 +982,9 @@ void qmi_device_unref(struct qmi_device *device)
g_queue_foreach(device->req_queue, __request_free, NULL);
g_queue_free(device->req_queue);
g_queue_foreach(device->discovery_queue, __discovery_free, NULL);
g_queue_free(device->discovery_queue);
if (device->write_watch > 0)
g_source_remove(device->write_watch);
@@ -936,12 +994,18 @@ void qmi_device_unref(struct qmi_device *device)
if (device->close_on_unref)
close(device->fd);
if (device->shutdown_source)
g_source_remove(device->shutdown_source);
g_hash_table_destroy(device->service_list);
g_free(device->version_str);
g_free(device->version_list);
g_free(device);
if (device->shutting_down)
device->destroyed = true;
else
g_free(device);
}
void qmi_device_set_debug(struct qmi_device *device,
@@ -962,6 +1026,23 @@ void qmi_device_set_close_on_unref(struct qmi_device *device, bool do_close)
device->close_on_unref = do_close;
}
void qmi_result_print_tlvs(struct qmi_result *result)
{
const void *ptr = result->data;
uint16_t len = result->length;
while (len > QMI_TLV_HDR_SIZE) {
const struct qmi_tlv_hdr *tlv = ptr;
uint16_t tlv_length = GUINT16_FROM_LE(tlv->length);
DBG("tlv: 0x%02x len 0x%04x", tlv->type, tlv->length);
ptr += QMI_TLV_HDR_SIZE + tlv_length;
len -= QMI_TLV_HDR_SIZE + tlv_length;
}
}
static const void *tlv_get(const void *data, uint16_t size,
uint8_t type, uint16_t *length)
{
@@ -987,6 +1068,7 @@ static const void *tlv_get(const void *data, uint16_t size,
}
struct discover_data {
struct discovery super;
struct qmi_device *device;
qmi_discover_func_t func;
void *user_data;
@@ -994,6 +1076,21 @@ struct discover_data {
guint timeout;
};
static void discover_data_free(gpointer user_data)
{
struct discover_data *data = user_data;
if (data->timeout) {
g_source_remove(data->timeout);
data->timeout = 0;
}
if (data->destroy)
data->destroy(data->user_data);
g_free(data);
}
static void discover_callback(uint16_t message, uint16_t length,
const void *buffer, void *user_data)
{
@@ -1007,8 +1104,6 @@ static void discover_callback(uint16_t message, uint16_t length,
uint8_t count;
unsigned int i;
g_source_remove(data->timeout);
count = 0;
list = NULL;
@@ -1079,10 +1174,7 @@ done:
if (data->func)
data->func(count, list, data->user_data);
if (data->destroy)
data->destroy(data->user_data);
g_free(data);
__qmi_device_discovery_complete(data->device, &data->super);
}
static gboolean discover_reply(gpointer user_data)
@@ -1096,10 +1188,7 @@ static gboolean discover_reply(gpointer user_data)
data->func(device->version_count,
device->version_list, data->user_data);
if (data->destroy)
data->destroy(data->user_data);
g_free(data);
__qmi_device_discovery_complete(data->device, &data->super);
return FALSE;
}
@@ -1120,13 +1209,15 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
if (!data)
return false;
data->super.destroy = discover_data_free;
data->device = device;
data->func = func;
data->user_data = user_data;
data->destroy = destroy;
if (device->version_list) {
g_timeout_add_seconds(0, discover_reply, data);
data->timeout = g_timeout_add_seconds(0, discover_reply, data);
__qmi_device_discovery_started(device, &data->super);
return true;
}
@@ -1147,6 +1238,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
__request_submit(device, req, hdr->transaction);
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
__qmi_device_discovery_started(device, &data->super);
return true;
}
@@ -1177,63 +1269,256 @@ static void release_client(struct qmi_device *device,
__request_submit(device, req, hdr->transaction);
}
struct shutdown_data {
struct qmi_device *device;
qmi_shutdown_func_t func;
void *user_data;
qmi_destroy_func_t destroy;
};
static gboolean shutdown_reply(gpointer user_data)
static void shutdown_destroy(gpointer user_data)
{
struct shutdown_data *data = user_data;
struct qmi_device *device = user_data;
if (data->func)
data->func(data->user_data);
if (device->shutdown_destroy)
device->shutdown_destroy(device->shutdown_user_data);
g_free(data);
device->shutdown_source = 0;
return FALSE;
if (device->destroyed)
g_free(device);
}
static gboolean shutdown_timeout(gpointer user_data)
static gboolean shutdown_callback(gpointer user_data)
{
struct shutdown_data *data = user_data;
struct qmi_device *device = data->device;
struct qmi_device *device = user_data;
if (device->release_users > 0)
return TRUE;
return shutdown_reply(data);
device->shutting_down = true;
if (device->shutdown_func)
device->shutdown_func(device->shutdown_user_data);
device->shutting_down = true;
return FALSE;
}
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
struct shutdown_data *data;
if (!device)
return false;
if (device->shutdown_source > 0)
return false;
__debug_device(device, "device %p shutdown", device);
data = g_try_new0(struct shutdown_data, 1);
if (!data)
device->shutdown_source = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
0, shutdown_callback, device,
shutdown_destroy);
if (device->shutdown_source == 0)
return false;
data->device = device;
data->func = func;
data->user_data = user_data;
data->destroy = destroy;
if (device->release_users > 0)
g_timeout_add_seconds(0, shutdown_timeout, data);
else
g_timeout_add_seconds(0, shutdown_reply, data);
device->shutdown_func = func;
device->shutdown_user_data = user_data;
device->shutdown_destroy = destroy;
return true;
}
static bool get_device_file_name(struct qmi_device *device,
char *file_name, int size)
{
pid_t pid;
char temp[100];
ssize_t result;
if (size <= 0)
return false;
pid = getpid();
snprintf(temp, 100, "/proc/%d/fd/%d", (int) pid, device->fd);
temp[99] = 0;
result = readlink(temp, file_name, size - 1);
if (result == -1 || result >= size - 1) {
DBG("Error %d in readlink", errno);
return false;
}
file_name[result] = 0;
return true;
}
static char *get_first_dir_in_directory(char *dir_path)
{
DIR *dir;
struct dirent *dir_entry;
char *dir_name = NULL;
dir = opendir(dir_path);
if (!dir)
return NULL;
dir_entry = readdir(dir);
while ((dir_entry != NULL)) {
if (dir_entry->d_type == DT_DIR &&
strcmp(dir_entry->d_name, ".") != 0 &&
strcmp(dir_entry->d_name, "..") != 0) {
dir_name = g_strdup(dir_entry->d_name);
break;
}
dir_entry = readdir(dir);
}
closedir(dir);
return dir_name;
}
static char *get_device_interface(struct qmi_device *device)
{
char * const driver_names[] = { "usbmisc", "usb" };
unsigned int i;
char file_path[PATH_MAX];
char *file_name;
char *interface = NULL;
if (!get_device_file_name(device, file_path, sizeof(file_path)))
return NULL;
file_name = basename(file_path);
for (i = 0; i < G_N_ELEMENTS(driver_names) && !interface; i++) {
gchar *sysfs_path;
sysfs_path = g_strdup_printf("/sys/class/%s/%s/device/net/",
driver_names[i], file_name);
interface = get_first_dir_in_directory(sysfs_path);
g_free(sysfs_path);
}
return interface;
}
enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
struct qmi_device *device)
{
char *sysfs_path = NULL;
char *interface = NULL;
int fd = -1;
char value;
enum qmi_device_expected_data_format expected =
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
if (!device)
goto done;
interface = get_device_interface(device);
if (!interface) {
DBG("Error while getting interface name");
goto done;
}
/* Build sysfs file path and open it */
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
fd = open(sysfs_path, O_RDONLY);
if (fd < 0) {
/* maybe not supported by kernel */
DBG("Error %d in open(%s)", errno, sysfs_path);
goto done;
}
if (read(fd, &value, 1) != 1) {
DBG("Error %d in read(%s)", errno, sysfs_path);
goto done;
}
if (value == 'Y')
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP;
else if (value == 'N')
expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3;
else
DBG("Unexpected sysfs file contents");
done:
if (fd >= 0)
close(fd);
if (sysfs_path)
g_free(sysfs_path);
if (interface)
g_free(interface);
return expected;
}
bool qmi_device_set_expected_data_format(struct qmi_device *device,
enum qmi_device_expected_data_format format)
{
bool res = false;
char *sysfs_path = NULL;
char *interface = NULL;
int fd = -1;
char value;
if (!device)
goto done;
switch (format) {
case QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3:
value = 'N';
break;
case QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP:
value = 'Y';
break;
default:
DBG("Unhandled format: %d", (int) format);
goto done;
}
interface = get_device_interface(device);
if (!interface) {
DBG("Error while getting interface name");
goto done;
}
/* Build sysfs file path and open it */
sysfs_path = g_strdup_printf("/sys/class/net/%s/qmi/raw_ip", interface);
fd = open(sysfs_path, O_WRONLY);
if (fd < 0) {
/* maybe not supported by kernel */
DBG("Error %d in open(%s)", errno, sysfs_path);
goto done;
}
if (write(fd, &value, 1) != 1) {
DBG("Error %d in write(%s)", errno, sysfs_path);
goto done;
}
res = true;
done:
if (fd >= 0)
close(fd);
if (sysfs_path)
g_free(sysfs_path);
if (interface)
g_free(interface);
return res;
}
struct qmi_param *qmi_param_new(void)
{
struct qmi_param *param;
@@ -1435,6 +1720,27 @@ bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
return true;
}
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
int16_t *value)
{
const unsigned char *ptr;
uint16_t len, tmp;
if (!result || !type)
return false;
ptr = tlv_get(result->data, result->length, type, &len);
if (!ptr)
return false;
memcpy(&tmp, ptr, 2);
if (value)
*value = GINT16_FROM_LE(tmp);
return true;
}
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
uint16_t *value)
{
@@ -1501,6 +1807,7 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
}
struct service_create_data {
struct discovery super;
struct qmi_device *device;
bool shared;
uint8_t type;
@@ -1512,16 +1819,29 @@ struct service_create_data {
guint timeout;
};
static gboolean service_create_reply(gpointer user_data)
static void service_create_data_free(gpointer user_data)
{
struct service_create_data *data = user_data;
data->func(NULL, data->user_data);
if (data->timeout) {
g_source_remove(data->timeout);
data->timeout = 0;
}
if (data->destroy)
data->destroy(data->user_data);
g_free(data);
}
static gboolean service_create_reply(gpointer user_data)
{
struct service_create_data *data = user_data;
data->timeout = 0;
data->func(NULL, data->user_data);
__qmi_device_discovery_complete(data->device, &data->super);
return FALSE;
}
@@ -1537,8 +1857,6 @@ static void service_create_callback(uint16_t message, uint16_t length,
uint16_t len;
unsigned int hash_id;
g_source_remove(data->timeout);
result_code = tlv_get(buffer, length, 0x02, &len);
if (!result_code)
goto done;
@@ -1580,13 +1898,9 @@ static void service_create_callback(uint16_t message, uint16_t length,
done:
data->func(service, data->user_data);
qmi_service_unref(service);
if (data->destroy)
data->destroy(data->user_data);
g_free(data);
__qmi_device_discovery_complete(data->device, &data->super);
}
static void service_create_discover(uint8_t count,
@@ -1617,7 +1931,9 @@ static void service_create_discover(uint8_t count,
if (data->timeout > 0)
g_source_remove(data->timeout);
g_timeout_add_seconds(0, service_create_reply, data);
data->timeout = g_timeout_add_seconds(0,
service_create_reply, data);
__qmi_device_discovery_started(device, &data->super);
return;
}
@@ -1640,6 +1956,7 @@ static bool service_create(struct qmi_device *device, bool shared,
if (!data)
return false;
data->super.destroy = service_create_data_free;
data->device = device;
data->shared = shared;
data->type = type;
@@ -1662,6 +1979,7 @@ static bool service_create(struct qmi_device *device, bool shared,
done:
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
__qmi_device_discovery_started(device, &data->super);
return true;
}
@@ -1680,17 +1998,23 @@ bool qmi_service_create(struct qmi_device *device,
}
struct service_create_shared_data {
struct discovery super;
struct qmi_service *service;
struct qmi_device *device;
qmi_create_func_t func;
void *user_data;
qmi_destroy_func_t destroy;
guint timeout;
};
static gboolean service_create_shared_reply(gpointer user_data)
static void service_create_shared_data_free(gpointer user_data)
{
struct service_create_shared_data *data = user_data;
data->func(data->service, data->user_data);
if (data->timeout) {
g_source_remove(data->timeout);
data->timeout = 0;
}
qmi_service_unref(data->service);
@@ -1698,6 +2022,16 @@ static gboolean service_create_shared_reply(gpointer user_data)
data->destroy(data->user_data);
g_free(data);
}
static gboolean service_create_shared_reply(gpointer user_data)
{
struct service_create_shared_data *data = user_data;
data->timeout = 0;
data->func(data->service, data->user_data);
__qmi_device_discovery_complete(data->device, &data->super);
return FALSE;
}
@@ -1724,13 +2058,16 @@ bool qmi_service_create_shared(struct qmi_device *device,
if (!data)
return false;
data->super.destroy = service_create_shared_data_free;
data->service = qmi_service_ref(service);
data->device = device;
data->func = func;
data->user_data = user_data;
data->destroy = destroy;
g_timeout_add(0, service_create_shared_reply, data);
data->timeout = g_timeout_add(0,
service_create_shared_reply, data);
__qmi_device_discovery_started(device, &data->super);
return 0;
}

View File

@@ -35,18 +35,32 @@
#define QMI_SERVICE_CAT 10 /* Card application toolkit service */
#define QMI_SERVICE_UIM 11 /* UIM service */
#define QMI_SERVICE_PBM 12 /* Phonebook service */
#define QMI_SERVICE_QCHAT 13
#define QMI_SERVICE_RMTFS 14 /* Remote file system service */
#define QMI_SERVICE_TEST 15
#define QMI_SERVICE_LOC 16 /* Location service */
#define QMI_SERVICE_SAR 17 /* Specific absorption rate service */
#define QMI_SERVICE_CSD 20 /* Core sound driver service */
#define QMI_SERVICE_EFS 21 /* Embedded file system service */
#define QMI_SERVICE_TS 23 /* Thermal sensors service */
#define QMI_SERVICE_TMD 24 /* Thermal mitigation device service */
#define QMI_SERVICE_WDA 26 /* Wireless data administrative service */
#define QMI_SERVICE_CSVT 29
#define QMI_SERVICE_COEX 34
#define QMI_SERVICE_PDC 36 /* Persistent device configuration service */
#define QMI_SERVICE_RFRPE 41
#define QMI_SERVICE_DSD 42
#define QMI_SERVICE_SSCTL 43
#define QMI_SERVICE_CAT_OLD 224 /* Card application toolkit service */
#define QMI_SERVICE_RMS 225 /* Remote management service */
#define QMI_SERVICE_OMA 226 /* OMA device management service */
enum qmi_device_expected_data_format {
QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN,
QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3,
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP,
};
struct qmi_version {
uint8_t type;
uint16_t major;
@@ -82,6 +96,10 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
void *user_data, qmi_destroy_func_t destroy);
enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
struct qmi_device *device);
bool qmi_device_set_expected_data_format(struct qmi_device *device,
enum qmi_device_expected_data_format format);
struct qmi_param;
@@ -112,13 +130,15 @@ const void *qmi_result_get(struct qmi_result *result, uint8_t type,
char *qmi_result_get_string(struct qmi_result *result, uint8_t type);
bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type,
uint8_t *value);
bool qmi_result_get_int16(struct qmi_result *result, uint8_t type,
int16_t *value);
bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type,
uint16_t *value);
bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type,
uint32_t *value);
bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
uint64_t *value);
void qmi_result_print_tlvs(struct qmi_result *result);
struct qmi_service;

View File

@@ -41,12 +41,14 @@ static int qmimodem_init(void)
qmi_gprs_context_init();
qmi_radio_settings_init();
qmi_location_reporting_init();
qmi_netmon_init();
return 0;
}
static void qmimodem_exit(void)
{
qmi_netmon_exit();
qmi_location_reporting_exit();
qmi_radio_settings_exit();
qmi_gprs_context_exit();

View File

@@ -53,3 +53,6 @@ extern void qmi_radio_settings_exit(void);
extern void qmi_location_reporting_init(void);
extern void qmi_location_reporting_exit(void);
extern void qmi_netmon_init(void);
extern void qmi_netmon_exit(void);

View File

@@ -29,15 +29,202 @@
#include "qmi.h"
#include "nas.h"
#include "dms.h"
#include "qmimodem.h"
struct settings_data {
struct qmi_service *nas;
struct qmi_service *dms;
uint16_t major;
uint16_t minor;
};
static void get_system_selection_pref_cb(struct qmi_result *result,
void* user_data)
{
struct cb_data *cbd = user_data;
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
enum ofono_radio_access_mode mode = OFONO_RADIO_ACCESS_MODE_ANY;
uint16_t pref;
DBG("");
if (qmi_result_set_error(result, NULL)) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
return;
}
qmi_result_get_uint16(result,
QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE, &pref);
switch (pref) {
case QMI_NAS_RAT_MODE_PREF_GSM:
mode = OFONO_RADIO_ACCESS_MODE_GSM;
break;
case QMI_NAS_RAT_MODE_PREF_UMTS:
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
break;
case QMI_NAS_RAT_MODE_PREF_LTE:
mode = OFONO_RADIO_ACCESS_MODE_LTE;
break;
}
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
}
static void qmi_query_rat_mode(struct ofono_radio_settings *rs,
ofono_radio_settings_rat_mode_query_cb_t cb,
void *user_data)
{
struct settings_data *data = ofono_radio_settings_get_data(rs);
struct cb_data *cbd = cb_data_new(cb, user_data);
DBG("");
if (qmi_service_send(data->nas,
QMI_NAS_GET_SYSTEM_SELECTION_PREF, NULL,
get_system_selection_pref_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void set_system_selection_pref_cb(struct qmi_result *result,
void* user_data)
{
struct cb_data *cbd = user_data;
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
DBG("");
if (qmi_result_set_error(result, NULL)) {
CALLBACK_WITH_FAILURE(cb, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void qmi_set_rat_mode(struct ofono_radio_settings *rs,
enum ofono_radio_access_mode mode,
ofono_radio_settings_rat_mode_set_cb_t cb,
void *user_data)
{
struct settings_data *data = ofono_radio_settings_get_data(rs);
struct cb_data *cbd = cb_data_new(cb, user_data);
uint16_t pref = QMI_NAS_RAT_MODE_PREF_ANY;
struct qmi_param *param;
DBG("");
switch (mode) {
case OFONO_RADIO_ACCESS_MODE_ANY:
pref = QMI_NAS_RAT_MODE_PREF_ANY;
break;
case OFONO_RADIO_ACCESS_MODE_GSM:
pref = QMI_NAS_RAT_MODE_PREF_GSM;
break;
case OFONO_RADIO_ACCESS_MODE_UMTS:
pref = QMI_NAS_RAT_MODE_PREF_UMTS;
break;
case OFONO_RADIO_ACCESS_MODE_LTE:
pref = QMI_NAS_RAT_MODE_PREF_LTE;
break;
}
param = qmi_param_new();
if (!param) {
CALLBACK_WITH_FAILURE(cb, user_data);
return;
}
qmi_param_append_uint16(param, QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE,
pref);
if (qmi_service_send(data->nas,
QMI_NAS_SET_SYSTEM_SELECTION_PREF, param,
set_system_selection_pref_cb, cbd, g_free) > 0)
return;
qmi_param_free(param);
CALLBACK_WITH_FAILURE(cb, user_data);
g_free(cbd);
}
static void get_caps_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb;
const struct qmi_dms_device_caps *caps;
unsigned int available_rats;
uint16_t len;
uint8_t i;
DBG("");
if (qmi_result_set_error(result, NULL))
goto error;
caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, &len);
if (!caps)
goto error;
available_rats = 0;
for (i = 0; i < caps->radio_if_count; i++) {
switch (caps->radio_if[i]) {
case QMI_DMS_RADIO_IF_GSM:
available_rats |= OFONO_RADIO_ACCESS_MODE_GSM;
break;
case QMI_DMS_RADIO_IF_UMTS:
available_rats |= OFONO_RADIO_ACCESS_MODE_UMTS;
break;
case QMI_DMS_RADIO_IF_LTE:
available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
break;
}
}
CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
static void qmi_query_available_rats(struct ofono_radio_settings *rs,
ofono_radio_settings_available_rats_query_cb_t cb,
void *data)
{
struct settings_data *rsd = ofono_radio_settings_get_data(rs);
struct cb_data *cbd = cb_data_new(cb, data);
if (!rsd->dms)
goto error;
if (qmi_service_send(rsd->dms, QMI_DMS_GET_CAPS, NULL,
get_caps_cb, cbd, g_free) > 0)
return;
error:
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void create_dms_cb(struct qmi_service *service, void *user_data)
{
struct ofono_radio_settings *rs = user_data;
struct settings_data *data = ofono_radio_settings_get_data(rs);
DBG("");
if (!service)
return;
data->dms = qmi_service_ref(service);
}
static void create_nas_cb(struct qmi_service *service, void *user_data)
{
struct ofono_radio_settings *rs = user_data;
@@ -74,10 +261,12 @@ static int qmi_radio_settings_probe(struct ofono_radio_settings *rs,
ofono_radio_settings_set_data(rs, data);
qmi_service_create(device, QMI_SERVICE_NAS, create_nas_cb, rs, NULL);
qmi_service_create_shared(device, QMI_SERVICE_DMS,
create_dms_cb, rs, NULL);
qmi_service_create_shared(device, QMI_SERVICE_NAS,
create_nas_cb, rs, NULL);
return 0;
}
static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
@@ -99,6 +288,9 @@ static struct ofono_radio_settings_driver driver = {
.name = "qmimodem",
.probe = qmi_radio_settings_probe,
.remove = qmi_radio_settings_remove,
.set_rat_mode = qmi_set_rat_mode,
.query_rat_mode = qmi_query_rat_mode,
.query_available_rats = qmi_query_available_rats,
};
void qmi_radio_settings_init(void)

View File

@@ -30,6 +30,7 @@
#include <ofono/sim.h>
#include "qmi.h"
#include "dms.h"
#include "uim.h"
#include "qmimodem.h"
@@ -38,15 +39,36 @@
#define EF_STATUS_INVALIDATED 0
#define EF_STATUS_VALID 1
struct sim_data {
struct qmi_service *uim;
uint32_t event_mask;
/* max number of retry of commands that can temporary fail */
#define MAX_RETRY_COUNT 100
enum get_card_status_result {
GET_CARD_STATUS_RESULT_OK, /* No error */
GET_CARD_STATUS_RESULT_ERROR, /* Definitive error */
GET_CARD_STATUS_RESULT_TEMP_ERROR, /* error, a retry could work */
};
/* information from QMI_UIM_GET_CARD_STATUS command */
struct sim_status {
uint8_t card_state;
uint8_t app_type;
uint8_t passwd_state;
int retries[OFONO_SIM_PASSWORD_INVALID];
};
struct sim_data {
struct qmi_device *qmi_dev;
struct qmi_service *dms;
struct qmi_service *uim;
uint32_t event_mask;
uint8_t app_type;
uint32_t retry_count;
guint poll_source;
};
static void qmi_query_passwd_state(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *user_data);
static int create_fileid_data(uint8_t app_type, int fileid,
const unsigned char *path,
unsigned int path_len,
@@ -146,7 +168,7 @@ static void qmi_read_attributes(struct ofono_sim *sim, int fileid,
{
struct sim_data *data = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
unsigned char aid_data[2] = { 0x06, 0x00 };
unsigned char aid_data[2] = { 0x00, 0x00 };
unsigned char fileid_data[9];
int fileid_len;
struct qmi_param *param;
@@ -211,7 +233,7 @@ static void qmi_read_transparent(struct ofono_sim *sim,
{
struct sim_data *data = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
unsigned char aid_data[2] = { 0x06, 0x00 };
unsigned char aid_data[2] = { 0x00, 0x00 };
unsigned char read_data[4];
unsigned char fileid_data[9];
int fileid_len;
@@ -257,7 +279,7 @@ static void qmi_read_record(struct ofono_sim *sim,
{
struct sim_data *data = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
unsigned char aid_data[2] = { 0x06, 0x00 };
unsigned char aid_data[2] = { 0x00, 0x00 };
unsigned char read_data[4];
unsigned char fileid_data[9];
int fileid_len;
@@ -295,76 +317,214 @@ error:
g_free(cbd);
}
static void qmi_query_passwd_state(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *user_data)
static void write_generic_cb(struct qmi_result *result, void *user_data)
{
struct sim_data *data = ofono_sim_get_data(sim);
struct cb_data *cbd = user_data;
ofono_sim_write_cb_t cb = cbd->cb;
uint16_t len;
const uint8_t *card_result;
uint8_t sw1, sw2;
DBG("passwd state %d", data->passwd_state);
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
CALLBACK_WITH_FAILURE(cb, -1, user_data);
card_result = qmi_result_get(result, 0x10, &len);
if (card_result == NULL || len != 2) {
DBG("card_result: %p, len: %d", card_result, (int) len);
CALLBACK_WITH_FAILURE(cb, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, data->passwd_state, user_data);
}
sw1 = card_result[0];
sw2 = card_result[1];
static void qmi_query_pin_retries(struct ofono_sim *sim,
ofono_sim_pin_retries_cb_t cb, void *user_data)
{
struct sim_data *data = ofono_sim_get_data(sim);
DBG("%02x, %02x", sw1, sw2);
DBG("passwd state %d", data->passwd_state);
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
(sw1 == 0x90 && sw2 != 0x00)) {
struct ofono_error error;
if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
ofono_error("%s: error sw1 %02x sw2 %02x", __func__, sw1, sw2);
error.type = OFONO_ERROR_TYPE_SIM;
error.error = (sw1 << 8) | sw2;
cb(&error, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, data->retries, user_data);
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void card_setup(const struct qmi_uim_slot_info *slot,
static void write_generic(struct ofono_sim *sim,
uint16_t qmi_message, int fileid,
int start_or_recordnum,
int length, const unsigned char *value,
const unsigned char *path, unsigned int path_len,
ofono_sim_write_cb_t cb, void *user_data)
{
struct sim_data *data = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
unsigned char aid_data[2] = { 0x00, 0x00 };
unsigned char write_data[4 + length];
unsigned char fileid_data[9];
int fileid_len;
struct qmi_param *param;
DBG("file id 0x%04x path len %d", fileid, path_len);
fileid_len = create_fileid_data(data->app_type, fileid,
path, path_len, fileid_data);
if (fileid_len < 0)
goto error;
write_data[0] = start_or_recordnum & 0xff;
write_data[1] = (start_or_recordnum & 0xff00) >> 8;
write_data[2] = length & 0xff;
write_data[3] = (length & 0xff00) >> 8;
memcpy(&write_data[4], value, length);
param = qmi_param_new();
if (!param)
goto error;
qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
qmi_param_append(param, 0x02, fileid_len, fileid_data);
qmi_param_append(param, 0x03, 4 + length, write_data);
if (qmi_service_send(data->uim, qmi_message, param,
write_generic_cb, cbd, g_free) > 0)
return;
qmi_param_free(param);
error:
CALLBACK_WITH_FAILURE(cb, user_data);
g_free(cbd);
}
static void qmi_write_transparent(struct ofono_sim *sim,
int fileid, int start, int length,
const unsigned char *value,
const unsigned char *path,
unsigned int path_len,
ofono_sim_write_cb_t cb, void *user_data)
{
write_generic(sim, QMI_UIM_WRITE_TRANSPARENT, fileid, start,
length, value, path, path_len, cb, user_data);
}
static void qmi_write_linear(struct ofono_sim *sim,
int fileid, int record, int length,
const unsigned char *value,
const unsigned char *path,
unsigned int path_len,
ofono_sim_write_cb_t cb, void *user_data)
{
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, record,
length, value, path, path_len, cb, user_data);
}
static void qmi_write_cyclic(struct ofono_sim *sim,
int fileid, int length,
const unsigned char *value,
const unsigned char *path,
unsigned int path_len,
ofono_sim_write_cb_t cb, void *user_data)
{
write_generic(sim, QMI_UIM_WRITE_RECORD, fileid, 0,
length, value, path, path_len, cb, user_data);
}
static void get_imsi_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_imsi_cb_t cb = cbd->cb;
char *str;
DBG("");
if (qmi_result_set_error(result, NULL)) {
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
return;
}
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMSI);
if (!str) {
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
qmi_free(str);
}
static void qmi_read_imsi(struct ofono_sim *sim,
ofono_sim_imsi_cb_t cb, void *user_data)
{
struct sim_data *data = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
DBG("");
if (qmi_service_send(data->dms, QMI_DMS_GET_IMSI, NULL,
get_imsi_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
g_free(cbd);
}
/* Return true if a retry could give another (better) result */
static bool get_card_status(const struct qmi_uim_slot_info *slot,
const struct qmi_uim_app_info1 *info1,
const struct qmi_uim_app_info2 *info2,
struct sim_data *data)
struct sim_status *sim_stat)
{
data->card_state = slot->card_state;
data->app_type = info1->app_type;
bool need_retry = false;
sim_stat->card_state = slot->card_state;
sim_stat->app_type = info1->app_type;
switch (info1->app_state) {
case 0x02: /* PIN1 or UPIN is required */
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
break;
case 0x03: /* PUK1 or PUK for UPIN is required */
data->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
break;
case 0x04: /* Personalization state must be checked. */
/* This is temporary, we could retry and get another result */
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
need_retry = true;
break;
case 0x07: /* Ready */
data->passwd_state = OFONO_SIM_PASSWORD_NONE;
sim_stat->passwd_state = OFONO_SIM_PASSWORD_NONE;
break;
default:
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
DBG("info1->app_state:0x%x: OFONO_SIM_PASSWORD_INVALID",
info1->app_state);
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
break;
}
data->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
data->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
data->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
data->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
sim_stat->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
return need_retry;
}
static void get_card_status_cb(struct qmi_result *result, void *user_data)
static enum get_card_status_result handle_get_card_status_result(
struct qmi_result *result, struct sim_status *sim_stat)
{
struct ofono_sim *sim = user_data;
struct sim_data *data = ofono_sim_get_data(sim);
const void *ptr;
const struct qmi_uim_card_status *status;
uint16_t len, offset;
uint8_t i;
DBG("");
enum get_card_status_result res = GET_CARD_STATUS_RESULT_ERROR;
if (qmi_result_set_error(result, NULL))
goto done;
@@ -397,15 +557,211 @@ static void get_card_status_cb(struct qmi_result *result, void *user_data)
index = GUINT16_FROM_LE(status->index_gw_pri);
if ((index & 0xff) == i && (index >> 8) == n)
card_setup(slot, info1, info2, data);
if ((index & 0xff) == i && (index >> 8) == n) {
if (get_card_status(slot, info1, info2,
sim_stat))
res = GET_CARD_STATUS_RESULT_TEMP_ERROR;
else
res = GET_CARD_STATUS_RESULT_OK;
}
}
}
done:
return res;
}
static gboolean query_passwd_state_retry(gpointer userdata)
{
struct cb_data *cbd = userdata;
ofono_sim_passwd_cb_t cb = cbd->cb;
struct ofono_sim *sim = cbd->user;
struct sim_data *data = ofono_sim_get_data(sim);
data->poll_source = 0;
qmi_query_passwd_state(sim, cb, cbd->data);
return FALSE;
}
static void query_passwd_state_cb(struct qmi_result *result,
void *user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_passwd_cb_t cb = cbd->cb;
struct ofono_sim *sim = cbd->user;
struct sim_data *data = ofono_sim_get_data(sim);
struct sim_status sim_stat;
enum get_card_status_result res;
struct cb_data *retry_cbd;
res = handle_get_card_status_result(result, &sim_stat);
switch (res) {
case GET_CARD_STATUS_RESULT_OK:
DBG("passwd state %d", sim_stat.passwd_state);
data->retry_count = 0;
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, cbd->data);
break;
case GET_CARD_STATUS_RESULT_TEMP_ERROR:
data->retry_count++;
if (data->retry_count > MAX_RETRY_COUNT) {
DBG("Failed after %d attempts", data->retry_count);
data->retry_count = 0;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
} else {
DBG("Retry command");
retry_cbd = cb_data_new(cb, cbd->data);
retry_cbd->user = sim;
data->poll_source = g_timeout_add(20,
query_passwd_state_retry,
retry_cbd);
}
break;
case GET_CARD_STATUS_RESULT_ERROR:
DBG("Command failed");
data->retry_count = 0;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
break;
}
}
static void qmi_query_passwd_state(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *user_data)
{
struct sim_data *data = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
DBG("");
cbd->user = sim;
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
query_passwd_state_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
g_free(cbd);
}
static void query_pin_retries_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_pin_retries_cb_t cb = cbd->cb;
struct sim_status sim_stat;
DBG("");
if (handle_get_card_status_result(result, &sim_stat) !=
GET_CARD_STATUS_RESULT_OK) {
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, sim_stat.retries, cbd->data);
}
static void qmi_query_pin_retries(struct ofono_sim *sim,
ofono_sim_pin_retries_cb_t cb, void *user_data)
{
struct sim_data *data = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
DBG("");
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
query_pin_retries_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
g_free(cbd);
}
static void pin_send_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
DBG("");
if (qmi_result_set_error(result, NULL)) {
CALLBACK_WITH_FAILURE(cb, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void qmi_pin_send(struct ofono_sim *sim, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *user_data)
{
struct sim_data *data = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
int passwd_len;
struct qmi_param *param;
struct qmi_uim_param_message_info *info_data;
unsigned char session_info_data[2];
DBG("");
if (!passwd)
goto error;
passwd_len = strlen(passwd);
if (passwd_len <= 0 || passwd_len > 0xFF)
goto error;
param = qmi_param_new();
if (!param)
goto error;
/* param info */
info_data = alloca(2 + passwd_len);
info_data->pin_id = 0x01; /* PIN 1 */
info_data->length = (uint8_t) passwd_len;
memcpy(info_data->pin_value, passwd, passwd_len);
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_INFO, 2 + passwd_len,
info_data);
/* param Session Information */
session_info_data[0] = 0x6;
session_info_data[1] = 0x0;
qmi_param_append(param, QMI_UIM_PARAM_MESSAGE_SESSION_INFO, 2,
session_info_data);
if (qmi_service_send(data->uim, QMI_UIM_VERIFY_PIN, param,
pin_send_cb, cbd, g_free) > 0)
return;
qmi_param_free(param);
error:
CALLBACK_WITH_FAILURE(cb, cbd->data);
g_free(cbd);
}
static void get_card_status_cb(struct qmi_result *result, void *user_data)
{
struct ofono_sim *sim = user_data;
struct sim_data *data = ofono_sim_get_data(sim);
struct sim_status sim_stat;
DBG("");
if (handle_get_card_status_result(result, &sim_stat) !=
GET_CARD_STATUS_RESULT_OK) {
data->app_type = 0; /* Unknown */
sim_stat.card_state = 0x00; /* Absent */
} else {
data->app_type = sim_stat.app_type;
}
ofono_sim_register(sim);
switch (data->card_state) {
switch (sim_stat.card_state) {
case 0x00: /* Absent */
case 0x02: /* Error */
break;
@@ -465,30 +821,44 @@ static void create_uim_cb(struct qmi_service *service, void *user_data)
return;
error:
qmi_service_unref(data->uim);
ofono_sim_remove(sim);
}
static void create_dms_cb(struct qmi_service *service, void *user_data)
{
struct ofono_sim *sim = user_data;
struct sim_data *data = ofono_sim_get_data(sim);
DBG("");
if (!service) {
ofono_error("Failed to request DMS service");
ofono_sim_remove(sim);
return;
}
data->dms = qmi_service_ref(service);
qmi_service_create(data->qmi_dev, QMI_SERVICE_UIM, create_uim_cb, sim,
NULL);
}
static int qmi_sim_probe(struct ofono_sim *sim,
unsigned int vendor, void *user_data)
{
struct qmi_device *device = user_data;
struct sim_data *data;
int i;
DBG("");
data = g_new0(struct sim_data, 1);
data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
data->retries[i] = -1;
data->qmi_dev = device;
ofono_sim_set_data(sim, data);
qmi_service_create(device, QMI_SERVICE_UIM, create_uim_cb, sim, NULL);
qmi_service_create_shared(device, QMI_SERVICE_DMS,
create_dms_cb, sim, NULL);
return 0;
}
@@ -501,9 +871,18 @@ static void qmi_sim_remove(struct ofono_sim *sim)
ofono_sim_set_data(sim, NULL);
qmi_service_unregister_all(data->uim);
if (data->poll_source > 0)
g_source_remove(data->poll_source);
qmi_service_unref(data->uim);
if (data->uim) {
qmi_service_unregister_all(data->uim);
qmi_service_unref(data->uim);
data->uim = NULL;
}
if (data->dms) {
qmi_service_unregister_all(data->dms);
qmi_service_unref(data->dms);
}
g_free(data);
}
@@ -516,8 +895,13 @@ static struct ofono_sim_driver driver = {
.read_file_transparent = qmi_read_transparent,
.read_file_linear = qmi_read_record,
.read_file_cyclic = qmi_read_record,
.write_file_transparent = qmi_write_transparent,
.write_file_linear = qmi_write_linear,
.write_file_cyclic = qmi_write_cyclic,
.read_imsi = qmi_read_imsi,
.query_passwd_state = qmi_query_passwd_state,
.query_pin_retries = qmi_query_pin_retries,
.send_passwd = qmi_pin_send,
};
void qmi_sim_init(void)

View File

@@ -277,7 +277,7 @@ static void qmi_bearer_query(struct ofono_sms *sms,
DBG("");
if (data->major < 1 && data->minor < 2)
if (data->major < 1 || (data->major == 1 && data->minor < 2))
goto error;
if (qmi_service_send(data->wms, QMI_WMS_GET_DOMAIN_PREF, NULL,
@@ -315,7 +315,7 @@ static void qmi_bearer_set(struct ofono_sms *sms, int bearer,
DBG("bearer %d", bearer);
if (data->major < 1 && data->minor < 2)
if (data->major < 1 || (data->major == 1 && data->minor < 2))
goto error;
domain = bearer_to_domain(bearer);
@@ -411,7 +411,7 @@ static void get_routes_cb(struct qmi_result *result, void *user_data)
new_list->count = GUINT16_TO_LE(1);
new_list->route[0].msg_type = QMI_WMS_MSG_TYPE_P2P;
new_list->route[0].msg_class = QMI_WMS_MSG_CLASS_NONE;
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NV;
new_list->route[0].storage_type = QMI_WMS_STORAGE_TYPE_NONE;
new_list->route[0].action = QMI_WMS_ACTION_TRANSFER_AND_ACK;
param = qmi_param_new();

View File

@@ -25,6 +25,8 @@
#define QMI_UIM_WRITE_RECORD 35 /* Write a record */
#define QMI_UIM_GET_FILE_ATTRIBUTES 36 /* Get file attributes */
#define QMI_UIM_VERIFY_PIN 38 /* Verify PIN */
#define QMI_UIM_EVENT_REGISTRATION 46 /* Register for indications */
#define QMI_UIM_GET_CARD_STATUS 47 /* Get card status */
@@ -91,3 +93,12 @@ struct qmi_uim_file_attributes {
uint16_t raw_len;
uint8_t raw_value[0];
} __attribute__((__packed__));
/* Verify PIN parameter */
#define QMI_UIM_PARAM_MESSAGE_SESSION_INFO 0x01
#define QMI_UIM_PARAM_MESSAGE_INFO 0x02
struct qmi_uim_param_message_info {
uint8_t pin_id;
uint8_t length;
uint8_t pin_value[0];
} __attribute__((__packed__));

View File

@@ -0,0 +1,25 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Kerlink SA. 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.
*
*/
#define QMI_WDA_SET_DATA_FORMAT 32 /* Set data format */
#define QMI_WDA_GET_DATA_FORMAT 33 /* Get data format */
/* Get and set data format interface */
#define QMI_WDA_LL_PROTOCOL 0x11 /* uint32_t */
#define QMI_WDA_DATA_LINK_PROTOCOL_UNKNOWN 0
#define QMI_WDA_DATA_LINK_PROTOCOL_802_3 1
#define QMI_WDA_DATA_LINK_PROTOCOL_RAW_IP 2

View File

@@ -30,6 +30,13 @@
/* Start WDS network interface */
#define QMI_WDS_PARAM_APN 0x14 /* string */
#define QMI_WDS_PARAM_IP_FAMILY 0x19 /* uint8 */
#define QMI_WDS_PARAM_USERNAME 0x17 /* string */
#define QMI_WDS_PARAM_PASSWORD 0x18 /* string */
#define QMI_WDS_PARAM_AUTHENTICATION_PREFERENCE 0x16 /* uint8 */
#define QMI_WDS_AUTHENTICATION_NONE 0x0
#define QMI_WDS_AUTHENTICATION_PAP 0x1
#define QMI_WDS_AUTHENTICATION_CHAP 0x2
#define QMI_WDS_RESULT_PKT_HANDLE 0x01 /* uint32 */
@@ -51,10 +58,12 @@ struct qmi_wds_notify_conn_status {
/* Get the runtime data session settings */
#define QMI_WDS_RESULT_PDP_TYPE 0x11 /* uint8 */
#define QMI_WDS_RESULT_APN 0x14 /* string */
#define QMI_WDS_RESULT_PRIMARY_DNS 0x15 /* uint32 IPv4 */
#define QMI_WDS_RESULT_SECONDARY_DNS 0x16 /* uint32 IPv4 */
#define QMI_WDS_RESULT_IP_ADDRESS 0x1e /* uint32 IPv4 */
#define QMI_WDS_RESULT_GATEWAY 0x20 /* uint32 IPv4 */
#define QMI_WDS_RESULT_GATEWAY_NETMASK 0x21 /* uint32 IPv4 */
#define QMI_WDS_RESULT_IP_FAMILY 0x2b /* uint8 */
#define QMI_WDS_PDP_TYPE_IPV4 0x00

View File

@@ -62,6 +62,7 @@ struct qmi_wms_param_message {
#define QMI_WMS_STORAGE_TYPE_UIM 0
#define QMI_WMS_STORAGE_TYPE_NV 1
#define QMI_WMS_STORAGE_TYPE_UNKNOWN 2
#define QMI_WMS_STORAGE_TYPE_NONE 255
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1

View File

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

View File

@@ -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-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,15 +23,19 @@
#include <grilio_request.h>
#include <grilio_parser.h>
#include <gutil_idlepool.h>
#include <gutil_misc.h>
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
#define MAX_RETRIES (5)
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 +64,36 @@ 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 const char *ril_cell_info_int_format(int value, const char *format)
{
if (value == SAILFISH_CELL_INVALID_VALUE) {
return "";
} else {
static GUtilIdlePool *ril_cell_info_pool = NULL;
GUtilIdlePool *pool = gutil_idle_pool_get(&ril_cell_info_pool);
char *str = g_strdup_printf(format, value);
gutil_idle_pool_add(pool, str, g_free);
return str;
}
}
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
{
while (l1 && l2) {
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,121 +104,166 @@ 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 = SAILFISH_CELL_INVALID_VALUE;
gsm->bsic = SAILFISH_CELL_INVALID_VALUE;
/* Optional RIL_GSM_SignalStrength_v12 part */
gsm->timingAdvance = SAILFISH_CELL_INVALID_VALUE;
/* 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%s%s%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(gsm->mcc, ",mcc=%d"),
ril_cell_info_int_format(gsm->mnc, ",mnc=%d"),
ril_cell_info_int_format(gsm->lac, ",lac=%d"),
ril_cell_info_int_format(gsm->cid, ",cid=%d"),
ril_cell_info_int_format(gsm->arfcn, ",arfcn=%d"),
ril_cell_info_int_format(gsm->bsic, ",bsic=%d"),
ril_cell_info_int_format(gsm->signalStrength,
",strength=%d"),
ril_cell_info_int_format(gsm->bitErrorRate, ",err=%d"),
ril_cell_info_int_format(gsm->timingAdvance, ",t=%d"));
cell->type = SAILFISH_CELL_TYPE_GSM;
cell->registered = registered;
return cell;
}
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 = SAILFISH_CELL_INVALID_VALUE;
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
grilio_parser_get_int32(rilp, &wcdma->lac) &&
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;
DBG("[wcdma] reg=%d%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(wcdma->mcc, ",mcc=%d"),
ril_cell_info_int_format(wcdma->mnc, ",mnc=%d"),
ril_cell_info_int_format(wcdma->lac, ",lac=%d"),
ril_cell_info_int_format(wcdma->cid, ",cid=%d"),
ril_cell_info_int_format(wcdma->psc, ",psc=%d"),
ril_cell_info_int_format(wcdma->signalStrength,
",strength=%d"),
ril_cell_info_int_format(wcdma->bitErrorRate,
",err=%d"));
cell->type = SAILFISH_CELL_TYPE_WCDMA;
cell->registered = registered;
return cell;
}
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 = SAILFISH_CELL_INVALID_VALUE;
if (grilio_parser_get_int32(rilp, &lte->mcc) &&
grilio_parser_get_int32(rilp, &lte->mnc) &&
grilio_parser_get_int32(rilp, &lte->ci) &&
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) &&
grilio_parser_get_int32(rilp, &lte->rssnr) &&
grilio_parser_get_int32(rilp, &lte->cqi) &&
grilio_parser_get_int32(rilp, &lte->timingAdvance)) {
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
"strength=%d,rsrp=%d,rsrq=0x%x,rssnr=0x%x,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;
DBG("[lte] reg=%d%s%s%s%s%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(lte->mcc, ",mcc=%d"),
ril_cell_info_int_format(lte->mnc, ",mnc=%d"),
ril_cell_info_int_format(lte->ci, ",ci=%d"),
ril_cell_info_int_format(lte->pci, ",pci=%d"),
ril_cell_info_int_format(lte->tac, ",tac=%d"),
ril_cell_info_int_format(lte->signalStrength,
",strength=%d"),
ril_cell_info_int_format(lte->rsrp, ",rsrp=%d"),
ril_cell_info_int_format(lte->rsrq, ",rsrq=%d"),
ril_cell_info_int_format(lte->rssnr, ",rssnr=%d"),
ril_cell_info_int_format(lte->cqi, ",cqi=%d"),
ril_cell_info_int_format(lte->timingAdvance, ",t=%d"));
cell->type = SAILFISH_CELL_TYPE_LTE;
cell->registered = registered;
return cell;
}
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 +278,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 +299,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 +320,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, (status == RIL_E_SUCCESS) ?
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
}
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_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
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 +360,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_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
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 +374,22 @@ 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) ?
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self,
(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) {
ril_cell_info_update_rate(self);
}
ril_cell_info_update_rate(RIL_CELL_INFO(arg));
}
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 +407,153 @@ 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;
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) {
ril_cell_info_refresh(self);
if (priv->sim_card_ready) {
ril_cell_info_update_rate(self);
}
self->sim_card_ready = ril_sim_card_ready(sim);
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
ril_cell_info_refresh(self);
ril_cell_info_update_rate(self);
}
/* 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_CAST(info, struct ril_cell_info, info);
}
static void ril_cell_info_ref_proc(struct sailfish_cell_info *info)
{
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;
}
}
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *self,
ril_cell_info_cb_t cb, void *arg)
static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
gulong id)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_CELLS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_cell_info_remove_handler(struct ril_cell_info *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
if (G_LIKELY(id)) {
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
}
}
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 *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) {
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));
}
self->sim_card_ready = ril_sim_card_ready(sim_card);
ril_cell_info_refresh(self);
ril_cell_info_update_rate(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 +563,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-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,13 +14,20 @@
*/
#include "ril_config.h"
#include "ril_util.h"
#include "ril_log.h"
#include <gutil_intarray.h>
#include <gutil_ints.h>
#include <gutil_misc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* Utilities for parsing ril_subscription.conf */
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);
@@ -32,6 +39,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)
{
@@ -109,23 +141,74 @@ 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);
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();
GUtilIntArray *array = gutil_int_array_new();
char **values, **ptr;
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(value, '#');
if (comment) *comment = 0;
values = g_strsplit(value, ",", -1);
ptr = values;
while (*ptr) {
const char *str = *ptr++;
char *end = NULL;
long ival = strtol(str, &end, 0);
int val;
if (str[0] && !end[0]) {
gutil_int_array_append(array, ival);
if (gutil_parse_int(*ptr++, 0, &val)) {
gutil_int_array_append(array, val);
}
}
@@ -141,7 +224,7 @@ 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);
GString *buf = g_string_new(NULL);
for (i=0; i<n; i++) {
if (buf->len > 0) {
@@ -154,6 +237,337 @@ char *ril_config_ints_to_string(GUtilInts *ints, char separator)
return NULL;
}
/**
* The ril_config_merge_files() function does the following:
*
* 1. Loads the specified key file (say, "/etc/foo.conf")
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
* for the files with the same suffix as the main file (e.g. "*.conf")
* 3. Sorts the files from the subdirectory (alphabetically)
* 4. Merges the contents of the additional files with the main file
* according to their sort order.
*
* When the entries are merged, keys and groups overwrite the exising
* ones by default. Keys can be suffixed with special characters to
* remove or modify the existing entries instead:
*
* ':' Sets the (default) value if the key is missing
* '+' Appends values to the string list
* '?' Appends only new (non-existent) values to the string list
* '-' Removes the values from the string list
*
* Both keys and groups can be prefixed with '!' to remove the entire key
* or group.
*
* For example if we merge these two files:
*
* /etc/foo.conf:
*
* [foo]
* a=1
* b=2,3
* c=4
* d=5
* [bar]
* e=5
*
* /etc/foo.d/bar.conf:
*
* [foo]
* a+=2
* b-=2
* c=5
* !d
* [!bar]
*
* we end up with this:
*
* [foo]
* a=1
* b=2,3
* c=5
*
* Not that the list separator is assumed to be ',' (rather than default ';').
* The keyfile passed to ril_config_merge_files() should use the same list
* separator, because the default values are copied from the config files
* as is.
*/
static gint ril_config_sort_files(gconstpointer a, gconstpointer b)
{
/* The comparison function for g_ptr_array_sort() doesn't take
* the pointers from the array as arguments, it takes pointers
* to the pointers in the array. */
return strcmp(*(char**)a, *(char**)b);
}
static char **ril_config_collect_files(const char *path, const char *suffix)
{
/* Returns sorted list of regular files in the directory,
* optionally having the specified suffix (e.g. ".conf").
* Returns NULL if nothing appropriate has been found. */
char **files = NULL;
DIR *d = opendir(path);
if (d) {
GPtrArray *list = g_ptr_array_new();
const struct dirent *p;
while ((p = readdir(d)) != NULL) {
/* No need to even stat . and .. */
if (strcmp(p->d_name, ".") &&
strcmp(p->d_name, "..") && (!suffix ||
g_str_has_suffix(p->d_name, suffix))) {
struct stat st;
char *buf = g_strconcat(path, "/", p->d_name,
NULL);
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
g_ptr_array_add(list, buf);
} else {
g_free(buf);
}
}
}
if (list->len > 0) {
g_ptr_array_sort(list, ril_config_sort_files);
g_ptr_array_add(list, NULL);
files = (char**)g_ptr_array_free(list, FALSE);
} else {
g_ptr_array_free(list, TRUE);
}
closedir(d);
}
return files;
}
static int ril_config_list_find(char **list, gsize len, const char *value)
{
guint i;
for (i = 0; i < len; i++) {
if (!strcmp(list[i], value)) {
return i;
}
}
return -1;
}
static void ril_config_list_append(GKeyFile *conf, GKeyFile *k,
const char *group, const char *key,
char **values, gsize n, gboolean unique)
{
/* Note: will steal strings from values */
if (n > 0) {
int i;
gsize len = 0;
gchar **list = g_key_file_get_string_list(conf, group, key,
&len, NULL);
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
for (i = 0; i < (int)len; i++) {
g_ptr_array_add(newlist, list[i]);
}
for (i = 0; i < (int)n; i++) {
char *val = values[i];
if (!unique || ril_config_list_find((char**)
newlist->pdata, newlist->len, val) < 0) {
/* Move the string to the new list */
g_ptr_array_add(newlist, val);
memmove(values + i, values + i + 1,
sizeof(char*) * (n - i));
i--;
n--;
}
}
if (newlist->len > len) {
g_key_file_set_string_list(conf, group, key,
(const gchar * const *) newlist->pdata,
newlist->len);
}
/* Strings are deallocated by GPtrArray */
g_ptr_array_free(newlist, TRUE);
g_free(list);
}
}
static void ril_config_list_remove(GKeyFile *conf, GKeyFile *k,
const char *group, const char *key, char **values, gsize n)
{
if (n > 0) {
gsize len = 0;
gchar **list = g_key_file_get_string_list(conf, group, key,
&len, NULL);
if (len > 0) {
gsize i;
const gsize oldlen = len;
for (i = 0; i < n; i++) {
int pos;
/* Remove all matching values */
while ((pos = ril_config_list_find(list, len,
values[i])) >= 0) {
g_free(list[pos]);
memmove(list + pos, list + pos + 1,
sizeof(char*) * (len - pos));
len--;
}
}
if (len < oldlen) {
g_key_file_set_string_list(conf, group, key,
(const gchar * const *) list, len);
}
}
g_strfreev(list);
}
}
static void ril_config_merge_group(GKeyFile *conf, GKeyFile *k,
const char *group)
{
gsize i, n = 0;
char **keys = g_key_file_get_keys(k, group, &n, NULL);
for (i=0; i<n; i++) {
char *key = keys[i];
if (key[0] == '!') {
if (key[1]) {
g_key_file_remove_key(conf, group, key+1, NULL);
}
} else {
const gsize len = strlen(key);
const char last = (len > 0) ? key[len-1] : 0;
if (last == '+' || last == '?') {
gsize count = 0;
gchar **values = g_key_file_get_string_list(k,
group, key, &count, NULL);
key[len-1] = 0;
ril_config_list_append(conf, k, group, key,
values, count, last == '?');
g_strfreev(values);
} else if (last == '-') {
gsize count = 0;
gchar **values = g_key_file_get_string_list(k,
group, key, &count, NULL);
key[len-1] = 0;
ril_config_list_remove(conf, k, group, key,
values, count);
g_strfreev(values);
} else {
/* Overwrite the value (it must exist in k) */
gchar *value = g_key_file_get_value(k, group,
key, NULL);
if (last == ':') {
/* Default value */
key[len-1] = 0;
if (!g_key_file_has_key(conf,
group, key, NULL)) {
g_key_file_set_value(conf,
group, key, value);
}
} else {
g_key_file_set_value(conf, group, key,
value);
}
g_free(value);
}
}
}
g_strfreev(keys);
}
static void ril_config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
{
gsize i, n = 0;
char **groups = g_key_file_get_groups(k, &n);
for (i=0; i<n; i++) {
const char *group = groups[i];
if (group[0] == '!') {
g_key_file_remove_group(conf, group + 1, NULL);
} else {
ril_config_merge_group(conf, k, group);
}
}
g_strfreev(groups);
}
static void ril_config_merge_file(GKeyFile *conf, const char *file)
{
GKeyFile *k = g_key_file_new();
g_key_file_set_list_separator(k, ',');
if (g_key_file_load_from_file(k, file, 0, NULL)) {
ril_config_merge_keyfile(conf, k);
}
g_key_file_unref(k);
}
void ril_config_merge_files(GKeyFile *conf, const char *file)
{
if (conf && file && file[0]) {
char *dot = strrchr(file, '.');
const char *suffix;
char *dir;
char **files;
if (!dot) {
dir = g_strconcat(file, ".d", NULL);
suffix = NULL;
} else if (!dot[1]) {
dir = g_strconcat(file, "d", NULL);
suffix = NULL;
} else {
/* 2 bytes for ".d" and 1 for NULL terminator */
dir = g_malloc(dot - file + 3);
strncpy(dir, file, dot - file);
strcpy(dir + (dot - file), ".d");
suffix = dot + 1;
}
files = ril_config_collect_files(dir, suffix);
g_free(dir);
/* Load the main config */
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
DBG("Loading %s", file);
ril_config_merge_file(conf, file);
}
if (files) {
char **ptr;
for (ptr = files; *ptr; ptr++) {
DBG("Merging %s", *ptr);
ril_config_merge_file(conf, *ptr);
}
g_strfreev(files);
}
}
}
/*
* Local Variables:
* mode: C

View File

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

View File

@@ -1,10 +1,6 @@
/*
* RIL constants adopted from AOSP's header:
*
* /hardware/ril/reference_ril/ril.h
*
* Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2013-2017 Jolla Ltd.
* Copyright (C) 2013-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,47 +15,9 @@
#ifndef __RIL_CONSTANTS_H
#define __RIL_CONSTANTS_H 1
/* 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
#include <ofono/ril-constants.h>
/* call states */
enum ril_call_state {
RIL_CALL_ACTIVE = 0,
RIL_CALL_HOLDING = 1,
RIL_CALL_DIALING = 2,
RIL_CALL_ALERTING = 3,
RIL_CALL_INCOMING = 4,
RIL_CALL_WAITING = 5
};
#define RIL_MAX_UUID_LENGTH 64
/* Radio state */
enum ril_radio_state {
@@ -113,7 +71,60 @@ 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 */
@@ -181,30 +192,30 @@ enum ril_call_fail_cause {
};
enum ril_data_call_fail_cause {
PDP_FAIL_NONE = 0,
PDP_FAIL_OPERATOR_BARRED = 0x08,
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
PDP_FAIL_NSAPI_IN_USE = 0x23,
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
PDP_FAIL_SIGNAL_LOST = -3,
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
PDP_FAIL_RADIO_POWER_OFF = -5,
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
PDP_FAIL_NONE = 0,
PDP_FAIL_OPERATOR_BARRED = 0x08,
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
PDP_FAIL_NSAPI_IN_USE = 0x23,
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
PDP_FAIL_SIGNAL_LOST = -3,
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
PDP_FAIL_RADIO_POWER_OFF = -5,
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
};
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
@@ -309,221 +320,15 @@ 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 */
enum ril_restricted_state {
RIL_RESTRICTED_STATE_NONE = 0x00,
RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01,
RIL_RESTRICTED_STATE_CS_NORMAL = 0x02,
RIL_RESTRICTED_STATE_CS_ALL = 0x04,
RIL_RESTRICTED_STATE_PS_ALL = 0x10
};
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 */
#define RIL_REQUEST_GET_SIM_STATUS 1
#define RIL_REQUEST_ENTER_SIM_PIN 2
#define RIL_REQUEST_ENTER_SIM_PUK 3
#define RIL_REQUEST_ENTER_SIM_PIN2 4
#define RIL_REQUEST_ENTER_SIM_PUK2 5
#define RIL_REQUEST_CHANGE_SIM_PIN 6
#define RIL_REQUEST_CHANGE_SIM_PIN2 7
#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
#define RIL_REQUEST_GET_CURRENT_CALLS 9
#define RIL_REQUEST_DIAL 10
#define RIL_REQUEST_GET_IMSI 11
#define RIL_REQUEST_HANGUP 12
#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
#define RIL_REQUEST_CONFERENCE 16
#define RIL_REQUEST_UDUB 17
#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
#define RIL_REQUEST_SIGNAL_STRENGTH 19
#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
#define RIL_REQUEST_OPERATOR 22
#define RIL_REQUEST_RADIO_POWER 23
#define RIL_REQUEST_DTMF 24
#define RIL_REQUEST_SEND_SMS 25
#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
#define RIL_REQUEST_SETUP_DATA_CALL 27
#define RIL_REQUEST_SIM_IO 28
#define RIL_REQUEST_SEND_USSD 29
#define RIL_REQUEST_CANCEL_USSD 30
#define RIL_REQUEST_GET_CLIR 31
#define RIL_REQUEST_SET_CLIR 32
#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
#define RIL_REQUEST_SET_CALL_FORWARD 34
#define RIL_REQUEST_QUERY_CALL_WAITING 35
#define RIL_REQUEST_SET_CALL_WAITING 36
#define RIL_REQUEST_SMS_ACKNOWLEDGE 37
#define RIL_REQUEST_GET_IMEI 38
#define RIL_REQUEST_GET_IMEISV 39
#define RIL_REQUEST_ANSWER 40
#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
#define RIL_REQUEST_SET_FACILITY_LOCK 43
#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
#define RIL_REQUEST_DTMF_START 49
#define RIL_REQUEST_DTMF_STOP 50
#define RIL_REQUEST_BASEBAND_VERSION 51
#define RIL_REQUEST_SEPARATE_CONNECTION 52
#define RIL_REQUEST_SET_MUTE 53
#define RIL_REQUEST_GET_MUTE 54
#define RIL_REQUEST_QUERY_CLIP 55
#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
#define RIL_REQUEST_DATA_CALL_LIST 57
#define RIL_REQUEST_RESET_RADIO 58
#define RIL_REQUEST_OEM_HOOK_RAW 59
#define RIL_REQUEST_OEM_HOOK_STRINGS 60
#define RIL_REQUEST_SCREEN_STATE 61
#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
#define RIL_REQUEST_SET_BAND_MODE 65
#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
#define RIL_REQUEST_STK_GET_PROFILE 67
#define RIL_REQUEST_STK_SET_PROFILE 68
#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
#define RIL_REQUEST_SET_LOCATION_UPDATES 76
#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
#define RIL_REQUEST_SET_TTY_MODE 80
#define RIL_REQUEST_QUERY_TTY_MODE 81
#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
#define RIL_REQUEST_CDMA_FLASH 84
#define RIL_REQUEST_CDMA_BURST_DTMF 85
#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
#define RIL_REQUEST_CDMA_SEND_SMS 87
#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
#define RIL_REQUEST_DEVICE_IDENTITY 98
#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
#define RIL_REQUEST_GET_SMSC_ADDRESS 100
#define RIL_REQUEST_SET_SMSC_ADDRESS 101
#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
#define RIL_REQUEST_ISIM_AUTHENTICATION 105
#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
#define RIL_REQUEST_VOICE_RADIO_TECH 108
#define RIL_REQUEST_GET_CELL_INFO_LIST 109
#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
#define RIL_REQUEST_IMS_SEND_SMS 113
#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
#define RIL_REQUEST_NV_READ_ITEM 118
#define RIL_REQUEST_NV_WRITE_ITEM 119
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
#define RIL_REQUEST_NV_RESET_CONFIG 121
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
#define RIL_REQUEST_ALLOW_DATA 123
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
#define RIL_REQUEST_SIM_AUTHENTICATION 125
#define RIL_REQUEST_GET_DC_RT_INFO 126
#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
#define RIL_REQUEST_SET_DATA_PROFILE 128
#define RIL_REQUEST_SHUTDOWN 129
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
/* RIL Unsolicited Messages */
#define RIL_UNSOL_RESPONSE_BASE 1000
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
#define RIL_UNSOL_ON_USSD 1006
#define RIL_UNSOL_ON_USSD_REQUEST 1007
#define RIL_UNSOL_NITZ_TIME_RECEIVED 1008
#define RIL_UNSOL_SIGNAL_STRENGTH 1009
#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
#define RIL_UNSOL_STK_SESSION_END 1012
#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
#define RIL_UNSOL_STK_CALL_SETUP 1015
#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
#define RIL_UNSOL_SIM_REFRESH 1017
#define RIL_UNSOL_CALL_RING 1018
#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
#define RIL_UNSOL_CDMA_CALL_WAITING 1025
#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
#define RIL_UNSOL_CDMA_INFO_REC 1027
#define RIL_UNSOL_OEM_HOOK_RAW 1028
#define RIL_UNSOL_RINGBACK_TONE 1029
#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
#define RIL_UNSOL_RIL_CONNECTED 1034
#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
#define RIL_UNSOL_CELL_INFO_LIST 1036
#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
#define RIL_UNSOL_RADIO_CAPABILITY 1042
#define RIL_UNSOL_ON_SS 1043
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
#define DATA_PROFILE_DEFAULT_STR "0"
/* 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-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,7 @@
#include "ril_network.h"
#include "ril_sim_settings.h"
#include "ril_util.h"
#include "ril_vendor.h"
#include "ril_log.h"
#include <gutil_strv.h>
@@ -27,13 +28,8 @@
#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"
#define PROTO_IPV4V6_STR "IPV4V6"
/* Yes, it does sometimes take minutes in roaming */
#define SETUP_DATA_CALL_TIMEOUT (300*1000) /* ms */
enum ril_data_priv_flags {
RIL_DATA_FLAG_NONE = 0x00,
@@ -77,6 +73,12 @@ enum ril_data_priv_flags {
typedef GObjectClass RilDataClass;
typedef struct ril_data RilData;
enum ril_data_io_event_id {
IO_EVENT_DATA_CALL_LIST_CHANGED,
IO_EVENT_RESTRICTED_STATE_CHANGED,
IO_EVENT_COUNT
};
enum ril_data_settings_event_id {
SETTINGS_EVENT_IMSI_CHANGED,
SETTINGS_EVENT_PREF_MODE,
@@ -95,7 +97,10 @@ struct ril_data_priv {
struct ril_radio *radio;
struct ril_network *network;
struct ril_data_manager *dm;
struct ril_vendor *vendor;
enum ril_data_priv_flags flags;
enum ril_restricted_state restricted_state;
struct ril_data_request *req_queue;
struct ril_data_request *pending_req;
@@ -104,8 +109,9 @@ struct ril_data_priv {
guint slot;
char *log_prefix;
guint query_id;
gulong io_event_id;
gulong io_event_id[IO_EVENT_COUNT];
gulong settings_event_id[SETTINGS_EVENT_COUNT];
GHashTable* grab;
};
enum ril_data_signal {
@@ -170,28 +176,53 @@ 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);
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
static void ril_data_call_deact_cid(struct ril_data *data, int cid);
static void ril_data_power_update(struct ril_data *self);
static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
{
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
*==========================================================================*/
static struct ril_data_call *ril_data_call_new()
{
return g_new0(struct ril_data_call, 1);
}
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
{
if (call) {
struct ril_data_call *dc = g_new0(struct ril_data_call, 1);
struct ril_data_call *dc = ril_data_call_new();
dc->cid = call->cid;
dc->status = call->status;
dc->active = call->active;
@@ -208,13 +239,18 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
}
}
static void ril_data_call_destroy(struct ril_data_call *call)
{
g_free(call->ifname);
g_strfreev(call->dnses);
g_strfreev(call->addresses);
g_strfreev(call->gateways);
}
void ril_data_call_free(struct ril_data_call *call)
{
if (call) {
g_free(call->ifname);
g_strfreev(call->dnses);
g_strfreev(call->addresses);
g_strfreev(call->gateways);
ril_data_call_destroy(call);
g_free(call);
}
}
@@ -232,7 +268,7 @@ static void ril_data_call_list_free(struct ril_data_call_list *list)
}
}
static gint ril_data_call_parse_compare(gconstpointer a, gconstpointer b)
static gint ril_data_call_compare(gconstpointer a, gconstpointer b)
{
const struct ril_data_call *ca = a;
const struct ril_data_call *cb = b;
@@ -246,42 +282,13 @@ static gint ril_data_call_parse_compare(gconstpointer a, gconstpointer b)
}
}
static const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
{
switch (proto) {
case OFONO_GPRS_PROTO_IPV6:
return PROTO_IPV6_STR;
case OFONO_GPRS_PROTO_IPV4V6:
return PROTO_IPV4V6_STR;
case OFONO_GPRS_PROTO_IP:
return PROTO_IP_STR;
default:
return NULL;
}
}
static int ril_data_protocol_to_ofono(gchar *str)
{
if (str) {
if (!strcmp(str, PROTO_IPV6_STR)) {
return OFONO_GPRS_PROTO_IPV6;
} else if (!strcmp(str, PROTO_IPV4V6_STR)) {
return OFONO_GPRS_PROTO_IPV4V6;
} else if (!strcmp(str, PROTO_IP_STR)) {
return OFONO_GPRS_PROTO_IP;
}
}
return -1;
}
static struct ril_data_call *ril_data_call_parse(int version,
GRilIoParser *rilp)
static gboolean ril_data_call_parse_default(struct ril_data_call *call,
int version, GRilIoParser *rilp)
{
int prot;
char *prot_str;
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
guint32 active = RIL_DATA_CALL_INACTIVE;
struct ril_data_call *call = g_new0(struct ril_data_call, 1);
/* RIL_Data_Call_Response_v6 (see ril.h) */
grilio_parser_get_uint32(rilp, &status);
@@ -294,7 +301,7 @@ static struct ril_data_call *ril_data_call_parse(int version,
call->dnses = grilio_parser_split_utf8(rilp, " ");
call->gateways = grilio_parser_split_utf8(rilp, " ");
prot = ril_data_protocol_to_ofono(prot_str);
prot = ril_protocol_to_ofono(prot_str);
if (prot < 0 && status == PDP_FAIL_NONE) {
ofono_error("Invalid protocol: %s", prot_str);
}
@@ -316,13 +323,49 @@ static struct ril_data_call *ril_data_call_parse(int version,
}
g_free(prot_str);
return call;
return TRUE;
}
static struct ril_data_call *ril_data_call_parse(struct ril_vendor *vendor,
int version, GRilIoParser *parser)
{
GRilIoParser copy = *parser;
struct ril_data_call *call = ril_data_call_new();
gboolean parsed = ril_vendor_data_call_parse(vendor, call,
version, parser);
if (!parsed) {
/* Try the default parser */
ril_data_call_destroy(call);
memset(call, 0, sizeof(*call));
*parser = copy;
parsed = ril_data_call_parse_default(call, version, parser);
}
if (parsed) {
DBG("[status=%d,retry=%d,cid=%d,active=%d,type=%s,ifname=%s,"
"mtu=%d,address=%s,dns=%s %s,gateways=%s]",
call->status, call->retry_time,
call->cid, call->active,
ril_protocol_from_ofono(call->prot),
call->ifname, call->mtu,
call->addresses ? call->addresses[0] : NULL,
call->dnses ? call->dnses[0] : NULL,
(call->dnses && call->dnses[0] &&
call->dnses[1]) ? call->dnses[1] : "",
call->gateways ? call->gateways[0] : NULL);
return call;
} else {
ril_data_call_free(call);
return NULL;
}
}
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
guint len, enum ril_data_call_format format)
guint len, struct ril_vendor *vendor,
enum ril_data_call_format format)
{
unsigned int version, n, i;
guint32 version, n, i;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
@@ -340,25 +383,14 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
}
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
struct ril_data_call *call =
ril_data_call_parse(list->version, &rilp);
struct ril_data_call *call = ril_data_call_parse(vendor,
list->version, &rilp);
DBG("[status=%d,retry=%d,cid=%d,"
"active=%d,type=%s,ifname=%s,mtu=%d,"
"address=%s, dns=%s %s,gateways=%s]",
call->status, call->retry_time,
call->cid, call->active,
ril_data_ofono_protocol_to_ril(call->prot),
call->ifname, call->mtu,
call->addresses ? call->addresses[0] : NULL,
call->dnses ? call->dnses[0] : NULL,
(call->dnses && call->dnses[0] &&
call->dnses[1]) ? call->dnses[1] : "",
call->gateways ? call->gateways[0] : NULL);
list->num++;
list->calls = g_slist_insert_sorted(list->calls, call,
ril_data_call_parse_compare);
if (call) {
list->num++;
list->calls = g_slist_insert_sorted(list->calls,
call, ril_data_call_compare);
}
}
if (list->calls) {
@@ -452,7 +484,7 @@ static int ril_data_call_list_move_calls(struct ril_data_call_list *dest,
dest->num++;
src->calls = g_slist_delete_link(src->calls, l);
dest->calls = g_slist_insert_sorted(dest->calls,
call, ril_data_call_parse_compare);
call, ril_data_call_compare);
}
l = next;
@@ -483,6 +515,10 @@ struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
static void ril_data_set_calls(struct ril_data *self,
struct ril_data_call_list *list)
{
struct ril_data_priv *priv = self->priv;
GHashTableIter it;
gpointer key;
if (!ril_data_call_list_equal(self->data_calls, list)) {
DBG("data calls changed");
ril_data_call_list_free(self->data_calls);
@@ -491,6 +527,63 @@ static void ril_data_set_calls(struct ril_data *self,
} else {
ril_data_call_list_free(list);
}
/* Clean up the grab table */
g_hash_table_iter_init(&it, priv->grab);
while (g_hash_table_iter_next(&it, &key, NULL)) {
const int cid = GPOINTER_TO_INT(key);
if (!ril_data_call_find(self->data_calls, cid)) {
g_hash_table_iter_remove(&it);
}
}
if (self->data_calls) {
GSList *l;
/* Disconnect stray calls (one at a time) */
for (l = self->data_calls->calls; l; l = l->next) {
struct ril_data_call *dc = l->data;
key = GINT_TO_POINTER(dc->cid);
if (!g_hash_table_contains(priv->grab, key)) {
DBG_(self, "stray call %u", dc->cid);
ril_data_call_deact_cid(self, dc->cid);
break;
}
}
}
}
static void ril_data_check_allowed(struct ril_data *self, gboolean was_allowed)
{
if (ril_data_allowed(self) != was_allowed) {
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
}
}
static void ril_data_restricted_state_changed_cb(GRilIoChannel *io, guint event,
const void *data, guint len, void *user_data)
{
struct ril_data *self = RIL_DATA(user_data);
GRilIoParser rilp;
guint32 count, state;
GASSERT(event == RIL_UNSOL_RESTRICTED_STATE_CHANGED);
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &count) && count == 1 &&
grilio_parser_get_uint32(&rilp, &state) &&
grilio_parser_at_end(&rilp)) {
struct ril_data_priv *priv = self->priv;
if (priv->restricted_state != state) {
const gboolean was_allowed = ril_data_allowed(self);
DBG_(self, "restricted state 0x%02x", state);
priv->restricted_state = state;
ril_data_check_allowed(self, was_allowed);
}
}
}
static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
@@ -508,7 +601,7 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
}
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->options.data_call_format));
priv->vendor, priv->options.data_call_format));
}
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
@@ -517,11 +610,18 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
struct ril_data *self = RIL_DATA(user_data);
struct ril_data_priv *priv = self->priv;
/*
* Only RIL_E_SUCCESS and RIL_E_RADIO_NOT_AVAILABLE are expected here,
* all other errors are filtered out by ril_voicecall_clcc_retry()
*/
GASSERT(priv->query_id);
priv->query_id = 0;
if (ril_status == RIL_E_SUCCESS) {
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->options.data_call_format));
priv->vendor, priv->options.data_call_format));
} else {
/* RADIO_NOT_AVAILABLE == no calls */
ril_data_set_calls(self, NULL);
}
}
@@ -723,7 +823,7 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
struct ril_data_call *call = NULL;
if (ril_status == RIL_E_SUCCESS) {
list = ril_data_call_list_parse(data, len,
list = ril_data_call_list_parse(data, len, priv->vendor,
priv->options.data_call_format);
}
@@ -786,9 +886,9 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
struct ril_data_request_setup *setup =
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;
const char *proto_str = ril_protocol_from_ofono(setup->proto);
GRilIoRequest *ioreq;
int tech, auth = RIL_AUTH_NONE;
GASSERT(proto_str);
@@ -811,30 +911,30 @@ 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]) {
auth = ril_auth_method_from_ofono(setup->auth_method);
}
/*
* 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_format(ioreq, "%d", tech);
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
grilio_request_append_utf8(ioreq, setup->apn);
grilio_request_append_utf8(ioreq, setup->username);
grilio_request_append_utf8(ioreq, setup->password);
grilio_request_append_format(ioreq, "%d", auth);
grilio_request_append_utf8(ioreq, proto_str);
/* Give vendor code a chance to build a vendor specific packet */
ioreq = ril_vendor_data_call_req(priv->vendor, tech,
DATA_PROFILE_DEFAULT_STR, setup->apn, setup->username,
setup->password, auth, proto_str);
if (!ioreq) {
/* The default one */
ioreq = grilio_request_new();
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);
grilio_request_append_utf8(ioreq, setup->username);
grilio_request_append_utf8(ioreq, setup->password);
grilio_request_append_format(ioreq, "%d", auth);
grilio_request_append_utf8(ioreq, proto_str);
}
GASSERT(!req->pending_id);
grilio_request_set_timeout(ioreq, SETUP_DATA_CALL_TIMEOUT);
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
RIL_REQUEST_SETUP_DATA_CALL, ril_data_call_setup_cb,
NULL, setup);
@@ -924,6 +1024,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 +1042,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,
@@ -971,19 +1071,15 @@ static struct ril_data_request *ril_data_call_deact_new(struct ril_data *data,
return req;
}
static void ril_data_call_deact_cid(struct ril_data *data, int cid)
{
ril_data_request_queue(ril_data_call_deact_new(data, cid, NULL, NULL));
}
/*==========================================================================*
* ril_data_allow_request
*==========================================================================*/
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 +1089,20 @@ 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");
}
ril_data_check_allowed(data, was_allowed);
}
ril_data_request_finish(req);
@@ -1007,25 +1110,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;
}
@@ -1073,19 +1183,19 @@ static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config)
const struct ril_slot_config *config,
struct ril_vendor *vendor)
{
GASSERT(dm);
if (G_LIKELY(dm)) {
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 +1203,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;
}
@@ -1106,9 +1217,16 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
priv->dm = ril_data_manager_ref(dm);
priv->radio = ril_radio_ref(radio);
priv->network = ril_network_ref(network);
priv->io_event_id = grilio_channel_add_unsol_event_handler(io,
priv->vendor = ril_vendor_ref(vendor);
priv->io_event_id[IO_EVENT_DATA_CALL_LIST_CHANGED] =
grilio_channel_add_unsol_event_handler(io,
ril_data_call_list_changed_cb,
RIL_UNSOL_DATA_CALL_LIST_CHANGED, self);
priv->io_event_id[IO_EVENT_RESTRICTED_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(io,
ril_data_restricted_state_changed_cb,
RIL_UNSOL_RESTRICTED_STATE_CHANGED, self);
priv->settings_event_id[SETTINGS_EVENT_IMSI_CHANGED] =
ril_sim_settings_add_imsi_changed_handler(settings,
@@ -1118,12 +1236,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 +1247,39 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
return NULL;
}
static gboolean ril_data_poll_call_state_retry(GRilIoRequest* req,
int ril_status, const void* resp_data, guint resp_len, void* user_data)
{
switch (ril_status) {
case RIL_E_SUCCESS:
case RIL_E_RADIO_NOT_AVAILABLE:
return FALSE;
default:
return TRUE;
}
}
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);
grilio_request_set_retry_func(req,
ril_data_poll_call_state_retry);
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)) {
@@ -1154,6 +1300,8 @@ void ril_data_unref(struct ril_data *self)
gboolean ril_data_allowed(struct ril_data *self)
{
return G_LIKELY(self) &&
(self->priv->restricted_state &
RIL_RESTRICTED_STATE_PS_ALL) == 0 &&
(self->priv->flags &
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON)) ==
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
@@ -1168,9 +1316,7 @@ static void ril_data_deactivate_all(struct ril_data *self)
struct ril_data_call *call = l->data;
if (call->status == PDP_FAIL_NONE) {
DBG_(self, "deactivating call %u", call->cid);
ril_data_request_queue(
ril_data_call_deact_new(self,
call->cid, NULL, NULL));
ril_data_call_deact_cid(self, call->cid);
}
}
}
@@ -1180,8 +1326,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 +1356,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 +1373,18 @@ 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);
}
ril_data_check_allowed(self, was_allowed);
}
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
@@ -1244,12 +1401,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 +1455,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);
}
}
@@ -1337,12 +1483,39 @@ struct ril_data_request *ril_data_call_deactivate(struct ril_data *self,
return req;
}
gboolean ril_data_call_grab(struct ril_data *self, int cid, void *cookie)
{
if (self && cookie && ril_data_call_find(self->data_calls, cid)) {
struct ril_data_priv *priv = self->priv;
gpointer key = GINT_TO_POINTER(cid);
void *prev = g_hash_table_lookup(priv->grab, key);
if (!prev) {
g_hash_table_insert(priv->grab, key, cookie);
return TRUE;
} else {
return (prev == cookie);
}
}
return FALSE;
}
void ril_data_call_release(struct ril_data *self, int cid, void *cookie)
{
if (self && cookie) {
struct ril_data_priv *priv = self->priv;
g_hash_table_remove(priv->grab, GUINT_TO_POINTER(cid));
}
}
static void ril_data_init(struct ril_data *self)
{
struct ril_data_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_DATA_TYPE, struct ril_data_priv);
self->priv = priv;
priv->grab = g_hash_table_new(g_direct_hash, g_direct_equal);
}
static void ril_data_dispose(GObject *object)
@@ -1356,7 +1529,7 @@ static void ril_data_dispose(GObject *object)
ril_sim_settings_remove_handlers(settings, priv->settings_event_id,
G_N_ELEMENTS(priv->settings_event_id));
grilio_channel_remove_handlers(priv->io, &priv->io_event_id, 1);
grilio_channel_remove_all_handlers(priv->io, priv->io_event_id);
grilio_queue_cancel_all(priv->q, FALSE);
priv->query_id = 0;
@@ -1370,6 +1543,7 @@ static void ril_data_dispose(GObject *object)
dm->data_list = g_slist_remove(dm->data_list, self);
ril_data_manager_check_data(dm);
g_hash_table_destroy(priv->grab);
G_OBJECT_CLASS(ril_data_parent_class)->dispose(object);
}
@@ -1386,6 +1560,7 @@ static void ril_data_finalize(GObject *object)
ril_network_unref(priv->network);
ril_data_manager_unref(priv->dm);
ril_data_call_list_free(self->data_calls);
ril_vendor_unref(priv->vendor);
G_OBJECT_CLASS(ril_data_parent_class)->finalize(object);
}
@@ -1538,9 +1713,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 +1737,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-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,8 +17,11 @@
#define RIL_DATA_H
#include "ril_types.h"
#include <ofono/gprs-context.h>
#include <glib-object.h>
enum ril_data_call_active {
RIL_DATA_CALL_INACTIVE = 0,
RIL_DATA_CALL_LINK_DOWN = 1,
@@ -56,8 +59,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 +87,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,
@@ -95,10 +99,12 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config);
const struct ril_slot_config *config,
struct ril_vendor *vendor);
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);
@@ -117,11 +123,18 @@ struct ril_data_request *ril_data_call_deactivate(struct ril_data *data,
void ril_data_request_detach(struct ril_data_request *req);
void ril_data_request_cancel(struct ril_data_request *req);
gboolean ril_data_call_grab(struct ril_data *data, int cid, void *cookie);
void ril_data_call_release(struct ril_data *data, int cid, void *cookie);
void ril_data_call_free(struct ril_data_call *call);
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
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) 2016 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,8 @@
#include "ril_types.h"
#include <glib-object.h>
struct ril_ecclist_priv;
struct ril_ecclist {

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,14 +17,15 @@
#include "ril_network.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_mtu.h"
#include "ril_log.h"
#include <gutil_strv.h>
#include <arpa/inet.h>
#include "ofono.h"
#include "common.h"
#include "mtu-watch.h"
#define CTX_ID_NONE ((unsigned int)(-1))
@@ -43,7 +44,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;
@@ -63,7 +64,7 @@ static char *ril_gprs_context_netmask(const char *bits)
const char* str;
struct in_addr in;
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
((1 << nbits)-1) << (32-nbits));
((1u << nbits)-1) << (32-nbits));
str = inet_ntoa(in);
if (str) {
return g_strdup(str);
@@ -87,6 +88,7 @@ static int ril_gprs_context_address_family(const char *addr)
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
{
if (gcd->active_call) {
ril_data_call_release(gcd->data, gcd->active_call->cid, gcd);
ril_data_call_free(gcd->active_call);
gcd->active_call = NULL;
}
@@ -95,7 +97,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 +109,10 @@ 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);
ril_data_call_grab(gcd->data, call->cid, gcd);
} else {
ril_gprs_context_free_active_call(gcd);
}
@@ -377,7 +380,7 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
ril_gprs_context_set_dns_servers(gc, call);
}
ofono_gprs_context_signal_change(gc, call->cid);
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
ril_data_call_free(prev_call);
}
@@ -395,6 +398,8 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
if (ril_status != RIL_E_SUCCESS) {
ofono_error("GPRS context: Reply failure: %s",
ril_error_to_string(ril_status));
} else if (!call) {
ofono_error("Unexpected data call failure");
} else if (call->status != PDP_FAIL_NONE) {
ofono_error("Unexpected data call status %d", call->status);
error.type = OFONO_ERROR_TYPE_CMS;
@@ -444,7 +449,7 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
/* Let's make sure that we aren't connecting when roaming not allowed */
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
if (!ofono_gprs_get_roaming_allowed(gprs) &&
if (!__ofono_gprs_get_roaming_allowed(gprs) &&
ril_netreg_check_if_really_roaming(netreg, rs) ==
NETWORK_REGISTRATION_STATUS_ROAMING) {
struct ofono_error error;
@@ -477,24 +482,23 @@ static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
* invoked and gcd->deactivate.req will be NULL.
*/
if (gcd->deactivate.req) {
struct ofono_error error;
ofono_gprs_context_cb_t cb = gcd->deactivate.cb;
gpointer cb_data = gcd->deactivate.data;
if (ril_status == RIL_E_SUCCESS) {
GASSERT(gcd->active_call);
ril_error_init_ok(&error);
ofono_info("Deactivated data call");
} else {
ril_error_init_failure(&error);
ofono_error("Deactivate failure: %s",
ril_error_to_string(ril_status));
}
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
if (cb) {
struct ofono_error error;
ril_gprs_context_free_active_call(gcd);
cb(&error, cb_data);
cb(ril_error_ok(&error), cb_data);
return;
}
}
@@ -508,7 +512,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
GASSERT(gcd->active_ctx_cid == id);
ofono_info("Deactivating context: %u", id);
if (gcd->active_call && gcd->active_ctx_cid == id) {
@@ -575,7 +579,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-2019 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 <ofono/watch.h>
#define MAX_PDP_CONTEXTS (2)
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
@@ -50,24 +52,18 @@ struct ril_modem_online_request {
struct ril_modem_data {
struct ril_modem modem;
struct ofono_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 +79,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 +122,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 +206,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 +234,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 ofono_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);
}
@@ -274,10 +247,11 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("%s", ofono_modem_get_path(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,
@@ -310,9 +284,13 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
ofono_phonebook_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
ofono_message_waiting_register(ofono_message_waiting_create(modem));
if (md->modem.config.enable_stk) {
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
}
if (md->modem.config.enable_cbs) {
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
}
}
static void ril_modem_post_online(struct ofono_modem *modem)
@@ -331,20 +309,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 +369,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);
ofono_watch_remove_handler(md->watch, md->imsi_event_id);
ofono_watch_unref(md->watch);
if (md->online_check_id) {
g_source_remove(md->online_check_id);
}
@@ -426,25 +393,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 +425,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 +441,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 = ofono_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 =
ofono_watch_add_imsi_changed_handler(md->watch,
ril_modem_imsi_cb, md);
md->set_online.md = md;
@@ -490,8 +456,10 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
ofono_modem_set_data(ofono, md);
err = ofono_modem_register(ofono);
if (!err) {
ril_radio_power_cycle(modem->radio);
GASSERT(io->connected);
if (config->radio_power_cycle) {
ril_radio_power_cycle(modem->radio);
}
/*
* ofono_modem_reset sets Powered to TRUE without
@@ -504,11 +472,12 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
/*
* With some RIL implementations, querying available
* band modes causes some magic Android properties to
* appear. Otherwise this request is pretty harmless
* and useless.
* appear.
*/
grilio_queue_send_request(md->q, NULL,
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
if (config->query_available_band_mode) {
grilio_queue_send_request(md->q, NULL,
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
}
ril_modem_update_radio_settings(md);
return modem;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,18 +14,27 @@
*/
#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;
};
/* This number must be in sync with ril_netmon_notify_ofono: */
#define RIL_NETMON_MAX_OFONO_PARAMS (8)
struct ril_netmon_ofono_param {
enum ofono_netmon_info type;
int value;
};
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
{
return ofono ? ofono_netmon_get_data(ofono) : NULL;
@@ -39,7 +48,7 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
if (mcc >= 0 && mcc <= 999) {
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
if (mnc >= 0 && mnc <= 999) {
const int mnclen = mnclength(mcc, mnc);
const unsigned int mnclen = mnclength(mcc, mnc);
const char *format[] = { "%d", "%02d", "%03d" };
const char *fmt = (mnclen > 0 &&
mnclen <= G_N_ELEMENTS(format)) ?
@@ -49,58 +58,171 @@ 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)
static void ril_netmon_notify_ofono(struct ofono_netmon *netmon,
enum ofono_netmon_cell_type type, int mcc, int mnc,
struct ril_netmon_ofono_param *params, int nparams)
{
char mcc[OFONO_MAX_MCC_LENGTH + 1];
char mnc[OFONO_MAX_MNC_LENGTH + 1];
char s_mcc[OFONO_MAX_MCC_LENGTH + 1];
char s_mnc[OFONO_MAX_MNC_LENGTH + 1];
int i;
ril_netmon_format_mccmnc(mcc, mnc, gsm->mcc, gsm->mnc);
ofono_netmon_serving_cell_notify(netmon,
OFONO_NETMON_CELL_TYPE_GSM,
OFONO_NETMON_INFO_MCC, mcc,
OFONO_NETMON_INFO_MNC, mnc,
OFONO_NETMON_INFO_LAC, gsm->lac,
OFONO_NETMON_INFO_CI, gsm->cid,
OFONO_NETMON_INFO_RSSI, gsm->signalStrength,
OFONO_NETMON_INFO_BER, gsm->bitErrorRate,
/* Better not to push uninitialized data to the stack ... */
for (i = nparams; i < RIL_NETMON_MAX_OFONO_PARAMS; i++) {
params[i].type = OFONO_NETMON_INFO_INVALID;
params[i].value = SAILFISH_CELL_INVALID_VALUE;
}
ril_netmon_format_mccmnc(s_mcc, s_mnc, mcc, mnc);
ofono_netmon_serving_cell_notify(netmon, type,
OFONO_NETMON_INFO_MCC, s_mcc,
OFONO_NETMON_INFO_MNC, s_mnc,
params[0].type, params[0].value,
params[1].type, params[1].value,
params[2].type, params[2].value,
params[3].type, params[3].value,
params[4].type, params[4].value,
params[5].type, params[5].value,
params[6].type, params[6].value,
params[7].type, params[7].value,
OFONO_NETMON_INFO_INVALID);
}
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
const struct sailfish_cell_info_gsm *gsm)
{
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
int n = 0;
if (gsm->lac != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_LAC;
params[n].value = gsm->lac;
n++;
}
if (gsm->cid != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CI;
params[n].value = gsm->cid;
n++;
}
if (gsm->arfcn != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_ARFCN;
params[n].value = gsm->arfcn;
n++;
}
if (gsm->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSSI;
params[n].value = gsm->signalStrength;
n++;
}
if (gsm->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_BER;
params[n].value = gsm->bitErrorRate;
n++;
}
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_GSM,
gsm->mcc, gsm->mnc, params, n);
}
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];
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
int n = 0;
ril_netmon_format_mccmnc(mcc, mnc, wcdma->mcc, wcdma->mnc);
ofono_netmon_serving_cell_notify(netmon,
OFONO_NETMON_CELL_TYPE_UMTS,
OFONO_NETMON_INFO_MCC, mcc,
OFONO_NETMON_INFO_MNC, mnc,
OFONO_NETMON_INFO_LAC, wcdma->lac,
OFONO_NETMON_INFO_CI, wcdma->cid,
OFONO_NETMON_INFO_PSC, wcdma->psc,
OFONO_NETMON_INFO_RSSI, wcdma->signalStrength,
OFONO_NETMON_INFO_BER, wcdma->bitErrorRate,
OFONO_NETMON_INFO_INVALID);
if (wcdma->lac != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_LAC;
params[n].value = wcdma->lac;
n++;
}
if (wcdma->cid != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CI;
params[n].value = wcdma->cid;
n++;
}
if (wcdma->psc != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_PSC;
params[n].value = wcdma->psc;
n++;
}
if (wcdma->uarfcn != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_ARFCN;
params[n].value = wcdma->uarfcn;
n++;
}
if (wcdma->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSSI;
params[n].value = wcdma->signalStrength;
n++;
}
if (wcdma->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_BER;
params[n].value = wcdma->bitErrorRate;
n++;
}
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_UMTS,
wcdma->mcc, wcdma->mnc, params, n);
}
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];
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
int n = 0;
ril_netmon_format_mccmnc(mcc, mnc, lte->mcc, lte->mnc);
ofono_netmon_serving_cell_notify(netmon,
OFONO_NETMON_CELL_TYPE_LTE,
OFONO_NETMON_INFO_MCC, mcc,
OFONO_NETMON_INFO_MNC, mnc,
OFONO_NETMON_INFO_CI, lte->ci,
OFONO_NETMON_INFO_RSSI, lte->signalStrength,
OFONO_NETMON_INFO_TIMING_ADVANCE, lte->timingAdvance,
OFONO_NETMON_INFO_INVALID);
if (lte->ci != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CI;
params[n].value = lte->ci;
n++;
}
if (lte->earfcn != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_EARFCN;
params[n].value = lte->earfcn;
n++;
}
if (lte->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSSI;
params[n].value = lte->signalStrength;
n++;
}
if (lte->rsrp != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSRQ;
params[n].value = lte->rsrp;
n++;
}
if (lte->rsrq != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSRP;
params[n].value = lte->rsrq;
n++;
}
if (lte->cqi != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CQI;
params[n].value = lte->cqi;
n++;
}
if (lte->timingAdvance != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_TIMING_ADVANCE;
params[n].value = lte->timingAdvance;
n++;
}
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_LTE,
lte->mcc, lte->mnc, params, n);
}
static void ril_netmon_request_update(struct ofono_netmon *netmon,
@@ -111,19 +233,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 +278,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 +304,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-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,6 +21,9 @@
#include "common.h"
#include "simutil.h"
#define REGISTRATION_TIMEOUT (100*1000) /* ms */
#define REGISTRATION_MAX_RETRIES (2)
enum ril_netreg_events {
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
@@ -36,6 +39,7 @@ enum ril_netreg_network_events {
struct ril_netreg {
GRilIoChannel *io;
GRilIoQueue *q;
gboolean network_selection_manual_0;
struct ofono_netreg *netreg;
struct ril_network *network;
char *log_prefix;
@@ -61,6 +65,8 @@ struct ril_netreg_cbd {
#define ril_netreg_cbd_free g_free
#define DBG_(nd,fmt,args...) DBG("%s" fmt, (nd)->log_prefix, ##args)
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
{
return ofono ? ofono_netreg_get_data(ofono) : NULL;
@@ -109,7 +115,7 @@ static gboolean ril_netreg_status_notify_cb(gpointer user_data)
struct ril_netreg *nd = user_data;
const struct ril_registration_state *reg = &nd->network->voice;
DBG("%s", nd->log_prefix);
DBG_(nd, "");
GASSERT(nd->notify_id);
nd->notify_id = 0;
ofono_netreg_status_notify(nd->netreg,
@@ -124,9 +130,9 @@ static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
/* Coalesce multiple notifications into one */
if (nd->notify_id) {
DBG("%snotification aready queued", nd->log_prefix);
DBG_(nd, "notification aready queued");
} else {
DBG("%squeuing notification", nd->log_prefix);
DBG_(nd, "queuing notification");
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
}
}
@@ -138,7 +144,7 @@ static void ril_netreg_registration_status(struct ofono_netreg *netreg,
const struct ril_registration_state *reg = &nd->network->voice;
struct ofono_error error;
DBG("%s", nd->log_prefix);
DBG_(nd, "");
cb(ril_error_ok(&error),
ril_netreg_check_status(nd, reg->status),
reg->lac, reg->ci, reg->access_tech, data);
@@ -151,7 +157,7 @@ static gboolean ril_netreg_current_operator_cb(void *user_data)
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
struct ofono_error error;
DBG("%s", nd->log_prefix);
DBG_(nd, "");
GASSERT(nd->current_operator_id);
nd->current_operator_id = 0;
@@ -294,12 +300,16 @@ static void ril_netreg_register_auto(struct ofono_netreg *netreg,
ofono_netreg_register_cb_t cb, void *data)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
GRilIoRequest *req = grilio_request_new();
ofono_info("nw select automatic");
grilio_queue_send_request_full(nd->q, NULL,
grilio_request_set_timeout(req, REGISTRATION_TIMEOUT);
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
ril_netreg_register_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, cb, data));
grilio_request_unref(req);
}
static void ril_netreg_register_manual(struct ofono_netreg *netreg,
@@ -308,9 +318,12 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
GRilIoRequest *req = grilio_request_new();
const char *suffix = nd->network_selection_manual_0 ? "+0" : "";
ofono_info("nw select manual: %s%s", mcc, mnc);
grilio_request_append_format(req, "%s%s+0", mcc, mnc);
ofono_info("nw select manual: %s%s%s", mcc, mnc, suffix);
grilio_request_append_format(req, "%s%s%s", mcc, mnc, suffix);
grilio_request_set_timeout(req, REGISTRATION_TIMEOUT);
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
ril_netreg_register_cb, ril_netreg_cbd_free,
@@ -318,14 +331,24 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
grilio_request_unref(req);
}
static int ril_netreg_dbm_to_percentage(int dbm)
{
const int min_dbm = -100; /* very weak signal, 0.0000000001 mW */
const int max_dbm = -60; /* strong signal, 0.000001 mW */
return (dbm <= min_dbm) ? 1 :
(dbm >= max_dbm) ? 100 :
(100 * (dbm - min_dbm) / (max_dbm - min_dbm));
}
static int ril_netreg_get_signal_strength(const void *data, guint len)
{
GRilIoParser rilp;
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
int rsrp = 0, tdscdma_dbm = 0;
grilio_parser_init(&rilp, data, len);
/* RIL_SignalStrength_v6 */
/* GW_SignalStrength */
grilio_parser_get_int32(&rilp, &gw_signal);
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
@@ -341,23 +364,57 @@ static int ril_netreg_get_signal_strength(const void *data, guint len)
/* LTE_SignalStrength */
grilio_parser_get_int32(&rilp, &lte_signal);
grilio_parser_get_int32(&rilp, NULL); /* rsrp */
grilio_parser_get_int32(&rilp, NULL); /* rsrq */
grilio_parser_get_int32(&rilp, NULL); /* rssnr */
grilio_parser_get_int32(&rilp, NULL); /* cqi */
grilio_parser_get_int32(&rilp, &rsrp);
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal, cdma_dbm,
evdo_dbm, lte_signal);
/* Skip the rest of LTE_SignalStrength_v8 */
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
grilio_parser_get_int32(&rilp, NULL) && /* cqi */
grilio_parser_get_int32(&rilp, NULL)) { /* timingAdvance */
/* TD_SCDMA_SignalStrength */
grilio_parser_get_int32(&rilp, &tdscdma_dbm); /* rscp */
}
if (rsrp == INT_MAX) {
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d, tdscdma: %d",
gw_signal, cdma_dbm, evdo_dbm,
lte_signal, tdscdma_dbm);
} else {
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d, tdscdma: %d",
gw_signal, cdma_dbm, evdo_dbm,
lte_signal, rsrp, tdscdma_dbm);
}
/* Return the first valid one */
if (gw_signal != 99 && gw_signal != -1) {
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
* RSRP value. If we've got zero, don't report it just yet. */
if (gw_signal >= 1 && gw_signal <= 31) {
/* Valid values are (0-31, 99) as defined in TS 27.007 */
return (gw_signal * 100) / 31;
}
if (lte_signal != 99 && lte_signal != -1) {
/* Valid values are (0-31, 99) as defined in TS 27.007 */
if (lte_signal >= 0 && lte_signal <= 31) {
return (lte_signal * 100) / 31;
}
/* RSCP range: 25 to 120 dBm as defined in 3GPP TS 25.123 */
if (tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
return ril_netreg_dbm_to_percentage(-tdscdma_dbm);
}
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
return ril_netreg_dbm_to_percentage(-rsrp);
}
/* If we've got zero strength and no valid RSRP, then so be it */
if (gw_signal == 0) {
return 0;
}
/* In case of dbm, return the value directly */
if (cdma_dbm != -1) {
return MIN(cdma_dbm, 100);
@@ -378,7 +435,7 @@ static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
strength = ril_netreg_get_signal_strength(data, len);
DBG("%d", strength);
DBG_(nd, "%d", strength);
ofono_netreg_strength_notify(nd->netreg, strength);
}
@@ -417,9 +474,8 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
{
struct ril_netreg *nd = user_data;
GRilIoParser rilp;
struct ofono_network_time time;
int year, mon, mday, hour, min, sec, dst, tzi;
char tzs, tz[4];
int year, mon, mday, hour, min, sec, tzi, dst = 0;
char tzs;
gchar *nitz;
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
@@ -427,21 +483,33 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
grilio_parser_init(&rilp, data, len);
nitz = grilio_parser_get_utf8(&rilp);
DBG("%s", nitz);
sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u", &year, &mon, &mday,
&hour, &min, &sec, &tzs, &tzi, &dst);
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
DBG_(nd, "%s", nitz);
time.utcoff = atoi(tz) * 15 * 60;
time.dst = dst;
time.sec = sec;
time.min = min;
time.hour = hour;
time.mday = mday;
time.mon = mon;
time.year = 2000 + year;
/*
* Format: yy/mm/dd,hh:mm:ss(+/-)tz[,ds]
* The ds part is considered optional, initialized to zero.
*/
if (nitz && sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u",
&year, &mon, &mday, &hour, &min, &sec, &tzs, &tzi,
&dst) >= 8 && (tzs == '+' || tzs == '-')) {
struct ofono_network_time time;
char tz[4];
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
time.utcoff = atoi(tz) * 15 * 60;
time.dst = dst;
time.sec = sec;
time.min = min;
time.hour = hour;
time.mday = mday;
time.mon = mon;
time.year = 2000 + year;
ofono_netreg_time_notify(nd->netreg, &time);
} else {
ofono_warn("Failed to parse NITZ string \"%s\"", nitz);
}
ofono_netreg_time_notify(nd->netreg, &time);
g_free(nitz);
}
@@ -482,14 +550,17 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
{
struct ril_modem *modem = data;
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
guint slot = ril_modem_slot(modem);
const struct ril_slot_config *config = &modem->config;
DBG("[%u] %p", slot, netreg);
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
nd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
DBG_(nd, "%p", netreg);
nd->io = grilio_channel_ref(ril_modem_io(modem));
nd->q = grilio_queue_new(nd->io);
nd->network = ril_network_ref(modem->network);
nd->netreg = netreg;
nd->network_selection_manual_0 = config->network_selection_manual_0;
ofono_netreg_set_data(netreg, nd);
nd->timer_id = g_idle_add(ril_netreg_register, nd);
@@ -499,9 +570,8 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
static void ril_netreg_remove(struct ofono_netreg *netreg)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
int i;
DBG("%p", netreg);
DBG_(nd, "%p", netreg);
grilio_queue_cancel_all(nd->q, FALSE);
ofono_netreg_set_data(netreg, NULL);
@@ -517,14 +587,10 @@ static void ril_netreg_remove(struct ofono_netreg *netreg)
g_source_remove(nd->current_operator_id);
}
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
}
ril_network_remove_all_handlers(nd->network, nd->network_event_id);
ril_network_unref(nd->network);
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
G_N_ELEMENTS(nd->ril_event_id));
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
grilio_channel_unref(nd->io);
grilio_queue_unref(nd->q);
g_free(nd->log_prefix);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2019 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 @@
#include "ril_radio.h"
#include "ril_sim_card.h"
#include "ril_sim_settings.h"
#include "ril_vendor.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -27,6 +28,8 @@
#include <gutil_misc.h>
#include <ofono/netreg.h>
#include <ofono/watch.h>
#include <ofono/gprs.h>
#include "common.h"
@@ -47,13 +50,35 @@ enum ril_network_radio_event {
RADIO_EVENT_COUNT
};
enum ril_network_sim_events {
SIM_EVENT_STATUS_CHANGED,
SIM_EVENT_IO_ACTIVE_CHANGED,
SIM_EVENT_COUNT
};
enum ril_network_unsol_event {
UNSOL_EVENT_NETWORK_STATE,
UNSOL_EVENT_RADIO_CAPABILITY,
UNSOL_EVENT_COUNT
};
enum ril_network_watch_event {
WATCH_EVENT_GPRS,
WATCH_EVENT_GPRS_SETTINGS,
WATCH_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;
struct ril_sim_card *simcard;
struct ril_vendor *vendor;
struct ofono_watch *watch;
int rat;
enum ril_pref_net_type lte_network_mode;
enum ril_pref_net_type umts_network_mode;
int network_mode_timeout;
char *log_prefix;
guint operator_poll_id;
guint voice_poll_id;
@@ -61,11 +86,15 @@ 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];
gulong simcard_event_id[SIM_EVENT_COUNT];
gulong watch_ids[WATCH_EVENT_COUNT];
gboolean need_initial_attach_apn;
gboolean set_initial_attach_apn;
struct ofono_network_operator operator;
gboolean assert_rat;
};
enum ril_network_signal {
@@ -73,13 +102,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 };
@@ -103,7 +134,8 @@ G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_UMTS > OFONO_RADIO_ACCESS_MODE_GSM);
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_LTE > OFONO_RADIO_ACCESS_MODE_UMTS);
static void ril_network_query_pref_mode(struct ril_network *self);
static void ril_network_set_pref_mode(struct ril_network *self, int rat);
static void ril_network_check_pref_mode(struct ril_network *self,
gboolean immediate);
static void ril_network_emit(struct ril_network *self,
enum ril_network_signal sig)
@@ -200,8 +232,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 (!gutil_parse_int(slac, 16, &reg->lac)) {
reg->lac = -1;
}
if (!gutil_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",
@@ -386,12 +424,25 @@ static void ril_network_poll_state(struct ril_network *self)
priv->operator_poll_id = ril_network_poll_and_retry(self,
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
ril_network_poll_operator_cb);
priv->voice_poll_id = ril_network_poll_and_retry(self,
priv->voice_poll_id, RIL_REQUEST_VOICE_REGISTRATION_STATE,
ril_network_poll_voice_state_cb);
priv->data_poll_id = ril_network_poll_and_retry(self,
priv->data_poll_id, RIL_REQUEST_DATA_REGISTRATION_STATE,
ril_network_poll_data_state_cb);
ril_network_query_registration_state(self);
}
void ril_network_query_registration_state(struct ril_network *self)
{
if (self) {
struct ril_network_priv *priv = self->priv;
DBG_(self, "");
priv->voice_poll_id = ril_network_poll_and_retry(self,
priv->voice_poll_id,
RIL_REQUEST_VOICE_REGISTRATION_STATE,
ril_network_poll_voice_state_cb);
priv->data_poll_id = ril_network_poll_and_retry(self,
priv->data_poll_id,
RIL_REQUEST_DATA_REGISTRATION_STATE,
ril_network_poll_data_state_cb);
}
}
static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
@@ -417,22 +468,29 @@ static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
static int ril_network_mode_to_rat(struct ril_network *self,
enum ofono_radio_access_mode mode)
{
struct ril_sim_settings *settings = self->settings;
struct ril_network_priv *priv = self->priv;
switch (mode) {
case OFONO_RADIO_ACCESS_MODE_ANY:
case OFONO_RADIO_ACCESS_MODE_LTE:
if (self->settings->enable_4g) {
return PREF_NET_TYPE_LTE_GSM_WCDMA;
if (settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
return priv->lte_network_mode;
}
/* no break */
default:
case OFONO_RADIO_ACCESS_MODE_UMTS:
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
if (settings->techs & OFONO_RADIO_ACCESS_MODE_UMTS) {
return priv->umts_network_mode;
}
/* no break */
case OFONO_RADIO_ACCESS_MODE_GSM:
return PREF_NET_TYPE_GSM_ONLY;
}
}
static int ril_network_pref_mode_expected(struct ril_network *self)
static enum ofono_radio_access_mode ril_network_actual_pref_mode
(struct ril_network *self)
{
struct ril_sim_settings *settings = self->settings;
struct ril_network_priv *priv = self->priv;
@@ -447,7 +505,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;
/*
@@ -455,49 +513,129 @@ static int ril_network_pref_mode_expected(struct ril_network *self)
* and max_pref_mode are not ANY, we pick the smallest value.
* Otherwise we take any non-zero value if there is one.
*/
const enum ofono_radio_access_mode pref_mode =
(settings->pref_mode && max_pref_mode) ?
return (settings->pref_mode && max_pref_mode) ?
MIN(settings->pref_mode, max_pref_mode) :
settings->pref_mode ? settings->pref_mode :
max_pref_mode;
return ril_network_mode_to_rat(self, pref_mode);
settings->pref_mode ? settings->pref_mode : max_pref_mode;
}
static gboolean ril_network_need_initial_attach_apn(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
struct ril_radio *radio = priv->radio;
struct ofono_watch *watch = priv->watch;
if (watch->gprs && radio->state == RADIO_STATE_ON) {
switch (ril_network_actual_pref_mode(self)) {
case OFONO_RADIO_ACCESS_MODE_ANY:
case OFONO_RADIO_ACCESS_MODE_LTE:
return TRUE;
case OFONO_RADIO_ACCESS_MODE_UMTS:
case OFONO_RADIO_ACCESS_MODE_GSM:
break;
}
}
return FALSE;
}
static void ril_network_set_initial_attach_apn(struct ril_network *self,
const struct ofono_gprs_primary_context *ctx)
{
struct ril_network_priv *priv = self->priv;
const char *proto = ril_protocol_from_ofono(ctx->proto);
const char *username;
const char *password;
enum ril_auth auth;
GRilIoRequest *req;
if (ctx->username[0] || ctx->password[0]) {
auth = ril_auth_method_from_ofono(ctx->auth_method);
username = ctx->username;
password = ctx->password;
} else {
auth = RIL_AUTH_NONE;
username = "";
password = "";
}
req = ril_vendor_set_attach_apn_req(priv->vendor,
DATA_PROFILE_DEFAULT_STR, ctx->apn,
username, password, auth, proto);
if (!req) {
/* Default format */
req = grilio_request_new();
grilio_request_append_utf8(req, ctx->apn);
grilio_request_append_utf8(req, proto);
grilio_request_append_int32(req, auth);
grilio_request_append_utf8(req, username);
grilio_request_append_utf8(req, password);
}
DBG_(self, "\"%s\"", ctx->apn);
grilio_queue_send_request(priv->q, req,
RIL_REQUEST_SET_INITIAL_ATTACH_APN);
grilio_request_unref(req);
}
static void ril_network_try_set_initial_attach_apn(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
if (priv->need_initial_attach_apn && priv->set_initial_attach_apn) {
struct ofono_gprs *gprs = priv->watch->gprs;
const struct ofono_gprs_primary_context *ctx =
ofono_gprs_context_settings_by_type(gprs,
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
if (ctx) {
priv->set_initial_attach_apn = FALSE;
ril_network_set_initial_attach_apn(self, ctx);
}
}
}
static void ril_network_check_initial_attach_apn(struct ril_network *self)
{
const gboolean need = ril_network_need_initial_attach_apn(self);
struct ril_network_priv *priv = self->priv;
if (priv->need_initial_attach_apn != need) {
DBG_(self, "%sneed initial attach apn", need ? "" : "don't ");
priv->need_initial_attach_apn = need;
if (need) {
/* We didn't need initial attach APN and now we do */
priv->set_initial_attach_apn = TRUE;
}
}
ril_network_try_set_initial_attach_apn(self);
}
static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
return priv->radio->online && ril_sim_card_ready(priv->sim_card);
/*
* With some modems an attempt to set rat significantly slows
* down SIM I/O, let's avoid that.
*/
return priv->radio->online && ril_sim_card_ready(priv->simcard) &&
!priv->simcard->sim_io_active &&
!priv->timer[TIMER_SET_RAT_HOLDOFF] ;
}
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
const int rat = ril_network_pref_mode_expected(self);
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
GASSERT(priv->timer[TIMER_SET_RAT_HOLDOFF]);
priv->timer[TIMER_SET_RAT_HOLDOFF] = 0;
/*
* Don't retry the request if modem is offline or SIM card isn't
* ready, to avoid spamming system log with error messages. Radio
* and SIM card state change callbacks will schedule a new check
* when it's appropriate.
*/
if (priv->rat != rat) {
if (ril_network_can_set_pref_mode(self)) {
ril_network_set_pref_mode(self, rat);
} else {
DBG_(self, "giving up");
}
}
ril_network_check_pref_mode(self, FALSE);
return G_SOURCE_REMOVE;
}
static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
static void ril_network_set_rat_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
@@ -512,33 +650,57 @@ static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int status,
ril_network_query_pref_mode(self);
}
static void ril_network_set_rat(struct ril_network *self, int rat)
{
struct ril_network_priv *priv = self->priv;
if (!priv->set_rat_id && priv->radio->online &&
ril_sim_card_ready(priv->simcard) &&
/*
* With some modems an attempt to set rat significantly
* slows down SIM I/O, let's avoid that.
*/
!priv->simcard->sim_io_active &&
!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
GRilIoRequest *req = grilio_request_sized_new(8);
DBG_(self, "setting rat mode %d", rat);
grilio_request_append_int32(req, 1); /* count */
grilio_request_append_int32(req, rat);
grilio_request_set_timeout(req, priv->network_mode_timeout);
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
ril_network_set_rat_cb, NULL, self);
grilio_request_unref(req);
/* We have submitted the request, clear the assertion flag */
priv->assert_rat = FALSE;
/* And don't do it too often */
priv->timer[TIMER_SET_RAT_HOLDOFF] =
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
ril_network_set_rat_holdoff_cb, self);
} else {
DBG_(self, "need to set rat mode %d", rat);
}
}
static void ril_network_set_pref_mode(struct ril_network *self, int rat)
{
struct ril_network_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(8);
DBG_(self, "setting rat mode %d", rat);
grilio_request_append_int32(req, 1); /* Number of params */
grilio_request_append_int32(req, rat);
grilio_queue_cancel_request(priv->q, priv->set_rat_id, FALSE);
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
ril_network_set_pref_mode_cb, NULL, self);
grilio_request_unref(req);
/* Don't do it too often */
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
priv->timer[TIMER_SET_RAT_HOLDOFF] =
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
ril_network_set_rat_holdoff_cb, self);
if (priv->rat != rat || priv->assert_rat) {
ril_network_set_rat(self, rat);
}
}
static void ril_network_check_pref_mode(struct ril_network *self,
gboolean force)
gboolean immediate)
{
struct ril_network_priv *priv = self->priv;
const int rat = ril_network_pref_mode_expected(self);
const int rat = ril_network_mode_to_rat
(self, ril_network_actual_pref_mode(self));
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
ril_network_stop_timer(self, TIMER_FORCE_CHECK_PREF_MODE);
@@ -547,15 +709,18 @@ static void ril_network_check_pref_mode(struct ril_network *self,
* ril_network_pref_mode_changed_cb and is meant
* to force radio tech check right now.
*/
force = TRUE;
}
if (priv->rat == rat || force) {
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
immediate = TRUE;
}
if (priv->rat != rat) {
/* Something isn't right, we need to fix it */
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
}
if (immediate) {
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
}
if (priv->rat != rat || priv->assert_rat) {
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
ril_network_set_pref_mode(self, rat);
} else {
@@ -644,17 +809,26 @@ 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_initial_attach_apn(self);
}
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 +857,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 +876,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,11 +886,22 @@ static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
ril_network_poll_state(self);
}
static void ril_network_radio_capability_changed_cb(GRilIoChannel *io,
guint code, const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
DBG_(self, "");
GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
ril_network_assert_pref_mode(self, FALSE);
}
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
{
struct ril_network *self = RIL_NETWORK(data);
ril_network_check_pref_mode(self, FALSE);
ril_network_check_initial_attach_apn(self);
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(self);
}
@@ -734,6 +926,7 @@ static gboolean ril_network_check_pref_mode_cb(gpointer user_data)
DBG_(self, "checking pref mode");
ril_network_check_pref_mode(self, TRUE);
ril_network_check_initial_attach_apn(self);
return G_SOURCE_REMOVE;
}
@@ -767,9 +960,38 @@ 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_sim_settings *settings)
static void ril_network_watch_gprs_cb(struct ofono_watch *watch,
void* user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
DBG_(self, "gprs %s", watch->gprs ? "appeared" : "is gone");
priv->set_initial_attach_apn = TRUE;
ril_network_check_initial_attach_apn(self);
}
static void ril_network_watch_gprs_settings_cb(struct ofono_watch *watch,
enum ofono_gprs_context_type type,
const struct ofono_gprs_primary_context *settings,
void *user_data)
{
if (type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
priv->set_initial_attach_apn = TRUE;
ril_network_check_initial_attach_apn(self);
}
}
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *simcard,
struct ril_sim_settings *settings,
const struct ril_slot_config *config,
struct ril_vendor *vendor)
{
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
struct ril_network_priv *priv = self->priv;
@@ -778,25 +1000,51 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
priv->io = grilio_channel_ref(io);
priv->q = grilio_queue_new(priv->io);
priv->radio = ril_radio_ref(radio);
priv->sim_card = ril_sim_card_ref(sim_card);
priv->simcard = ril_sim_card_ref(simcard);
priv->vendor = ril_vendor_ref(vendor);
priv->watch = ofono_watch_new(path);
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,
/* Copy relevant config values */
priv->lte_network_mode = config->lte_network_mode;
priv->umts_network_mode = config->umts_network_mode;
priv->network_mode_timeout = config->network_mode_timeout;
/* Register listeners */
priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
grilio_channel_add_unsol_event_handler(priv->io,
ril_network_state_changed_cb,
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);
priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
ril_radio_add_online_changed_handler(priv->radio,
ril_network_radio_online_cb, self);
priv->simcard_event_id[SIM_EVENT_STATUS_CHANGED] =
ril_sim_card_add_status_changed_handler(priv->simcard,
ril_network_sim_status_changed_cb, self);
priv->simcard_event_id[SIM_EVENT_IO_ACTIVE_CHANGED] =
ril_sim_card_add_sim_io_active_changed_handler(priv->simcard,
ril_network_sim_status_changed_cb, self);
priv->settings_event_id =
ril_sim_settings_add_pref_mode_changed_handler(settings,
ril_network_pref_mode_changed_cb, self);
priv->sim_status_event_id =
ril_sim_card_add_status_changed_handler(priv->sim_card,
ril_network_sim_status_changed_cb, self);
priv->watch_ids[WATCH_EVENT_GPRS] =
ofono_watch_add_gprs_changed_handler(priv->watch,
ril_network_watch_gprs_cb, self);
priv->watch_ids[WATCH_EVENT_GPRS_SETTINGS] =
ofono_watch_add_gprs_settings_changed_handler(priv->watch,
ril_network_watch_gprs_settings_cb, self);
/*
* Query the initial state. Querying network state before the radio
@@ -809,6 +1057,12 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
ril_network_poll_state(self);
}
priv->set_initial_attach_apn =
priv->need_initial_attach_apn =
ril_network_need_initial_attach_apn(self);
ril_vendor_set_network(vendor, self);
ril_network_try_set_initial_attach_apn(self);
return self;
}
@@ -840,57 +1094,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);
}
ofono_watch_remove_all_handlers(priv->watch, priv->watch_ids);
ofono_watch_unref(priv->watch);
grilio_queue_cancel_all(priv->q, FALSE);
priv->set_rat_id = 0;
priv->query_rat_id = 0;
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_remove_all_handlers(priv->io, priv->unsol_event_id);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
ril_radio_unref(priv->radio);
ril_sim_card_unref(priv->sim_card);
ril_sim_card_remove_all_handlers(priv->simcard, priv->simcard_event_id);
ril_sim_card_unref(priv->simcard);
ril_sim_settings_remove_handler(self->settings,
priv->settings_event_id);
ril_sim_settings_unref(self->settings);
ril_vendor_unref(priv->vendor);
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-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,7 +18,7 @@
#include "ril_types.h"
#include <ofono/radio-settings.h>
#include <glib-object.h>
struct ofono_network_operator;
@@ -38,21 +38,27 @@ 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_sim_settings *settings);
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,
const struct ril_slot_config *ril_slot_config,
struct ril_vendor *vendor);
struct ril_network *ril_network_ref(struct ril_network *net);
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);
void ril_network_query_registration_state(struct ril_network *net);
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
@@ -61,9 +67,14 @@ 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);
#define ril_network_remove_all_handlers(net, ids) \
ril_network_remove_handlers(net, ids, G_N_ELEMENTS(ids))
#endif /* RIL_NETWORK_H */
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-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

@@ -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,103 +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;
GHashTable *errors;
};
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);
void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
int index, const char *id, const char *message);
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,
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)
@@ -147,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,956 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* 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
* 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 (6)
#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_SIGNAL_MODEM_ERROR "ModemError"
#define RIL_DBUS_IMSI_AUTO "auto"
#define RIL_DBUS_ERROR_SIGNATURE "si"
static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
{
return slot->enabled;
}
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_append_modem_error(DBusMessageIter *it,
const char *id, dbus_uint32_t count)
{
DBusMessageIter sub;
dbus_message_iter_open_container(it, DBUS_TYPE_STRUCT, NULL, &sub);
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id);
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &count);
dbus_message_iter_close_container(it, &sub);
}
static void ril_plugin_dbus_append_modem_errors(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
DBusMessageIter slots;
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
"a(" RIL_DBUS_ERROR_SIGNATURE ")", &slots);
while (*ptr) {
const struct ril_slot_info *slot = *ptr++;
DBusMessageIter errors;
dbus_message_iter_open_container(&slots, DBUS_TYPE_ARRAY,
"(" RIL_DBUS_ERROR_SIGNATURE ")", &errors);
if (g_hash_table_size(slot->errors)) {
gpointer key, value;
GHashTableIter iter;
g_hash_table_iter_init(&iter, slot->errors);
while (g_hash_table_iter_next(&iter, &key, &value)) {
ril_plugin_dbus_append_modem_error(&errors,
key, GPOINTER_TO_INT(value));
}
}
dbus_message_iter_close_container(&slots, &errors);
}
dbus_message_iter_close_container(it, &slots);
}
static void ril_plugin_dbus_signal_path_array(struct ril_plugin_dbus *dbus,
const char *name, ril_plugin_dbus_slot_select_fn fn)
{
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);
}
void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
int index, const char *id, const char *message)
{
const char *path = dbus->plugin->slots[index]->path;
if (!message) message = "";
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
RIL_DBUS_SIGNAL_MODEM_ERROR,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_STRING, &id,
DBUS_TYPE_STRING, &message,
DBUS_TYPE_INVALID);
}
static DBusMessage *ril_plugin_dbus_reply_with_path_array(DBusMessage *msg,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
{
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 void ril_plugin_dbus_append_all6(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all5(it, dbus);
ril_plugin_dbus_append_modem_errors(it, dbus);
}
static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
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_all6(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all6);
}
static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
DBusMessage *msg, void *data)
{
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_get_modem_errors(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_modem_errors);
}
static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
DBusMessage *msg, void *data)
{
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_VERSION_ARG {"version", "i"}
#define RIL_DBUS_AVAILABLE_MODEMS_ARG {"availableModems", "ao"}
#define RIL_DBUS_ENABLED_MODEMS_ARG {"enabledModems", "ao" }
#define RIL_DBUS_DEFAULT_DATA_SIM_ARG {"defaultDataSim", "s" }
#define RIL_DBUS_DEFAULT_VOICE_SIM_ARG {"defaultVoiceSim", "s" }
#define RIL_DBUS_DEFAULT_DATA_MODEM_ARG {"defaultDataModem", "s" }
#define RIL_DBUS_DEFAULT_VOICE_MODEM_ARG {"defaultVoiceModem" , "s"}
#define RIL_DBUS_PRESENT_SIMS_ARG {"presentSims" , "ab"}
#define RIL_DBUS_IMEI_ARG {"imei" , "as"}
#define RIL_DBUS_MMS_SIM_ARG {"mmsSim", "s"}
#define RIL_DBUS_MMS_MODEM_ARG {"mmsModem" , "s"}
#define RIL_DBUS_READY_ARG {"ready" , "b"}
#define RIL_DBUS_MODEM_ERRORS_ARG {"errors" , \
"aa(" RIL_DBUS_ERROR_SIGNATURE ")"}
#define RIL_DBUS_GET_ALL_ARGS \
RIL_DBUS_VERSION_ARG, \
RIL_DBUS_AVAILABLE_MODEMS_ARG, \
RIL_DBUS_ENABLED_MODEMS_ARG, \
RIL_DBUS_DEFAULT_DATA_SIM_ARG, \
RIL_DBUS_DEFAULT_VOICE_SIM_ARG, \
RIL_DBUS_DEFAULT_DATA_MODEM_ARG, \
RIL_DBUS_DEFAULT_VOICE_MODEM_ARG
#define RIL_DBUS_GET_ALL2_ARGS \
RIL_DBUS_GET_ALL_ARGS, \
RIL_DBUS_PRESENT_SIMS_ARG
#define RIL_DBUS_GET_ALL3_ARGS \
RIL_DBUS_GET_ALL2_ARGS, \
RIL_DBUS_IMEI_ARG
#define RIL_DBUS_GET_ALL4_ARGS \
RIL_DBUS_GET_ALL3_ARGS, \
RIL_DBUS_MMS_SIM_ARG, \
RIL_DBUS_MMS_MODEM_ARG
#define RIL_DBUS_GET_ALL5_ARGS \
RIL_DBUS_GET_ALL4_ARGS, \
RIL_DBUS_READY_ARG
#define RIL_DBUS_GET_ALL6_ARGS \
RIL_DBUS_GET_ALL5_ARGS, \
RIL_DBUS_MODEM_ERRORS_ARG
static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
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_ASYNC_METHOD("GetAll6",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL6_ARGS),
ril_plugin_dbus_get_all6) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS(RIL_DBUS_VERSION_ARG),
ril_plugin_dbus_get_interface_version) },
{ GDBUS_METHOD("GetAvailableModems",
NULL, GDBUS_ARGS(RIL_DBUS_AVAILABLE_MODEMS_ARG),
ril_plugin_dbus_get_available_modems) },
{ GDBUS_METHOD("GetEnabledModems",
NULL, GDBUS_ARGS(RIL_DBUS_ENABLED_MODEMS_ARG),
ril_plugin_dbus_get_enabled_modems) },
{ GDBUS_METHOD("GetPresentSims",
NULL, GDBUS_ARGS(RIL_DBUS_PRESENT_SIMS_ARG),
ril_plugin_dbus_get_present_sims) },
{ GDBUS_ASYNC_METHOD("GetIMEI",
NULL, GDBUS_ARGS(RIL_DBUS_IMEI_ARG),
ril_plugin_dbus_get_imei) },
{ GDBUS_METHOD("GetDefaultDataSim",
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG),
ril_plugin_dbus_get_default_data_sim) },
{ GDBUS_METHOD("GetDefaultVoiceSim",
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG),
ril_plugin_dbus_get_default_voice_sim) },
{ GDBUS_METHOD("GetMmsSim",
NULL, GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG),
ril_plugin_dbus_get_mms_sim) },
{ GDBUS_METHOD("GetDefaultDataModem",
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG),
ril_plugin_dbus_get_default_data_modem) },
{ GDBUS_METHOD("GetDefaultVoiceModem",
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG),
ril_plugin_dbus_get_default_voice_modem) },
{ GDBUS_METHOD("GetMmsModem",
NULL, GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG),
ril_plugin_dbus_get_mms_modem) },
{ GDBUS_METHOD("GetReady",
NULL, GDBUS_ARGS(RIL_DBUS_READY_ARG),
ril_plugin_dbus_get_ready) },
{ GDBUS_METHOD("GetModemErrors",
NULL, GDBUS_ARGS(RIL_DBUS_MODEM_ERRORS_ARG),
ril_plugin_dbus_get_modem_errors) },
{ GDBUS_METHOD("SetEnabledModems",
GDBUS_ARGS({ "modems", "ao" }), NULL,
ril_plugin_dbus_set_enabled_modems) },
{ 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(RIL_DBUS_ENABLED_MODEMS_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
GDBUS_ARGS({"index", "i" },
{"present" , "b"})) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_READY_CHANGED,
GDBUS_ARGS(RIL_DBUS_READY_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MODEM_ERROR,
GDBUS_ARGS({"path","o"},
{"error_id", "s"},
{"message", "s"})) },
{ }
};
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-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -71,14 +71,16 @@ G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
#define RIL_RADIO_TYPE (ril_radio_get_type())
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
return self->online && !priv->power_cycle &&
g_hash_table_size(priv->req_table) > 0;
return (self->online || g_hash_table_size(priv->req_table) > 0) &&
!priv->power_cycle;
}
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
@@ -99,13 +101,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);
DBG_(self, "");
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;
}
@@ -115,7 +118,7 @@ static void ril_radio_cancel_retry(struct ril_radio *self)
struct ril_radio_priv *priv = self->priv;
if (priv->retry_id) {
DBG("%sretry cancelled", priv->log_prefix);
DBG_(self, "retry cancelled");
g_source_remove(priv->retry_id);
priv->retry_id = 0;
}
@@ -126,10 +129,10 @@ 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) {
if (ril_radio_state_on(priv->last_known_state) ==
should_be_on) {
/* All is good, cancel pending retry if there is one */
ril_radio_cancel_retry(self);
} else if (priv->state_changed_while_request_pending) {
@@ -137,7 +140,7 @@ static void ril_radio_check_state(struct ril_radio *self)
ril_radio_submit_power_request(self, should_be_on);
} else if (!priv->retry_id) {
/* There has been no reaction so far, wait a bit */
DBG("%sretry scheduled", priv->log_prefix);
DBG_(self, "retry scheduled");
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
ril_radio_power_request_retry_cb, self);
}
@@ -146,28 +149,20 @@ static void ril_radio_check_state(struct ril_radio *self)
/* Don't update public state while something is pending */
if (!priv->pending_id && !priv->retry_id &&
self->state != priv->last_known_state) {
DBG("%s%s -> %s", priv->log_prefix,
ril_radio_state_to_string(self->state),
DBG_(self, "%s -> %s", ril_radio_state_to_string(self->state),
ril_radio_state_to_string(priv->last_known_state));
self->state = priv->last_known_state;
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
}
}
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
const void *data, guint len, void *user_data)
static void ril_radio_power_request_done(struct ril_radio *self)
{
struct ril_radio *self = user_data;
struct ril_radio_priv *priv = self->priv;
GASSERT(priv->pending_id);
priv->pending_id = 0;
if (ril_status != RIL_E_SUCCESS) {
ofono_error("Power request failed: %s",
ril_error_to_string(ril_status));
}
if (priv->next_state_valid) {
ril_radio_submit_power_request(self, priv->next_state);
} else {
@@ -175,13 +170,32 @@ static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
}
}
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_radio *self = RIL_RADIO(user_data);
if (ril_status != RIL_E_SUCCESS) {
ofono_error("Power request failed: %s",
ril_error_to_string(ril_status));
}
ril_radio_power_request_done(self);
}
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 +203,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);
}
@@ -205,13 +221,18 @@ static void ril_radio_power_request(struct ril_radio *self, gboolean on,
/* Wait for the pending request to complete */
priv->next_state_valid = TRUE;
priv->next_state = on;
DBG("%s%s (queued)", priv->log_prefix, on_off);
DBG_(self, "%s (queued)", on_off);
} else {
DBG("%s%s (ignored)", priv->log_prefix, on_off);
DBG_(self, "%s (ignored)", on_off);
}
} else {
DBG("%s%s", priv->log_prefix, on_off);
ril_radio_submit_power_request(self, on);
if (ril_radio_state_on(priv->last_known_state) == on) {
DBG_(self, "%s (already)", on_off);
ril_radio_check_state(self);
} else {
DBG_(self, "%s", on_off);
ril_radio_submit_power_request(self, on);
}
}
}
@@ -228,12 +249,12 @@ void ril_radio_power_cycle(struct ril_radio *self)
struct ril_radio_priv *priv = self->priv;
if (ril_radio_state_off(priv->last_known_state)) {
DBG("%spower is already off", priv->log_prefix);
DBG_(self, "power is already off");
GASSERT(!priv->power_cycle);
} else if (priv->power_cycle) {
DBG("%salready in progress", priv->log_prefix);
DBG_(self, "already in progress");
} else {
DBG("%sinitiated", priv->log_prefix);
DBG_(self, "initiated");
priv->power_cycle = TRUE;
if (!priv->pending_id) {
ril_radio_submit_power_request(self, FALSE);
@@ -250,7 +271,7 @@ void ril_radio_power_on(struct ril_radio *self, gpointer tag)
if (!g_hash_table_contains(priv->req_table, tag)) {
gboolean was_on = ril_radio_power_should_be_on(self);
DBG("%s%p", priv->log_prefix, tag);
DBG_(self, "%p", tag);
g_hash_table_insert(priv->req_table, tag, tag);
if (!was_on && ril_radio_power_should_be_on(self)) {
ril_radio_power_request(self, TRUE, FALSE);
@@ -265,7 +286,7 @@ void ril_radio_power_off(struct ril_radio *self, gpointer tag)
struct ril_radio_priv *priv = self->priv;
if (g_hash_table_remove(priv->req_table, tag)) {
DBG("%s%p", priv->log_prefix, tag);
DBG_(self, "%p", tag);
if (!ril_radio_power_should_be_on(self)) {
/* The last one turns the lights off */
ril_radio_power_request(self, FALSE, FALSE);
@@ -330,27 +351,48 @@ 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);
if (radio_state != RADIO_STATE_UNAVAILABLE) {
struct ril_radio_priv *priv = self->priv;
DBG("%s%s", priv->log_prefix,
ril_radio_state_to_string(radio_state));
DBG_(self, "%s", ril_radio_state_to_string(radio_state));
GASSERT(!priv->pending_id || !priv->retry_id);
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
DBG("%sswitched off for power cycle", priv->log_prefix);
DBG_(self, "switched off for power cycle");
priv->power_cycle = FALSE;
}
priv->last_known_state = radio_state;
if (priv->pending_id) {
priv->state_changed_while_request_pending++;
if (ril_radio_state_on(radio_state) ==
ril_radio_power_should_be_on(self)) {
DBG_(self, "dropping pending request");
/*
* All right, the modem has switched to the
* desired state, drop the request.
*/
grilio_queue_cancel_request(priv->q,
priv->pending_id, FALSE);
/*
* This will zero pending_id and call
* ril_radio_check_state() if necesary:
*/
ril_radio_power_request_done(self);
/* We are done */
return;
} else {
/* Something weird is going on */
priv->state_changed_while_request_pending++;
}
}
priv->last_known_state = radio_state;
ril_radio_check_state(self);
}
}
@@ -365,10 +407,15 @@ struct ril_radio *ril_radio_new(GRilIoChannel *io)
priv->log_prefix =
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
g_strconcat(io->name, " ", NULL) : g_strdup("");
DBG("%s", priv->log_prefix);
DBG_(self, "");
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_radio_state_changed,
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
/*
* Some RILs like to receive power off request at startup even if
* radio is already off. Make those happy.
*/
ril_radio_submit_power_request(self, FALSE);
return self;
}
@@ -422,7 +469,7 @@ static void ril_radio_finalize(GObject *object)
struct ril_radio *self = RIL_RADIO(object);
struct ril_radio_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
DBG_(self, "");
g_free(priv->log_prefix);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);

View File

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

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-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,26 @@
#include <gutil_misc.h>
/*
* First we wait for USIM app to get activated by itself. If that
* doesn't happen within UICC_SUBSCRIPTION_START_MS we poke the SIM
* with SET_UICC_SUBSCRIPTION request, resubmitting it if it times out.
* If nothing happens within UICC_SUBSCRIPTION_TIMEOUT_MS we give up.
*
* Submitting SET_UICC_SUBSCRIPTION request when rild doesn't expect
* it sometimes breaks pretty much everything. Unfortunately, there no
* reliable way to find out when rild expects it and when it doesn't :/
*/
#define UICC_SUBSCRIPTION_START_MS (5000)
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
/* SIM I/O idle timeout is measured in the number of idle loops.
* 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 +58,12 @@ struct ril_sim_card_priv {
GRilIoQueue *q;
int flags;
guint status_req_id;
guint sub_req_id;
guint sub_start_timer;
gulong event_id[EVENT_COUNT];
guint sim_io_idle_id;
guint sim_io_idle_count;
GHashTable* sim_io_pending;
};
enum ril_sim_card_signal {
@@ -46,13 +71,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 +88,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,29 +169,115 @@ 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_tx_start(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
GRILIO_TRANSACTION_STATE tx_state =
grilio_queue_transaction_state(priv->q);
if (tx_state == GRILIO_TRANSACTION_NONE) {
tx_state = grilio_queue_transaction_start(priv->q);
DBG("status tx for slot %u %s", self->slot,
(tx_state == GRILIO_TRANSACTION_STARTED) ?
"started" : "starting");
}
}
static void ril_sim_card_tx_check(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
if (grilio_queue_transaction_state(priv->q) !=
GRILIO_TRANSACTION_NONE) {
const struct ril_sim_card_status *status = self->status;
if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
/* Transaction (if there is any) is finished when
* both GET_SIM_STATUS and SET_UICC_SUBSCRIPTION
* complete or get dropped */
if (!priv->status_req_id && !priv->sub_req_id &&
status->gsm_umts_index >= 0 &&
status->gsm_umts_index < status->num_apps) {
DBG("status tx for slot %u finished",
self->slot);
grilio_queue_transaction_finish(priv->q);
}
} else {
DBG("status tx for slot %u cancelled", self->slot);
grilio_queue_transaction_finish(priv->q);
}
}
}
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
if (priv->sub_start_timer) {
/* Don't need this timer anymore */
g_source_remove(priv->sub_start_timer);
priv->sub_start_timer = 0;
}
if (priv->sub_req_id) {
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
* so we better drop rather than cancel it (so that it gets
* removed from the list of pending requests) */
grilio_channel_drop_request(priv->io, priv->sub_req_id);
priv->sub_req_id = 0;
}
ril_sim_card_tx_check(self);
}
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)
{
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", self->slot, app_index, sub_id);
grilio_request_append_int32(req, self->slot);
grilio_request_append_int32(req, app_index);
grilio_request_append_int32(req, sub_id);
grilio_request_append_int32(req, sub_status);
grilio_queue_send_request(priv->q, req, (priv->io->ril_version <= 9 &&
grilio_request_append_int32(req, RIL_UICC_SUBSCRIPTION_ACTIVATE);
grilio_request_set_retry(req, 0, -1);
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
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 */
ril_sim_card_tx_start(self);
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
req, code, ril_sim_card_subscribe_cb, NULL, self);
grilio_request_unref(req);
}
static int ril_sim_card_select_app(const struct ril_sim_card_status *status)
{
int selected_app = -1;
guint i;
int i, selected_app = -1;
for (i = 0; i < status->num_apps; i++) {
const int type = status->apps[i].app_type;
@@ -185,14 +303,16 @@ 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);
if (app_index >= 0 && !self->priv->sub_start_timer) {
ril_sim_card_subscribe(self, app_index);
}
}
} else {
app_index = -1;
ril_sim_card_subscription_done(self);
}
if (app_index >= 0 &&
@@ -203,11 +323,23 @@ 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);
}
}
static gboolean ril_sim_card_sub_start_timeout(gpointer user_data)
{
struct ril_sim_card *self = RIL_SIMCARD(user_data);
struct ril_sim_card_priv *priv = self->priv;
DBG("%u", self->slot);
GASSERT(priv->sub_start_timer);
priv->sub_start_timer = 0;
ril_sim_card_update_app(self);
return G_SOURCE_REMOVE;
}
static void ril_sim_card_update_status(struct ril_sim_card *self,
struct ril_sim_card_status *status)
{
@@ -217,24 +349,42 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
struct ril_sim_card_status *old_status = self->status;
self->status = status;
if (diff & RIL_SIMCARD_STATE_CHANGED &&
status->card_state == RIL_CARDSTATE_PRESENT) {
struct ril_sim_card_priv *priv = self->priv;
/*
* SIM card has just appeared, give it some time to
* activate the USIM app
*/
if (priv->sub_start_timer) {
g_source_remove(priv->sub_start_timer);
}
DBG("started subscription timeout for slot %u",
self->slot);
priv->sub_start_timer =
g_timeout_add(UICC_SUBSCRIPTION_START_MS,
ril_sim_card_sub_start_timeout, self);
}
ril_sim_card_update_app(self);
g_signal_emit(self, ril_sim_card_signals[
SIGNAL_STATUS_RECEIVED], 0);
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_update_app(self);
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 +467,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 +489,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 +501,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);
@@ -363,30 +515,128 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
ril_sim_card_update_status(self, status);
}
}
ril_sim_card_tx_check(self);
}
static void ril_sim_card_request_status(struct ril_sim_card *self)
void ril_sim_card_reset(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
if (G_LIKELY(self)) {
struct ril_sim_card_status *status =
g_new0(struct ril_sim_card_status, 1);
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();
/* Simulate removal and re-submit the SIM status query */
status->card_state = RIL_CARDSTATE_ABSENT;
status->gsm_umts_index = -1;
status->cdma_index = -1;
status->ims_index = -1;
ril_sim_card_update_status(self, status);
ril_sim_card_request_status(self);
}
}
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
priv->status_req_id = grilio_queue_send_request_full(priv->q,
void ril_sim_card_request_status(struct ril_sim_card *self)
{
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();
/* Start the transaction to not allow any other
* requests to interfere with SIM status query */
ril_sim_card_tx_start(self);
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
priv->status_req_id =
grilio_queue_send_request_full(priv->q,
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 +724,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 +745,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 +767,13 @@ 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);
}
if (priv->sub_start_timer) {
g_source_remove(priv->sub_start_timer);
}
g_hash_table_destroy(priv->sim_io_pending);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
ril_sim_card_status_free(self->status);
@@ -520,22 +787,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-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,8 @@
#include "ril_types.h"
#include <glib-object.h>
struct ril_sim_card_app {
enum ril_app_type app_type;
enum ril_app_state app_state;
@@ -44,6 +46,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 +58,10 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
void ril_sim_card_unref(struct ril_sim_card *sc);
void ril_sim_card_reset(struct ril_sim_card *sc);
void ril_sim_card_request_status(struct ril_sim_card *sc);
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
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,13 +71,19 @@ 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);
/* Inline wrappers */
static inline enum ril_app_type
ril_sim_card_app_type(struct ril_sim_card *sc)
static inline enum ril_app_type ril_sim_card_app_type(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
static inline const char *ril_sim_card_app_aid(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->aid : NULL; }
#define ril_sim_card_remove_all_handlers(net, ids) \
ril_sim_card_remove_handlers(net, ids, G_N_ELEMENTS(ids))
#endif /* RIL_SIM_CARD_H */

View File

@@ -1,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,53 +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.
*/
#ifndef RIL_SIM_INFO_H
#define RIL_SIM_INFO_H
#include "ril_types.h"
struct ril_sim_info {
GObject object;
struct ril_sim_info_priv *priv;
const char *iccid;
const char *imsi;
const char *spn;
};
struct ofono_sim;
typedef void (*ril_sim_info_cb_t)(struct ril_sim_info *info, void *arg);
struct ril_sim_info *ril_sim_info_new(const char *log_prefix);
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *info);
void ril_sim_info_unref(struct ril_sim_info *si);
void ril_sim_info_set_ofono_sim(struct ril_sim_info *si, struct ofono_sim *sim);
void ril_sim_info_set_network(struct ril_sim_info *si, struct ril_network *net);
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *si,
ril_sim_info_cb_t cb, void *arg);
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *si,
ril_sim_info_cb_t cb, void *arg);
gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *si,
ril_sim_info_cb_t cb, void *arg);
void ril_sim_info_remove_handler(struct ril_sim_info *si, gulong id);
#endif /* RIL_SIM_INFO_H */
/*
* 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-2019 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,27 +16,28 @@
#include "ril_sim_settings.h"
#include "ril_log.h"
#include <ofono/watch.h>
#include <gutil_misc.h>
#include <ofono/sim.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 ofono_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;
GKeyFile *storage;
gulong watch_event_id[WATCH_EVENT_COUNT];
struct ofono_watch *watch;
char *imsi;
};
@@ -62,176 +63,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 ofono_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 = ofono_watch_new(path);
priv->watch_event_id[WATCH_EVENT_IMSI] =
ofono_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 +162,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);
ofono_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
ofono_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-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,26 +18,24 @@
#include "ril_types.h"
#include <ofono/radio-settings.h>
#include <glib-object.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,
struct ofono_sim *sim);
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *s,
enum ofono_radio_access_mode mode);
gulong ril_sim_settings_add_imsi_changed_handler(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);
}
@@ -471,7 +471,7 @@ static int ril_sms_probe(struct ofono_sms *sms, unsigned int vendor,
static void ril_sms_remove(struct ofono_sms *sms)
{
int i;
unsigned int i;
struct ril_sms *sd = ril_sms_get_data(sms);
DBG("");

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"
@@ -269,7 +268,7 @@ static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor, void *data)
static void ril_stk_remove(struct ofono_stk *stk)
{
struct ril_stk *sd = ril_stk_get_data(stk);
int i;
unsigned int i;
DBG("");
ofono_stk_set_data(stk, NULL);

View File

@@ -17,10 +17,17 @@
# If it's set to true, all [ril_x] sections are ignored even
# if they are present, and no default configurtation is created.
#
# Default is false
# Default false
#
#EmptyConfig=false
# User and group for the ofono process. RIL clients are typically
# expected to run under radio:radio.
#
# Default 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
@@ -30,11 +37,22 @@
# 3G/LTE modules for each slot or you don't need 4G for both slots).
# Obviously, it only has any effect if you have more than one SIM.
#
# Default is true (switch the current data modem to 2G when changing
# Defaults to true (switch the current data modem to 2G when changing
# the data modems)
#
#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 auto (enable for RIL version >= 11)
#
#SetRadioCapability=auto
[ril_0]
# Required entry, defines the RIL socket path
@@ -63,13 +81,19 @@ socket=/dev/socket/rild
# RIL request timeout, in milliseconds.
#
# The default is zero (no timeout)
# Default zero (no timeout)
#
#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
# Default all
#
#technologies=all
# This one is deprecated, use the technologies entry instead (above).
#
#enable4G=true
@@ -78,7 +102,7 @@ socket=/dev/socket/rild
# which RIL version it's dealing with, it makes the decision at runtime.
# Settings it to false disables the workaround and always sends 122.
#
# Default is true (select SET_UICC_SUBSCRIPTION based on the RIL version)
# Default true (select SET_UICC_SUBSCRIPTION based on the RIL version)
#
#uiccWorkaround=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 auto (enable for RIL version >= 11)
#
#allowDataReq=auto
@@ -110,7 +134,7 @@ socket=/dev/socket/rild
# actually does check the empty pin (and decrements the retry count)
# then you should turn this feature off.
#
# Default is true
# Default true
#
#emptyPinQuery=true
@@ -122,7 +146,7 @@ socket=/dev/socket/rild
# but sometimes you have to explicitly tell ofono which one to use.
# Possible values are 6, 9, 11 and auto.
#
# Default is auto
# Default auto
#
#dataCallFormat=auto
@@ -131,7 +155,7 @@ socket=/dev/socket/rild
# this parameter. Usually, one retry is enough. The first retry occurs
# immediately, the subsequent ones after dataCallRetryDelay (see below)
#
# Default is 4
# Default 4
#
#dataCallRetryLimit=4
@@ -139,7 +163,7 @@ socket=/dev/socket/rild
# retry occurs immediately after the first failure, the delays are only
# applied if the first retry fails too.
#
# Default is 200 ms
# Default 200 ms
#
#dataCallRetryDelay=200
@@ -151,3 +175,92 @@ socket=/dev/socket/rild
#
#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
# Support for Cell Broadcast System (CBS). By default, its enabled but if
# your rild and/or modem is not happy about it, you can turn it off.
#
# Default true
#
#enableCellBroadcast=true
# Support for Sim Toolkit (STK). By default, its enabled but if your rild
# and/or modem is not happy about it, you can turn it off.
#
# Default true
#
#enableSimToolkit=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.
#
# Default 20000 (20 seconds)
#
#startTimeout=20000
# This allows to use deprecated RIL_REQUEST_GET_IMEI instead of
# RIL_REQUEST_DEVICE_IDENTITY to query IMEI from the modem. Some
# RILs (e.g. MTK) still don't understand RIL_REQUEST_DEVICE_IDENTITY.
#
# Default false (use RIL_REQUEST_DEVICE_IDENTITY)
#
#legacyImeiQuery=false
# Some devices don't support LTE RAT mode PREF_NET_TYPE_LTE_GSM_WCDMA.
# This option allows to set a custom LTE mode.
#
# Default 9 (PREF_NET_TYPE_LTE_GSM_WCDMA)
#
#lteNetworkMode=9
# Timeout for RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, in milliseconds.
#
# Default 20000 (20 seconds)
#
#networkModeTimeout=20000
# Cycle radio power at startup.
#
# Default true (cycle the power)
#
#radioPowerCycle=true
# With some RILs it seems to be necessary to kick (RIL_REQUEST_RADIO_POWER)
# the modems with power on after one of the modems has been powered off.
# Otherwise bad things may happen (like the modem never registering
# on the network).
#
# On the other hand, with some RILs it's causing some trouble (like this
# extra RIL_REQUEST_RADIO_POWER getting stuck indefinitely).
#
# Default true (for historical reasons)
#
#confirmRadioPowerOn=true
# Normally we should be able to have two simultaneously active data
# contexts - one for mobile data and one for MMS. Some devices however
# require that mobile data is disconnected before we can send or receive
# MMS. In other words, activation of the second data context fails.
#
# Default false (more than one context is supported)
#
#singleDataContext=false
# Configures whether +0 is added to MCCMNC string passed to
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL. Some Qualcomm RILs
# require it, some MediaTek RILs don't like it.
#
# Default true
#
#networkSelectionManual0=true

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2019 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,28 @@ struct ofono_sim;
#define RIL_RETRY_SECS (2)
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
struct ril_mce;
struct ril_data;
struct ril_data_call;
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_vendor;
struct ril_slot_config {
guint slot;
gboolean enable_4g;
enum ofono_radio_access_mode techs;
enum ril_pref_net_type lte_network_mode;
enum ril_pref_net_type umts_network_mode;
int network_mode_timeout;
gboolean query_available_band_mode;
gboolean empty_pin_query;
gboolean radio_power_cycle;
gboolean confirm_radio_power_on;
gboolean enable_voicecall;
gboolean enable_cbs;
gboolean enable_stk;
gboolean network_selection_manual_0;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
};

View File

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

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2019 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,12 +18,18 @@
#include <grilio_channel.h>
#include <gutil_misc.h>
#include <sys/socket.h>
#include <ctype.h>
#include "common.h"
#include "netreg.h"
#define RIL_PROTO_IP_STR "IP"
#define RIL_PROTO_IPV6_STR "IPV6"
#define RIL_PROTO_IPV4V6_STR "IPV4V6"
const char *ril_error_to_string(int error)
{
#define RIL_E_(name) case RIL_E_##name: return #name
@@ -48,7 +54,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 +64,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 +239,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;
@@ -288,13 +325,56 @@ const char *ril_radio_state_to_string(int radio_state)
}
}
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto)
{
switch (proto) {
case OFONO_GPRS_PROTO_IPV6:
return RIL_PROTO_IPV6_STR;
case OFONO_GPRS_PROTO_IPV4V6:
return RIL_PROTO_IPV4V6_STR;
case OFONO_GPRS_PROTO_IP:
return RIL_PROTO_IP_STR;
}
return NULL;
}
int ril_protocol_to_ofono(const gchar *str)
{
if (str) {
if (!strcmp(str, RIL_PROTO_IPV6_STR)) {
return OFONO_GPRS_PROTO_IPV6;
} else if (!strcmp(str, RIL_PROTO_IPV4V6_STR)) {
return OFONO_GPRS_PROTO_IPV4V6;
} else if (!strcmp(str, RIL_PROTO_IP_STR)) {
return OFONO_GPRS_PROTO_IP;
}
}
return -1;
}
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth)
{
switch (auth) {
case OFONO_GPRS_AUTH_METHOD_NONE:
return RIL_AUTH_NONE;
case OFONO_GPRS_AUTH_METHOD_CHAP:
return RIL_AUTH_CHAP;
case OFONO_GPRS_AUTH_METHOD_PAP:
return RIL_AUTH_PAP;
case OFONO_GPRS_AUTH_METHOD_ANY:
/* Use default */
break;
}
/* Default */
return RIL_AUTH_BOTH;
}
/* Returns enum access_technology or -1 on failure. */
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 (gutil_parse_int(stech, 0, &tech)) {
switch (tech) {
case RADIO_TECH_GPRS:
case RADIO_TECH_GSM:
@@ -351,8 +431,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++;
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2019 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,12 +18,17 @@
#include "ril_types.h"
#include <ofono/gprs-context.h>
struct ofono_network_operator;
const char *ril_error_to_string(int error);
const char *ril_request_to_string(guint request);
const char *ril_unsol_event_to_string(guint event);
const char *ril_radio_state_to_string(int radio_state);
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto);
int ril_protocol_to_ofono(const char *str);
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth);
int ril_parse_tech(const char *stech, int *ril_tech);
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);

View File

@@ -0,0 +1,202 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 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_vendor.h"
#include "ril_vendor_impl.h"
#include "ril_log.h"
#include <grilio_channel.h>
G_DEFINE_ABSTRACT_TYPE(RilVendor, ril_vendor, G_TYPE_OBJECT)
/* Vendor driver descriptors are in the "__vendor" section */
extern const struct ril_vendor_driver __start___vendor[];
extern const struct ril_vendor_driver __stop___vendor[];
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name)
{
if (name) {
const struct ril_vendor_driver *d;
for (d = __start___vendor; d < __stop___vendor; d++) {
if (!strcasecmp(d->name, name)) {
return d;
}
}
}
return NULL;
}
RilVendor *ril_vendor_create(const struct ril_vendor_driver *driver,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *config)
{
return (driver && driver->create_vendor) ?
driver->create_vendor(driver->driver_data, io, path, config) :
NULL;
}
RilVendor *ril_vendor_ref(RilVendor *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_VENDOR(self));
}
return self;
}
void ril_vendor_unref(RilVendor *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_VENDOR(self));
}
}
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
struct ril_vendor_defaults *defaults)
{
if (vendor && vendor->get_defaults) {
vendor->get_defaults(defaults);
}
}
const char *ril_vendor_request_to_string(RilVendor *self, guint request)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
request_to_string(self, request) : NULL;
}
const char *ril_vendor_event_to_string(RilVendor *self, guint event)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
event_to_string(self, event) : NULL;
}
void ril_vendor_set_network(RilVendor *self, struct ril_network *nw)
{
if (G_LIKELY(self)) {
RIL_VENDOR_GET_CLASS(self)->set_network(self, nw);
}
}
GRilIoRequest *ril_vendor_set_attach_apn_req(RilVendor *self,
const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
set_attach_apn_req(self, profile, apn, username, password,
auth, proto) : NULL;
}
GRilIoRequest *ril_vendor_data_call_req(RilVendor *self,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
data_call_req(self, tech, profile, apn, username, password,
auth, proto) : NULL;
}
gboolean ril_vendor_data_call_parse(RilVendor *self,
struct ril_data_call *call, int ver, GRilIoParser *rilp)
{
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
data_call_parse(self, call, ver, rilp);
}
static void ril_vendor_default_set_network(RilVendor *self,
struct ril_network *network)
{
if (self->network != network) {
if (self->network) {
g_object_remove_weak_pointer(G_OBJECT(self->network),
(gpointer*) &self->network);
}
self->network = network;
if (self->network) {
g_object_add_weak_pointer(G_OBJECT(network),
(gpointer*) &self->network);
}
}
}
static const char *ril_vendor_default_id_to_string(RilVendor *self, guint id)
{
return NULL;
}
static GRilIoRequest *ril_vendor_default_set_attach_apn_req(RilVendor *self,
const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
return NULL;
}
static GRilIoRequest *ril_vendor_default_data_call_req(RilVendor *self,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
return NULL;
}
static gboolean ril_vendor_default_data_call_parse(RilVendor *self,
struct ril_data_call *call, int version,
GRilIoParser *rilp)
{
return FALSE;
}
void ril_vendor_init_base(RilVendor *self, GRilIoChannel *io)
{
self->io = grilio_channel_ref(io);
}
static void ril_vendor_init(RilVendor *self)
{
}
static void ril_vendor_finalize(GObject* object)
{
RilVendor *self = RIL_VENDOR(object);
if (self->network) {
g_object_remove_weak_pointer(G_OBJECT(self->network),
(gpointer*) &self->network);
}
grilio_channel_unref(self->io);
G_OBJECT_CLASS(ril_vendor_parent_class)->finalize(object);
}
static void ril_vendor_class_init(RilVendorClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = ril_vendor_finalize;
klass->set_network = ril_vendor_default_set_network;
klass->request_to_string = ril_vendor_default_id_to_string;
klass->event_to_string = ril_vendor_default_id_to_string;
klass->set_attach_apn_req = ril_vendor_default_set_attach_apn_req;
klass->data_call_req = ril_vendor_default_data_call_req;
klass->data_call_parse = ril_vendor_default_data_call_parse;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,77 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2019 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_VENDOR_H
#define RIL_VENDOR_H
#include "ril_types.h"
struct ril_vendor_defaults {
gboolean empty_pin_query;
gboolean legacy_imei_query;
gboolean enable_cbs;
gboolean enable_stk;
gboolean query_available_band_mode;
};
struct ril_vendor_driver {
const char *name;
const void *driver_data;
void (*get_defaults)(struct ril_vendor_defaults *defaults);
struct ril_vendor *(*create_vendor)(const void *driver_data,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *cfg);
};
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name);
struct ril_vendor *ril_vendor_create
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
const char *path, const struct ril_slot_config *cfg);
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
struct ril_vendor_defaults *defaults);
struct ril_vendor *ril_vendor_ref(struct ril_vendor *vendor);
void ril_vendor_unref(struct ril_vendor *vendor);
const char *ril_vendor_request_to_string(struct ril_vendor *vendor,
guint request);
const char *ril_vendor_event_to_string(struct ril_vendor *vendor,
guint event);
void ril_vendor_set_network(struct ril_vendor *vendor, struct ril_network *nw);
GRilIoRequest *ril_vendor_set_attach_apn_req(struct ril_vendor *vendor,
const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
GRilIoRequest *ril_vendor_data_call_req(struct ril_vendor *vendor,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
gboolean ril_vendor_data_call_parse(struct ril_vendor *vendor,
struct ril_data_call *call, int version,
GRilIoParser *rilp);
/* Put vendor driver descriptors to the "__vendor" section */
#define RIL_VENDOR_DRIVER_DEFINE(name) const struct ril_vendor_driver name \
__attribute__((used, section("__vendor"))) =
#endif /* RIL_VENDOR_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,66 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 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_VENDOR_IMPL_H
#define RIL_VENDOR_IMPL_H
#include "ril_vendor.h"
#include <glib-object.h>
typedef struct ril_vendor {
GObject parent;
GRilIoChannel *io;
struct ril_network *network;
} RilVendor;
typedef struct ril_vendor_class {
GObjectClass parent;
void (*set_network)(RilVendor *vendor, struct ril_network *network);
const char *(*request_to_string)(RilVendor *vendor, guint request);
const char *(*event_to_string)(RilVendor *vendor, guint event);
GRilIoRequest *(*set_attach_apn_req)(RilVendor *vendor,
const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
GRilIoRequest *(*data_call_req)(RilVendor *vendor,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
gboolean (*data_call_parse)(RilVendor *vendor,
struct ril_data_call *call, int version,
GRilIoParser *rilp);
} RilVendorClass;
GType ril_vendor_get_type(void);
#define RIL_VENDOR_TYPE (ril_vendor_get_type())
#define RIL_VENDOR(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_VENDOR_TYPE, RilVendor)
#define RIL_VENDOR_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
RIL_VENDOR_TYPE, RilVendorClass)
#define RIL_VENDOR_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
RIL_VENDOR_TYPE, RilVendorClass)
void ril_vendor_init_base(RilVendor *vendor, GRilIoChannel *io);
#endif /* RIL_VENDOR_IMPL_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,620 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2019 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_vendor.h"
#include "ril_vendor_impl.h"
#include "ril_network.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
#include <grilio_channel.h>
#include <grilio_parser.h>
#include <grilio_request.h>
#include <grilio_queue.h>
#include <gutil_misc.h>
#include <ofono/watch.h>
#include <ofono/gprs.h>
#define SET_INITIAL_ATTACH_APN_TIMEOUT (20*1000)
enum ril_mtk_events {
MTK_EVENT_REGISTRATION_SUSPENDED,
MTK_EVENT_SET_ATTACH_APN,
MTK_EVENT_PS_NETWORK_STATE_CHANGED,
MTK_EVENT_INCOMING_CALL_INDICATION,
MTK_EVENT_COUNT
};
typedef struct ril_vendor_mtk {
RilVendor vendor;
const struct ril_mtk_flavor *flavor;
GRilIoQueue *q;
struct ofono_watch *watch;
guint set_initial_attach_apn_id;
gboolean initial_attach_apn_ok;
gulong ril_event_id[MTK_EVENT_COUNT];
guint slot;
} RilVendorMtk;
typedef struct ril_vendor_mtk_auto {
RilVendorMtk mtk;
gulong detect_id;
} RilVendorMtkAuto;
typedef RilVendorClass RilVendorMtkClass;
typedef RilVendorMtkClass RilVendorMtkAutoClass;
#define RIL_VENDOR_TYPE_MTK (ril_vendor_mtk_get_type())
#define RIL_VENDOR_TYPE_MTK_AUTO (ril_vendor_mtk_auto_get_type())
G_DEFINE_TYPE(RilVendorMtk, ril_vendor_mtk, RIL_VENDOR_TYPE)
G_DEFINE_TYPE(RilVendorMtkAuto, ril_vendor_mtk_auto, RIL_VENDOR_TYPE_MTK)
#define RIL_VENDOR_MTK(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_VENDOR_TYPE_MTK, RilVendorMtk)
#define RIL_VENDOR_MTK_AUTO(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_VENDOR_TYPE_MTK_AUTO, RilVendorMtkAuto)
/* driver_data point this this: */
struct ril_mtk_flavor {
const char *name;
const struct ril_mtk_msg *msg;
void (*build_attach_apn_req_fn)(GRilIoRequest *req, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
gboolean (*data_call_parse_fn)(struct ril_data_call *call,
int version, GRilIoParser *rilp);
};
/* MTK specific RIL messages (actual codes differ from model to model!) */
struct ril_mtk_msg {
guint request_resume_registration;
guint request_set_call_indication;
/* See ril_vendor_mtk_auto_detect_event */
#define unsol_msgs unsol_ps_network_state_changed
#define MTK_UNSOL_MSGS (4)
guint unsol_ps_network_state_changed;
guint unsol_registration_suspended;
guint unsol_incoming_call_indication;
guint unsol_set_attach_apn;
};
static const struct ril_mtk_msg msg_mtk1 = {
.request_resume_registration = 2050,
.request_set_call_indication = 2065,
.unsol_ps_network_state_changed = 3012,
.unsol_registration_suspended = 3021,
.unsol_incoming_call_indication = 3037,
.unsol_set_attach_apn = 3065
};
static const struct ril_mtk_msg msg_mtk2 = {
.request_resume_registration = 2065,
.request_set_call_indication = 2086,
.unsol_ps_network_state_changed = 3015,
.unsol_registration_suspended = 3024,
.unsol_incoming_call_indication = 3042,
.unsol_set_attach_apn = 3073
};
static const char *ril_vendor_mtk_request_to_string(RilVendor *vendor,
guint request)
{
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
const struct ril_mtk_msg *msg = self->flavor->msg;
if (request == msg->request_resume_registration) {
return "MTK_RESUME_REGISTRATION";
} else if (request == msg->request_set_call_indication) {
return "MTK_SET_CALL_INDICATION";
} else {
return NULL;
}
}
static const char *ril_vendor_mtk_unsol_msg_name(const struct ril_mtk_msg *msg,
guint event)
{
if (event == msg->unsol_ps_network_state_changed) {
return "MTK_PS_NETWORK_STATE_CHANGED";
} else if (event == msg->unsol_registration_suspended) {
return "MTK_REGISTRATION_SUSPENDED";
} else if (event == msg->unsol_set_attach_apn) {
return "MTK_SET_ATTACH_APN";
} else if (event == msg->unsol_incoming_call_indication) {
return "MTK_INCOMING_CALL_INDICATION";
} else {
return NULL;
}
}
static const char *ril_vendor_mtk_event_to_string(RilVendor *vendor,
guint event)
{
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
return ril_vendor_mtk_unsol_msg_name(self->flavor->msg, event);
}
static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
{
RilVendorMtk *self = RIL_VENDOR_MTK(user_data);
const struct ril_mtk_msg *msg = self->flavor->msg;
GRilIoParser rilp;
int session_id;
GASSERT(id == msg->unsol_registration_suspended);
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, NULL) &&
grilio_parser_get_int32(&rilp, &session_id)) {
GRilIoRequest *req = grilio_request_new();
DBG("slot=%u,session_id=%d", self->slot, session_id);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, session_id);
grilio_queue_send_request(self->q, req,
msg->request_resume_registration);
grilio_request_unref(req);
}
}
static void ril_vendor_mtk_build_attach_apn_req_1(GRilIoRequest *req,
const char *apn, const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
DBG("\"%s\" %s", apn, proto);
grilio_request_append_utf8(req, apn);
grilio_request_append_utf8(req, proto);
grilio_request_append_utf8(req, proto); /* roamingProtocol */
grilio_request_append_int32(req, auth);
grilio_request_append_utf8(req, username);
grilio_request_append_utf8(req, password);
grilio_request_append_utf8(req, ""); /* operatorNumeric */
grilio_request_append_int32(req, FALSE); /* canHandleIms */
grilio_request_append_int32(req, -1); /* dualApnPlmnList */
}
static void ril_vendor_mtk_build_attach_apn_req_2(GRilIoRequest *req,
const char *apn, const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
DBG("\"%s\" %s", apn, proto);
grilio_request_append_utf8(req, apn);
grilio_request_append_utf8(req, proto);
grilio_request_append_int32(req, auth);
grilio_request_append_utf8(req, username);
grilio_request_append_utf8(req, password);
grilio_request_append_utf8(req, ""); /* operatorNumeric */
grilio_request_append_int32(req, FALSE); /* canHandleIms */
grilio_request_append_int32(req, -1); /* dualApnPlmnList */
}
static void ril_vendor_mtk_initial_attach_apn_resp(GRilIoChannel *io,
int ril_status, const void *data, guint len, void *user_data)
{
RilVendorMtk *self = RIL_VENDOR_MTK(user_data);
GASSERT(self->set_initial_attach_apn_id);
self->set_initial_attach_apn_id = 0;
if (ril_status == RIL_E_SUCCESS) {
DBG("ok");
self->initial_attach_apn_ok = TRUE;
}
}
static void ril_vendor_mtk_initial_attach_apn_check(RilVendorMtk *self)
{
if (!self->set_initial_attach_apn_id && !self->initial_attach_apn_ok) {
struct ofono_watch *watch = self->watch;
const struct ofono_gprs_primary_context *pc =
ofono_gprs_context_settings_by_type(watch->gprs,
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
if (pc) {
const char *username;
const char *password;
enum ril_auth auth;
GRilIoRequest *req = grilio_request_new();
if (pc->username[0] || pc->password[0]) {
username = pc->username;
password = pc->password;
auth = ril_auth_method_from_ofono
(pc->auth_method);
} else {
username = "";
password = "";
auth = RIL_AUTH_NONE;
}
self->flavor->build_attach_apn_req_fn(req,
pc->apn, username, password, auth,
ril_protocol_from_ofono(pc->proto));
grilio_request_set_timeout(req,
SET_INITIAL_ATTACH_APN_TIMEOUT);
self->set_initial_attach_apn_id =
grilio_queue_send_request_full(self->q, req,
RIL_REQUEST_SET_INITIAL_ATTACH_APN,
ril_vendor_mtk_initial_attach_apn_resp,
NULL, self);
grilio_request_unref(req);
}
}
}
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
{
ril_vendor_mtk_initial_attach_apn_check(RIL_VENDOR_MTK(user_data));
}
static void ril_vendor_mtk_ps_network_state_changed(GRilIoChannel *io,
guint id, const void *data, guint len, void *user_data)
{
ril_network_query_registration_state(RIL_VENDOR(user_data)->network);
}
static void ril_vendor_mtk_incoming_call_indication(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
{
RilVendorMtk *self = RIL_VENDOR_MTK(user_data);
const struct ril_mtk_msg *msg = self->flavor->msg;
GRilIoRequest* req = NULL;
GASSERT(id == msg->unsol_incoming_call_indication);
if (msg->request_set_call_indication) {
int nparams, cid, seq;
gchar *call_id = NULL, *seq_no = NULL;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &nparams) && nparams >= 5 &&
(call_id = grilio_parser_get_utf8(&rilp)) != NULL &&
grilio_parser_skip_string(&rilp) /* number */ &&
grilio_parser_skip_string(&rilp) /* type */ &&
grilio_parser_skip_string(&rilp) /* call_mode */ &&
(seq_no = grilio_parser_get_utf8(&rilp)) != NULL &&
gutil_parse_int(call_id, 10, &cid) &&
gutil_parse_int(seq_no, 10, &seq)) {
DBG("slot=%u,cid=%d,seq=%d", self->slot, cid, seq);
req = grilio_request_new();
grilio_request_append_int32(req, 3); /* Param count */
/* mode - IMS_ALLOW_INCOMING_CALL_INDICATION: */
grilio_request_append_int32(req, 0);
grilio_request_append_int32(req, cid);
grilio_request_append_int32(req, seq);
} else {
DBG("failed to parse INCOMING_CALL_INDICATION");
}
g_free(call_id);
g_free(seq_no);
}
if (req) {
grilio_queue_send_request(self->q, req,
msg->request_set_call_indication);
grilio_request_unref(req);
} else {
/* Let ril_voicecall.c know that something happened */
grilio_channel_inject_unsol_event(io,
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
}
}
static GRilIoRequest *ril_vendor_mtk_data_call_req(RilVendor *vendor,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
GRilIoRequest *req = grilio_request_new();
grilio_request_append_int32(req, 8); /* Number of parameters */
grilio_request_append_format(req, "%d", tech);
grilio_request_append_utf8(req, profile);
grilio_request_append_utf8(req, apn);
grilio_request_append_utf8(req, username);
grilio_request_append_utf8(req, password);
grilio_request_append_format(req, "%d", auth);
grilio_request_append_utf8(req, proto);
grilio_request_append_format(req, "%d", self->slot+1);
return req;
}
static GRilIoRequest *ril_vendor_mtk_set_attach_apn_req(RilVendor *vendor,
const char *profile, const char *apn,
const char *user, const char *pass,
enum ril_auth auth, const char *prot)
{
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
GRilIoRequest *req = grilio_request_new();
self->flavor->build_attach_apn_req_fn(req, apn, user, pass, auth, prot);
return req;
}
static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_data_call *call,
int version, GRilIoParser *rilp)
{
if (version < 11) {
int prot;
char *prot_str;
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
guint32 active = RIL_DATA_CALL_INACTIVE;
/* RIL_Data_Call_Response_v6 with MTK specific additions */
grilio_parser_get_uint32(rilp, &status);
grilio_parser_get_int32(rilp, &call->retry_time);
grilio_parser_get_int32(rilp, &call->cid);
grilio_parser_get_uint32(rilp, &active);
grilio_parser_get_int32(rilp, &call->mtu); /* MTK specific */
prot_str = grilio_parser_get_utf8(rilp);
prot = ril_protocol_to_ofono(prot_str);
g_free(prot_str);
if (prot >= 0) {
call->ifname = grilio_parser_get_utf8(rilp);
call->addresses = grilio_parser_split_utf8(rilp, " ");
call->dnses = grilio_parser_split_utf8(rilp, " ");
call->gateways = grilio_parser_split_utf8(rilp, " ");
if (call->ifname && call->addresses) {
call->prot = prot;
call->status = status;
call->active = active;
return TRUE;
}
}
}
return FALSE;
}
static gboolean ril_vendor_mtk_data_call_parse(RilVendor *vendor,
struct ril_data_call *call, int version,
GRilIoParser *rilp)
{
const struct ril_mtk_flavor *flavor = RIL_VENDOR_MTK(vendor)->flavor;
return flavor->data_call_parse_fn ?
flavor->data_call_parse_fn(call, version, rilp) :
RIL_VENDOR_CLASS(ril_vendor_mtk_parent_class)->
data_call_parse(vendor, call, version, rilp);
}
static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
{
/*
* With most Qualcomm RIL implementations, querying available band
* modes causes some magic Android properties to appear. Otherwise
* this request is pretty harmless and useless.
*
* Most MediaTek RIL implementations don't support this request and
* don't even bother to reply which slows things down because we wait
* for this request to complete at startup.
*/
defaults->query_available_band_mode = FALSE;
defaults->empty_pin_query = FALSE;
defaults->legacy_imei_query = TRUE;
}
static void ril_vendor_mtk_base_init(RilVendorMtk *self, GRilIoChannel *io,
const char *path, const struct ril_slot_config *config)
{
ril_vendor_init_base(&self->vendor, io);
self->q = grilio_queue_new(io);
self->watch = ofono_watch_new(path);
self->slot = config->slot;
}
static void ril_vendor_mtk_set_flavor(RilVendorMtk *self,
const struct ril_mtk_flavor *flavor)
{
GRilIoChannel *io = self->vendor.io;
const struct ril_mtk_msg *msg = flavor->msg;
grilio_channel_remove_all_handlers(io, self->ril_event_id);
self->flavor = flavor;
self->ril_event_id[MTK_EVENT_REGISTRATION_SUSPENDED] =
grilio_channel_add_unsol_event_handler(io,
ril_vendor_mtk_registration_suspended,
msg->unsol_registration_suspended, self);
if (msg->unsol_set_attach_apn) {
self->ril_event_id[MTK_EVENT_SET_ATTACH_APN] =
grilio_channel_add_unsol_event_handler(io,
ril_vendor_mtk_set_attach_apn,
msg->unsol_set_attach_apn, self);
}
if (msg->unsol_ps_network_state_changed) {
self->ril_event_id[MTK_EVENT_PS_NETWORK_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(io,
ril_vendor_mtk_ps_network_state_changed,
msg->unsol_ps_network_state_changed, self);
}
if (msg->unsol_incoming_call_indication) {
self->ril_event_id[MTK_EVENT_INCOMING_CALL_INDICATION] =
grilio_channel_add_unsol_event_handler(io,
ril_vendor_mtk_incoming_call_indication,
msg->unsol_incoming_call_indication, self);
}
}
static RilVendor *ril_vendor_mtk_create_from_data(const void *driver_data,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *config)
{
const struct ril_mtk_flavor *flavor = driver_data;
RilVendorMtk *mtk = g_object_new(RIL_VENDOR_TYPE_MTK, NULL);
ril_vendor_mtk_base_init(mtk, io, path, config);
ril_vendor_mtk_set_flavor(mtk, flavor);
DBG("%s slot %u", flavor->name, mtk->slot);
return &mtk->vendor;
}
static void ril_vendor_mtk_init(RilVendorMtk *self)
{
}
static void ril_vendor_mtk_finalize(GObject* object)
{
RilVendorMtk *self = RIL_VENDOR_MTK(object);
RilVendor *vendor = &self->vendor;
DBG("slot %u", self->slot);
grilio_queue_cancel_all(self->q, FALSE);
grilio_queue_unref(self->q);
ofono_watch_unref(self->watch);
grilio_channel_remove_all_handlers(vendor->io, self->ril_event_id);
G_OBJECT_CLASS(ril_vendor_mtk_parent_class)->finalize(object);
}
static void ril_vendor_mtk_class_init(RilVendorMtkClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = ril_vendor_mtk_finalize;
klass->request_to_string = ril_vendor_mtk_request_to_string;
klass->event_to_string = ril_vendor_mtk_event_to_string;
klass->set_attach_apn_req = ril_vendor_mtk_set_attach_apn_req;
klass->data_call_req = ril_vendor_mtk_data_call_req;
klass->data_call_parse = ril_vendor_mtk_data_call_parse;
}
static const struct ril_mtk_flavor ril_mtk_flavor1 = {
.name = "mtk1",
.msg = &msg_mtk1,
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_1,
.data_call_parse_fn = NULL
};
static const struct ril_mtk_flavor ril_mtk_flavor2 = {
.name = "mtk2",
.msg = &msg_mtk2,
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_2,
.data_call_parse_fn = &ril_vendor_mtk_data_call_parse_v6
};
#define DEFAULT_MTK_TYPE (&ril_mtk_flavor1)
static const struct ril_mtk_flavor *mtk_flavors [] = {
&ril_mtk_flavor1,
&ril_mtk_flavor2
};
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk1) {
.name = "mtk1",
.driver_data = &ril_mtk_flavor1,
.get_defaults = ril_vendor_mtk_get_defaults,
.create_vendor = ril_vendor_mtk_create_from_data
};
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk2) {
.name = "mtk2",
.driver_data = &ril_mtk_flavor2,
.get_defaults = ril_vendor_mtk_get_defaults,
.create_vendor = ril_vendor_mtk_create_from_data
};
/* Auto-selection */
static void ril_vendor_mtk_auto_detect_event(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
{
RilVendorMtkAuto *self = RIL_VENDOR_MTK_AUTO(user_data);
guint i;
for (i = 0; i < G_N_ELEMENTS(mtk_flavors); i++) {
const struct ril_mtk_flavor *flavor = mtk_flavors[i];
const struct ril_mtk_msg *msg = flavor->msg;
const guint *ids = &msg->unsol_msgs;
guint j;
for (j = 0; j < MTK_UNSOL_MSGS; j++) {
if (ids[j] == id) {
DBG("event %u is %s %s", id, flavor->name,
ril_vendor_mtk_unsol_msg_name(msg,id));
ril_vendor_mtk_set_flavor(&self->mtk, flavor);
/* We are done */
grilio_channel_remove_handler(io,
self->detect_id);
self->detect_id = 0;
/* And repeat the event to invoke the handler */
grilio_channel_inject_unsol_event(io, id,
data, len);
return;
}
}
}
}
static void ril_vendor_mtk_auto_init(RilVendorMtkAuto *self)
{
}
static void ril_vendor_mtk_auto_finalize(GObject* object)
{
RilVendorMtkAuto *self = RIL_VENDOR_MTK_AUTO(object);
DBG("slot %u", self->mtk.slot);
grilio_channel_remove_handler(self->mtk.vendor.io, self->detect_id);
G_OBJECT_CLASS(ril_vendor_mtk_auto_parent_class)->finalize(object);
}
static void ril_vendor_mtk_auto_class_init(RilVendorMtkAutoClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = ril_vendor_mtk_auto_finalize;
}
static RilVendor *ril_vendor_mtk_auto_create_vendor(const void *driver_data,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *config)
{
RilVendorMtkAuto *self = g_object_new(RIL_VENDOR_TYPE_MTK_AUTO, NULL);
RilVendorMtk *mtk = &self->mtk;
ril_vendor_mtk_base_init(mtk, io, path, config);
ril_vendor_mtk_set_flavor(mtk, DEFAULT_MTK_TYPE);
DBG("%s slot %u", mtk->flavor->name, mtk->slot);
/*
* Subscribe for (all) unsolicited events. Keep on listening until
* we receive an MTK specific event that tells us which particular
* kind of MTK adaptation we are using.
*/
self->detect_id = grilio_channel_add_unsol_event_handler(io,
ril_vendor_mtk_auto_detect_event, 0, self);
return &mtk->vendor;
}
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk) {
.name = "mtk",
.get_defaults = ril_vendor_mtk_get_defaults,
.create_vendor = ril_vendor_mtk_auto_create_vendor
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

Some files were not shown because too many files have changed in this diff Show More