Compare commits

...

86 Commits

Author SHA1 Message Date
Slava Monich
adca340f4b [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 23:39:37 +03:00
Slava Monich
709bb7e596 [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-27 11:18:46 +03:00
jpoutiai
aef9bbd3e0 Merge branch 'jb38053' into 'master'
[plugins] support bt call audio control. Fixes JB#38053

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

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

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

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

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

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

Added ofono_voicecall_find_call API instead

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

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

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

It's the latest stable release.

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

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

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

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

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

It was totally broken. 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Possible values are 6, 9, 11 and auto.

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

1
ofono/.gitignore vendored
View File

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

View File

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

View File

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

View File

@@ -197,6 +197,7 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
drivers/rilmodem/call-barring.c \
drivers/rilmodem/netmon.c \
drivers/rilmodem/stk.c \
drivers/rilmodem/cbs.c \
drivers/infineonmodem/infineon_constants.h
endif
endif
@@ -574,6 +575,11 @@ builtin_sources += plugins/bluez5.c plugins/bluez5.h
builtin_modules += hfp_ag_bluez5
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
if SAILFISHFOS
builtin_modules += sfos_bt
builtin_sources += plugins/sfos_bt.c
endif
endif
if UPOWER
@@ -758,6 +764,7 @@ test_scripts = test/backtrace \
test/receive-sms \
test/remove-contexts \
test/send-sms \
test/cancel-sms \
test/set-mic-volume \
test/set-speaker-volume \
test/test-stk-menu \
@@ -828,7 +835,9 @@ test_scripts = test/backtrace \
test/set-sms-smsc \
test/set-sms-bearer \
test/get-serving-cell-info \
test/list-allowed-access-points
test/list-allowed-access-points \
test/enable-throttling \
test/disable-throttling
if TEST
testdir = $(pkglibdir)/test
@@ -854,7 +863,8 @@ if JOLLA_RILMODEM
unit_tests += unit/test-rilmodem-cs \
unit/test-rilmodem-cs \
unit/test-rilmodem-sms \
unit/test-rilmodem-cb
unit/test-rilmodem-cb \
unit/test-rilmodem-gprs
endif
endif
@@ -916,14 +926,14 @@ unit_test_provision_SOURCES = unit/test-provision.c \
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_provision_OBJECTS)
if RILMODEM
if JOLLA_RILMODEM
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
gatchat/ringbuffer.h gatchat/ringbuffer.c \
unit/rilmodem-test-server.h \
unit/rilmodem-test-server.c \
src/simutil.c
unit/rilmodem-test-engine.h \
unit/rilmodem-test-engine.c \
src/simutil.c \
drivers/rilmodem/rilutil.c
unit_test_rilmodem_cs_SOURCES = $(test_rilmodem_sources) \
unit/test-rilmodem-cs.c \
@@ -946,8 +956,12 @@ unit_test_rilmodem_cb_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
unit_objects += $(unit_test_rilmodem_cb_OBJECTS)
endif
endif
unit_test_rilmodem_gprs_SOURCES = $(test_rilmodem_sources) \
unit/test-rilmodem-gprs.c \
drivers/rilmodem/gprs.c
unit_test_rilmodem_gprs_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
unit_objects += $(unit_test_rilmodem_gprs_OBJECTS)
TESTS = $(unit_tests)

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(ofono, 1.18)
AC_INIT(ofono, 1.19)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)
@@ -183,6 +183,13 @@ if (test "${enable_jolla_rilmodem}" = "yes"); then
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS $LIBMCE_LIBS"
fi
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
[don't allow to add or remove connection context over D-Bus]), [
if (test "${enableval}" = "no"); then
CFLAGS="$CFLAGS -DDISABLE_ADD_REMOVE_CONTEXT"
fi
])
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
[disable Qualcomm QMI modem support]),
[enable_qmimodem=${enableval}])
@@ -206,6 +213,10 @@ 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(nettime, AC_HELP_STRING([--disable-nettime],
[disable Nettime plugin]),
[enable_nettime=${enableval}])

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,9 @@
#include "ril_config.h"
#include <gutil_intarray.h>
#include <gutil_ints.h>
/* Utilities for parsing ril_subscription.conf */
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
@@ -106,6 +109,51 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
}
}
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key)
{
char* value = ril_config_get_string(file, group, key);
if (value) {
char **values = g_strsplit(value, ",", -1);
char **ptr = values;
GUtilIntArray* array = gutil_int_array_new();
while (*ptr) {
const char *str = *ptr++;
char *end = NULL;
long ival = strtol(str, &end, 0);
if (str[0] && !end[0]) {
gutil_int_array_append(array, ival);
}
}
g_free(value);
g_strfreev(values);
return gutil_int_array_free_to_ints(array);
}
return NULL;
}
char *ril_config_ints_to_string(GUtilInts *ints, char separator)
{
if (ints) {
guint i, n;
const int *data = gutil_ints_get_data(ints, &n);
GString* buf = g_string_new(NULL);
for (i=0; i<n; i++) {
if (buf->len > 0) {
g_string_append_c(buf, separator);
}
g_string_append_printf(buf, "%d", data[i]);
}
return g_string_free(buf, FALSE);
}
return NULL;
}
/*
* Local Variables:
* mode: C

View File

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

View File

@@ -1,11 +1,10 @@
/*
*
* RIL constants adopted from AOSP's header:
*
* /hardware/ril/reference_ril/ril.h
*
* Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2013-2016 Jolla Ltd.
* Copyright (C) 2013-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -118,45 +117,68 @@ enum ril_radio_tech {
};
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
#define CALL_FAIL_UNOBTAINABLE_NUMBER 1
#define CALL_FAIL_NORMAL 16
#define CALL_FAIL_BUSY 17
#define CALL_FAIL_CONGESTION 34
#define CALL_FAIL_ACM_LIMIT_EXCEEDED 68
#define CALL_FAIL_CALL_BARRED 240
#define CALL_FAIL_FDN_BLOCKED 241
#define CALL_FAIL_IMSI_UNKNOWN_IN_VLR 242
#define CALL_FAIL_IMEI_NOT_ACCEPTED 243
#define CALL_FAIL_DIAL_MODIFIED_TO_USSD 244
#define CALL_FAIL_DIAL_MODIFIED_TO_SS 245
#define CALL_FAIL_DIAL_MODIFIED_TO_DIAL 246
#define CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE 1000
#define CALL_FAIL_CDMA_DROP 1001
#define CALL_FAIL_CDMA_INTERCEPT 1002
#define CALL_FAIL_CDMA_REORDER 1003
#define CALL_FAIL_CDMA_SO_REJECT 1004
#define CALL_FAIL_CDMA_RETRY_ORDER 1005
#define CALL_FAIL_CDMA_ACCESS_FAILURE 1006
#define CALL_FAIL_CDMA_PREEMPTED 1007
#define CALL_FAIL_CDMA_NOT_EMERGENCY 1008
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
enum ril_call_fail_cause {
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
CALL_FAIL_NORMAL = 16,
CALL_FAIL_BUSY = 17,
CALL_FAIL_NO_USER_RESPONDING = 18,
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
CALL_FAIL_CALL_REJECTED = 21,
CALL_FAIL_NUMBER_CHANGED = 22,
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
CALL_FAIL_FACILITY_REJECTED = 29,
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
CALL_FAIL_CONGESTION = 34,
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
CALL_FAIL_TEMPORARY_FAILURE = 41,
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
CALL_FAIL_QOS_UNAVAILABLE = 49,
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
CALL_FAIL_CALL_BARRED = 240,
CALL_FAIL_FDN_BLOCKED = 241,
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
/* Not defined in ril.h but valid 3GPP specific cause values
* for call control. See 3GPP TS 24.008 Annex H. */
#define CALL_FAIL_NO_ROUTE_TO_DESTINATION 3
#define CALL_FAIL_CHANNEL_UNACCEPTABLE 6
#define CALL_FAIL_OPERATOR_DETERMINED_BARRING 8
#define CALL_FAIL_NO_USER_RESPONDING 18
#define CALL_FAIL_USER_ALERTING_NO_ANSWER 19
#define CALL_FAIL_CALL_REJECTED 21
#define CALL_FAIL_NUMBER_CHANGED 22
#define CALL_FAIL_ANONYMOUS_CALL_REJECTION 24
#define CALL_FAIL_PRE_EMPTION 25
#define CALL_FAIL_DESTINATION_OUT_OF_ORDER 27
#define CALL_FAIL_INCOMPLETE_NUMBER 28
#define CALL_FAIL_FACILITY_REJECTED 29
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
CALL_FAIL_PRE_EMPTION = 25
};
enum ril_data_call_fail_cause {
PDP_FAIL_NONE = 0,

View File

@@ -36,6 +36,7 @@
#define PROTO_IPV4V6_STR "IPV4V6"
enum ril_data_priv_flags {
RIL_DATA_FLAG_NONE = 0x00,
RIL_DATA_FLAG_ALLOWED = 0x01,
RIL_DATA_FLAG_MAX_SPEED = 0x02,
RIL_DATA_FLAG_ON = 0x04
@@ -99,7 +100,8 @@ struct ril_data_priv {
struct ril_data_request *req_queue;
struct ril_data_request *pending_req;
enum ril_data_allow_data_opt allow_data;
struct ril_data_options options;
guint slot;
char *log_prefix;
guint query_id;
gulong io_event_id;
@@ -159,7 +161,8 @@ struct ril_data_request_setup {
char *password;
enum ofono_gprs_proto proto;
enum ofono_gprs_auth_method auth_method;
int retry_count;
guint retry_count;
guint retry_delay_id;
};
struct ril_data_request_deact {
@@ -172,7 +175,6 @@ struct ril_data_request_2g {
gulong handler_id;
};
static gboolean ril_data_manager_handover(struct ril_data_manager *dm);
static void ril_data_manager_check_data(struct ril_data_manager *dm);
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
@@ -272,7 +274,8 @@ static int ril_data_protocol_to_ofono(gchar *str)
return -1;
}
static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp)
static struct ril_data_call *ril_data_call_parse(int version,
GRilIoParser *rilp)
{
int prot;
char *prot_str;
@@ -280,6 +283,7 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
guint32 active = RIL_DATA_CALL_INACTIVE;
struct ril_data_call *call = g_new0(struct ril_data_call, 1);
/* RIL_Data_Call_Response_v6 (see ril.h) */
grilio_parser_get_uint32(rilp, &status);
grilio_parser_get_int32(rilp, &call->retry_time);
grilio_parser_get_int32(rilp, &call->cid);
@@ -299,15 +303,13 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
call->status = status;
call->active = active;
/* RIL_Data_Call_Response_v9 */
if (version >= 9) {
/* PCSCF */
grilio_parser_skip_string(rilp);
/*
* All known rils that report version 10 are using
* RIL_Data_Call_Response_v11 (FairPhone 2, Nexus 4)
*/
if (version >= 10) {
/* RIL_Data_Call_Response_v11 */
if (version >= 11) {
/* MTU */
grilio_parser_get_int32(rilp, &call->mtu);
}
@@ -317,7 +319,8 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
return call;
}
struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
guint len, enum ril_data_call_format format)
{
unsigned int version, n, i;
GRilIoParser rilp;
@@ -328,8 +331,13 @@ struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
struct ril_data_call_list *list =
g_new0(struct ril_data_call_list, 1);
DBG("version=%u,num=%u", version, n);
list->version = version;
if (format == RIL_DATA_CALL_FORMAT_AUTO || format == version) {
DBG("version=%u,num=%u", version, n);
list->version = version;
} else {
DBG("version=%u(%d),num=%u", version, format, n);
list->version = format;
}
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
struct ril_data_call *call =
@@ -499,7 +507,8 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
priv->query_id = 0;
}
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->options.data_call_format));
}
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
@@ -511,7 +520,8 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
GASSERT(priv->query_id);
priv->query_id = 0;
if (ril_status == RIL_E_SUCCESS) {
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->options.data_call_format));
}
}
@@ -586,11 +596,11 @@ static gboolean ril_data_request_do_cancel(struct ril_data_request *req)
struct ril_data_priv *priv = req->data->priv;
DBG_(req->data, "canceling %s request %p", req->name, req);
if (req->cancel) {
req->cancel(req);
}
if (priv->pending_req == req) {
/* Request has been submitted already */
if (req->cancel) {
req->cancel(req);
}
priv->pending_req = NULL;
} else if (priv->req_queue == req) {
/* It's the first one in the queue */
@@ -673,15 +683,33 @@ static void ril_data_request_queue(struct ril_data_request *req)
static void ril_data_call_setup_cancel(struct ril_data_request *req)
{
if (req->pending_id) {
grilio_queue_cancel_request(req->data->priv->q,
req->pending_id, FALSE);
req->pending_id = 0;
if (req->cb.setup) {
req->cb.setup(req->data, GRILIO_STATUS_CANCELLED,
NULL, req->arg);
}
struct ril_data_request_setup *setup =
G_CAST(req, struct ril_data_request_setup, req);
ril_data_request_cancel_io(req);
if (setup->retry_delay_id) {
g_source_remove(setup->retry_delay_id);
setup->retry_delay_id = 0;
}
if (req->cb.setup) {
ril_data_call_setup_cb_t cb = req->cb.setup;
req->cb.setup = NULL;
cb(req->data, GRILIO_STATUS_CANCELLED, NULL, req->arg);
}
}
static gboolean ril_data_call_setup_retry(void *user_data)
{
struct ril_data_request_setup *setup = user_data;
struct ril_data_request *req = &setup->req;
GASSERT(setup->retry_delay_id);
setup->retry_delay_id = 0;
setup->retry_count++;
DBG("silent retry %u out of %u", setup->retry_count,
req->data->priv->options.data_call_retry_limit);
req->submit(req);
return G_SOURCE_REMOVE;
}
static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
@@ -690,11 +718,13 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
struct ril_data_request_setup *setup = user_data;
struct ril_data_request *req = &setup->req;
struct ril_data *self = req->data;
struct ril_data_priv *priv = self->priv;
struct ril_data_call_list *list = NULL;
struct ril_data_call *call = NULL;
if (ril_status == RIL_E_SUCCESS) {
list = ril_data_call_list_parse(data, len);
list = ril_data_call_list_parse(data, len,
priv->options.data_call_format);
}
if (list) {
@@ -707,15 +737,25 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
}
if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED &&
!setup->retry_count) {
setup->retry_count < priv->options.data_call_retry_limit) {
/*
* Retry silently according to comment in ril.h
* (no more than once though)
* According to the comment from ril.h we should silently
* retry. First time we retry immediately and if that doedsn't
* work, then after certain delay.
*/
DBG("retrying silently");
setup->retry_count++;
req->pending_id = 0;
req->submit(req);
GASSERT(!setup->retry_delay_id);
if (!setup->retry_count) {
setup->retry_count++;
DBG("silent retry %u out of %u", setup->retry_count,
priv->options.data_call_retry_limit);
req->submit(req);
} else {
guint ms = priv->options.data_call_retry_delay_ms;
DBG("silent retry scheduled in %u ms", ms);
setup->retry_delay_id = g_timeout_add(ms,
ril_data_call_setup_retry, setup);
}
ril_data_call_list_free(list);
return;
}
@@ -844,14 +884,11 @@ static struct ril_data_request *ril_data_call_setup_new(struct ril_data *data,
static void ril_data_call_deact_cancel(struct ril_data_request *req)
{
if (req->pending_id) {
grilio_queue_cancel_request(req->data->priv->q,
req->pending_id, FALSE);
req->pending_id = 0;
if (req->cb.setup) {
req->cb.deact(req->data, GRILIO_STATUS_CANCELLED,
req->arg);
}
ril_data_request_cancel_io(req);
if (req->cb.deact) {
ril_data_call_deactivate_cb_t cb = req->cb.deact;
req->cb.deact = NULL;
cb(req->data, GRILIO_STATUS_CANCELLED, req->arg);
}
}
@@ -1023,9 +1060,20 @@ static void ril_data_settings_changed(struct ril_sim_settings *settings,
ril_data_manager_check_network_mode(RIL_DATA(user_data)->priv->dm);
}
static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
{
const struct ril_data *d1 = a;
const struct ril_data *d2 = b;
const struct ril_data_priv *p1 = d1->priv;
const struct ril_data_priv *p2 = d2->priv;
return p1->slot < p2->slot ? (-1) : p1->slot > p2->slot ? 1 : 0;
}
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, enum ril_data_allow_data_opt opt)
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config)
{
GASSERT(dm);
if (G_LIKELY(dm)) {
@@ -1034,17 +1082,17 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_sim_settings *settings = network->settings;
GRilIoRequest *req = grilio_request_new();
switch (opt) {
priv->options = *options;
switch (priv->options.allow_data) {
case RIL_ALLOW_DATA_ON:
case RIL_ALLOW_DATA_OFF:
priv->allow_data = opt;
break;
default:
/*
* When RIL_REQUEST_ALLOW_DATA first appeared in ril.h
* RIL_VERSION was 10
*/
priv->allow_data = (io->ril_version > 10) ?
priv->options.allow_data = (io->ril_version > 10) ?
RIL_ALLOW_DATA_ON : RIL_ALLOW_DATA_OFF;
break;
}
@@ -1052,6 +1100,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
priv->log_prefix = (name && name[0]) ?
g_strconcat(name, " ", NULL) : g_strdup("");
priv->slot = config->slot;
priv->q = grilio_queue_new(io);
priv->io = grilio_channel_ref(io);
priv->dm = ril_data_manager_ref(dm);
@@ -1076,7 +1125,10 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
NULL, self);
grilio_request_unref(req);
dm->data_list = g_slist_append(dm->data_list, self);
/* Order data contexts according to slot numbers */
dm->data_list = g_slist_insert_sorted(dm->data_list, self,
ril_data_compare_cb);
ril_data_manager_check_network_mode(dm);
return self;
}
return NULL;
@@ -1379,6 +1431,16 @@ void ril_data_manager_unref(struct ril_data_manager *self)
}
}
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
{
/*
* The 3G/LTE handover thing only makes sense if we are managing
* more than one SIM slot. Otherwise leave things where they are.
*/
return (self->data_list && self->data_list->next &&
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
}
static gboolean ril_data_manager_requests_pending(struct ril_data_manager *self)
{
GSList *l;
@@ -1398,53 +1460,54 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
GSList *l;
if (ril_data_manager_handover(self)) {
gboolean need_fast_access = FALSE;
struct ril_network *lte_network = NULL;
int non_gsm_count = 0;
/*
* Count number of SIMs for which GSM is selected
* Count number of SIMs for which non-GSM mode is selected
*/
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
struct ril_data_priv *priv = data->priv;
struct ril_sim_settings *sim = priv->network->settings;
struct ril_network *network = priv->network;
struct ril_sim_settings *sim = network->settings;
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM &&
sim->imsi) {
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) {
non_gsm_count++;
if (priv->flags & RIL_DATA_FLAG_MAX_SPEED) {
need_fast_access = TRUE;
if ((priv->flags & RIL_DATA_FLAG_MAX_SPEED) &&
!lte_network) {
lte_network = network;
}
}
}
/*
* If the SIM selected for internet access has non-GSM mode
* enabled and non-GSM mode is enabled for more than one SIM,
* then we need to limit other SIMs to GSM. Otherwise, turn
* all limits off.
* If there's no SIM selected for internet access
* then choose the first slot for LTE.
*/
if (need_fast_access && non_gsm_count > 1) {
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
struct ril_data_priv *priv = data->priv;
ril_network_set_max_pref_mode(priv->network,
(priv->flags & RIL_DATA_FLAG_MAX_SPEED) ?
OFONO_RADIO_ACCESS_MODE_ANY :
OFONO_RADIO_ACCESS_MODE_GSM,
FALSE);
}
return;
if (!lte_network) {
struct ril_data *data = self->data_list->data;
lte_network = data->priv->network;
}
}
/* Otherwise there's no reason to limit anything */
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
ril_network_set_max_pref_mode(data->priv->network,
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
struct ril_network *network = data->priv->network;
ril_network_set_max_pref_mode(network,
(network == lte_network) ?
OFONO_RADIO_ACCESS_MODE_ANY :
OFONO_RADIO_ACCESS_MODE_GSM,
FALSE);
}
} else {
/* Otherwise there's no reason to limit anything */
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
ril_network_set_max_pref_mode(data->priv->network,
OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
}
}
}
@@ -1462,16 +1525,6 @@ static struct ril_data *ril_data_manager_allowed(struct ril_data_manager *self)
return NULL;
}
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
{
/*
* The 3G/LTE handover thing only makes sense if we are managing
* more than one SIM slot. Otherwise leave things where they are.
*/
return (self->data_list && self->data_list->next &&
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
}
static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
struct ril_data *data)
{
@@ -1486,7 +1539,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
}
if (priv->allow_data == RIL_ALLOW_DATA_ON) {
if (priv->options.allow_data == RIL_ALLOW_DATA_ON) {
ril_data_request_queue(ril_data_allow_new(data));
} else {
priv->flags |= RIL_DATA_FLAG_ON;

View File

@@ -60,6 +60,20 @@ enum ril_data_allow_data_opt {
RIL_ALLOW_DATA_OFF
};
enum ril_data_call_format {
RIL_DATA_CALL_FORMAT_AUTO,
RIL_DATA_CALL_FORMAT_6 = 6,
RIL_DATA_CALL_FORMAT_9 = 9,
RIL_DATA_CALL_FORMAT_11 = 11
};
struct ril_data_options {
enum ril_data_allow_data_opt allow_data;
enum ril_data_call_format data_call_format;
unsigned int data_call_retry_limit;
unsigned int data_call_retry_delay_ms;
};
enum ril_data_role {
RIL_DATA_ROLE_NONE, /* Data not allowed */
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
@@ -79,8 +93,9 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
int ril_status, void *arg);
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, enum ril_data_allow_data_opt opt);
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config);
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
gboolean ril_data_allowed(struct ril_data *data);

View File

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

View File

@@ -51,11 +51,12 @@ struct ril_modem_online_request {
struct ril_modem_data {
struct ril_modem modem;
GRilIoQueue *q;
struct ofono_radio_settings *radio_settings;
char *log_prefix;
char *imei;
char *ecclist_file;
gboolean pre_sim_done;
gboolean allow_data;
gulong sim_imsi_event_id;
guint online_check_id;
enum ril_modem_power_state power_state;
@@ -73,6 +74,8 @@ struct ril_modem_data {
#define RADIO_POWER_TAG(md) (md)
#define DBG_(md,fmt,args...) DBG("%s" fmt, (md)->log_prefix, ##args)
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
{
struct ril_modem_data *md = ofono_modem_get_data(o);
@@ -115,6 +118,12 @@ struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
}
static inline struct ofono_radio_settings *ril_modem_radio_settings(
struct ril_modem *modem)
{
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
}
void ril_modem_delete(struct ril_modem *md)
{
if (md && md->ofono) {
@@ -223,17 +232,23 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
{
if (md->modem.radio->state == RADIO_STATE_ON) {
if (!md->radio_settings) {
DBG("Initializing radio settings interface");
md->radio_settings =
ofono_radio_settings_create(md->modem.ofono, 0,
RILMODEM_DRIVER, md);
struct ril_modem *m = &md->modem;
if (m->radio->state == RADIO_STATE_ON && m->sim_settings->imsi) {
/* radio-settings.c assumes that IMSI is available */
if (!ril_modem_radio_settings(m)) {
DBG_(md, "initializing radio settings interface");
ofono_radio_settings_create(m->ofono, 0,
RILMODEM_DRIVER, md);
}
} else {
/* ofono core may remove radio settings atom internally */
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
if (rs) {
DBG_(md, "removing radio settings interface");
ofono_radio_settings_remove(rs);
} else {
DBG_(md, "radio settings interface is already gone");
}
} else if (md->radio_settings) {
DBG("Removing radio settings interface");
ofono_radio_settings_remove(md->radio_settings);
md->radio_settings = NULL;
}
}
@@ -246,6 +261,14 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
ril_modem_update_online_state(md);
}
static void ril_modem_imsi_cb(struct ril_sim_settings *settings, void *data)
{
struct ril_modem_data *md = data;
GASSERT(md->modem.sim_settings == settings);
ril_modem_update_radio_settings(md);
}
static void ril_modem_pre_sim(struct ofono_modem *modem)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
@@ -255,7 +278,6 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
ril_modem_update_radio_settings(md);
if (!md->radio_state_event_id) {
md->radio_state_event_id =
ril_radio_add_state_changed_handler(md->modem.radio,
@@ -289,6 +311,7 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
ofono_message_waiting_register(ofono_message_waiting_create(modem));
}
@@ -385,6 +408,10 @@ static void ril_modem_remove(struct ofono_modem *ofono)
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
ril_radio_unref(modem->radio);
ril_sim_settings_remove_handler(modem->sim_settings,
md->sim_imsi_event_id);
ril_sim_settings_unref(modem->sim_settings);
if (md->online_check_id) {
g_source_remove(md->online_check_id);
}
@@ -399,13 +426,13 @@ static void ril_modem_remove(struct ofono_modem *ofono)
ril_network_unref(modem->network);
ril_sim_card_unref(modem->sim_card);
ril_sim_settings_unref(modem->sim_settings);
ril_cell_info_unref(modem->cell_info);
ril_data_unref(modem->data);
grilio_channel_unref(modem->io);
grilio_queue_cancel_all(md->q, FALSE);
grilio_queue_unref(md->q);
g_free(md->ecclist_file);
g_free(md->log_prefix);
g_free(md->imei);
g_free(md);
}
@@ -436,6 +463,8 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
modem->log_prefix = log_prefix;
modem->ecclist_file =
md->ecclist_file = g_strdup(slot->ecclist_file);
md->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
modem->ofono = ofono;
modem->radio = ril_radio_ref(radio);
@@ -446,6 +475,16 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
modem->data = ril_data_ref(data);
modem->io = grilio_channel_ref(io);
md->q = grilio_queue_new(io);
/*
* modem->sim_settings->imsi follows IMSI known to the ofono
* core, unlike ril_sim_info->imsi which may point to the
* cached IMSI even before the PIN code is entered.
*/
md->sim_imsi_event_id =
ril_sim_settings_add_imsi_changed_handler(settings,
ril_modem_imsi_cb, md);
md->set_online.md = md;
md->set_offline.md = md;
ofono_modem_set_data(ofono, md);
@@ -470,6 +509,8 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
*/
grilio_queue_send_request(md->q, NULL,
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
ril_modem_update_radio_settings(md);
return modem;
} else {
ofono_error("Error %d registering %s",

View File

@@ -436,9 +436,30 @@ static int ril_network_pref_mode_expected(struct ril_network *self)
{
struct ril_sim_settings *settings = self->settings;
struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode pref_mode = priv->max_pref_mode ?
MIN(settings->pref_mode, priv->max_pref_mode) :
settings->pref_mode;
/*
* On dual-SIM phones such as Jolla C only one slot at a time
* is allowed to use LTE. Even if the slot which has been using
* LTE gets powered off, we still need to explicitely set its
* preferred mode to GSM, to make LTE machinery available to
* the other slot. This sort of behaviour might not be necessary
* on some hardware and can (should) be made configurable when
* it becomes necessary.
*/
const enum ofono_radio_access_mode max_pref_mode =
(priv->radio->state == RADIO_STATE_ON) ? priv->max_pref_mode :
OFONO_RADIO_ACCESS_MODE_GSM;
/*
* OFONO_RADIO_ACCESS_MODE_ANY is zero. If both pref_mode
* and max_pref_mode are not ANY, we pick the smallest value.
* Otherwise we take any non-zero value if there is one.
*/
const enum ofono_radio_access_mode pref_mode =
(settings->pref_mode && max_pref_mode) ?
MIN(settings->pref_mode, max_pref_mode) :
settings->pref_mode ? settings->pref_mode :
max_pref_mode;
return ril_network_mode_to_rat(self, pref_mode);
}
@@ -555,6 +576,31 @@ static int ril_network_parse_pref_resp(const void *data, guint len)
return pref;
}
static void ril_network_startup_query_pref_mode_cb(GRilIoChannel *io,
int status, const void *data, guint len, void *user_data)
{
if (status == RIL_E_SUCCESS) {
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
priv->rat = ril_network_parse_pref_resp(data, len);
self->pref_mode = ril_network_rat_to_mode(priv->rat);
DBG_(self, "rat mode %d (%s)", priv->rat,
ofono_radio_access_mode_to_string(self->pref_mode));
if (self->pref_mode != pref_mode) {
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
}
/*
* Unlike ril_network_query_pref_mode_cb, this one always
* checks the preferred mode.
*/
ril_network_check_pref_mode(self, FALSE);
}
}
static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
@@ -661,8 +707,11 @@ static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
{
struct ril_network *self = RIL_NETWORK(data);
ril_network_check_pref_mode(self, FALSE);
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(RIL_NETWORK(data));
ril_network_poll_state(self);
}
}
@@ -753,7 +802,9 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
* Query the initial state. Querying network state before the radio
* has been turned on makes RIL unhappy.
*/
ril_network_query_pref_mode(self);
grilio_queue_send_request_full(priv->q, NULL,
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
ril_network_startup_query_pref_mode_cb, NULL, self);
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(self);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,6 +26,7 @@
#include "ril_log.h"
#include <gdbus.h>
#include <gutil_ints.h>
#include <gutil_strv.h>
#include <gutil_misc.h>
#include <mce_display.h>
@@ -54,6 +55,9 @@
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
#define RILMODEM_DEFAULT_DATA_OPT RIL_ALLOW_DATA_AUTO
#define RILMODEM_DEFAULT_DM_FLAGS RIL_DATA_MANAGER_3GLTE_HANDOVER
#define RILMODEM_DEFAULT_DATA_CALL_FORMAT RIL_DATA_CALL_FORMAT_AUTO
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT 4
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY 200 /* ms */
#define RILMODEM_DEFAULT_EMPTY_PIN_QUERY TRUE /* optimistic */
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
@@ -71,6 +75,11 @@
#define RILCONF_ECCLIST_FILE "ecclistFile"
#define RILCONF_ALLOW_DATA_REQ "allowDataReq"
#define RILCONF_EMPTY_PIN_QUERY "emptyPinQuery"
#define RILCONF_DATA_CALL_FORMAT "dataCallFormat"
#define RILCONF_DATA_CALL_RETRY_LIMIT "dataCallRetryLimit"
#define RILCONF_DATA_CALL_RETRY_DELAY "dataCallRetryDelay"
#define RILCONF_LOCAL_HANGUP_REASONS "localHangupReasons"
#define RILCONF_REMOTE_HANGUP_REASONS "remoteHangupReasons"
#define RIL_STORE "ril"
#define RIL_STORE_GROUP "Settings"
@@ -79,6 +88,12 @@
#define RIL_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
#define RIL_STORE_SLOTS_SEP ","
/* The file where error statistics is stored */
#define RIL_ERROR_STORAGE "rilerror"
/* Modem error ids, must be static strings (only one is defined for now) */
static const char RIL_ERROR_ID_RILD_RESTART[] = "rild-restart";
enum ril_plugin_io_events {
IO_EVENT_CONNECTED,
IO_EVENT_ERROR,
@@ -122,7 +137,7 @@ struct ril_slot {
int timeout; /* RIL timeout, in milliseconds */
int index;
int sim_flags;
enum ril_data_allow_data_opt allow_data_opt;
struct ril_data_options data_opt;
struct ril_slot_config config;
struct ril_plugin_priv *plugin;
struct ril_modem *modem;
@@ -202,6 +217,12 @@ static struct ofono_debug_desc ril_plugin_debug OFONO_DEBUG_ATTR = {
.notify = ril_plugin_debug_notify
};
static inline const char *ril_slot_debug_prefix(const struct ril_slot *slot)
{
/* slot->path always starts with a slash, skip it */
return slot->path + 1;
}
static struct ril_plugin_priv *ril_plugin_cast(struct ril_plugin *pub)
{
return G_CAST(pub, struct ril_plugin_priv, pub);
@@ -605,7 +626,7 @@ static void ril_plugin_sim_state_watch(enum ofono_sim_state new_state,
struct ril_slot *slot = data;
struct ril_plugin_priv *plugin = slot->plugin;
DBG("%s sim state %d", slot->path + 1, new_state);
DBG("%s sim state %d", ril_slot_debug_prefix(slot), new_state);
slot->sim_state = new_state;
if (new_state == OFONO_SIM_STATE_READY) {
struct ril_slot *voice_slot = plugin->voice_slot;
@@ -661,10 +682,10 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
struct ril_slot *slot = data;
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
DBG("%s sim registered", slot->path + 1);
DBG("%s sim registered", ril_slot_debug_prefix(slot));
ril_plugin_register_sim(slot, __ofono_atom_get_data(atom));
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
DBG("%s sim unregistered", slot->path + 1);
DBG("%s sim unregistered", ril_slot_debug_prefix(slot));
slot->sim = NULL;
}
@@ -672,8 +693,35 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
ril_plugin_update_modem_paths_full(slot->plugin);
}
static void ril_plugin_handle_error(struct ril_slot *slot)
static void ril_plugin_count_error(struct ril_slot *slot, const char *key,
const char *message)
{
GHashTable *errors = slot->pub.errors;
GKeyFile *storage = storage_open(NULL, RIL_ERROR_STORAGE);
/* Update life-time statistics */
if (storage) {
/* slot->path always starts with a slash, skip it */
const char *group = slot->path + 1;
g_key_file_set_integer(storage, group, key,
g_key_file_get_integer(storage, group, key, NULL) + 1);
storage_close(NULL, RIL_ERROR_STORAGE, storage, TRUE);
}
/* Update run-time error counts. The key is the error id which
* is always a static string */
g_hash_table_insert(errors, (void*)key, GINT_TO_POINTER(
GPOINTER_TO_INT(g_hash_table_lookup(errors, key)) + 1));
/* Issue the D-Bus signal */
ril_plugin_dbus_signal_modem_error(slot->plugin->dbus,
slot->index, key, message);
}
static void ril_plugin_handle_error(struct ril_slot *slot, const char *msg)
{
ofono_error("%s %s", ril_slot_debug_prefix(slot), msg);
ril_plugin_count_error(slot, RIL_ERROR_ID_RILD_RESTART, msg);
ril_plugin_shutdown_slot(slot, TRUE);
ril_plugin_update_modem_paths_full(slot->plugin);
ril_plugin_retry_init_io(slot);
@@ -682,12 +730,12 @@ static void ril_plugin_handle_error(struct ril_slot *slot)
static void ril_plugin_slot_error(GRilIoChannel *io, const GError *error,
void *data)
{
ril_plugin_handle_error((struct ril_slot *)data);
ril_plugin_handle_error((struct ril_slot *)data, GERRMSG(error));
}
static void ril_plugin_slot_disconnected(GRilIoChannel *io, void *data)
{
ril_plugin_handle_error((struct ril_slot *)data);
ril_plugin_handle_error((struct ril_slot *)data, "disconnected");
}
static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
@@ -695,7 +743,7 @@ static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
{
struct ril_slot *slot = data;
DBG("%s %d", slot->path + 1, online);
DBG("%s %d", ril_slot_debug_prefix(slot), online);
GASSERT(slot->modem);
GASSERT(slot->modem == modem);
@@ -807,14 +855,15 @@ static void ril_debug_trace_update(struct ril_slot *slot)
static const char *ril_plugin_log_prefix(struct ril_slot *slot)
{
return ril_plugin_multisim(slot->plugin) ? (slot->path + 1) : "";
return ril_plugin_multisim(slot->plugin) ?
ril_slot_debug_prefix(slot) : "";
}
static void ril_plugin_create_modem(struct ril_slot *slot)
{
struct ril_modem *modem;
DBG("%s", slot->path);
DBG("%s", ril_slot_debug_prefix(slot));
GASSERT(slot->io && slot->io->connected);
GASSERT(!slot->modem);
@@ -969,7 +1018,8 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
GASSERT(!slot->data);
slot->data = ril_data_new(slot->plugin->data_manager, log_prefix,
slot->radio, slot->network, slot->io, slot->allow_data_opt);
slot->radio, slot->network, slot->io, &slot->data_opt,
&slot->config);
GASSERT(!slot->cell_info);
if (slot->io->ril_version > 8) {
@@ -1063,7 +1113,13 @@ static struct ril_slot *ril_plugin_slot_new(const char *sockpath,
slot->config.empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
slot->allow_data_opt = RILMODEM_DEFAULT_DATA_OPT;
slot->data_opt.allow_data = RILMODEM_DEFAULT_DATA_OPT;
slot->data_opt.data_call_format = RILMODEM_DEFAULT_DATA_CALL_FORMAT;
slot->data_opt.data_call_retry_limit =
RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT;
slot->data_opt.data_call_retry_delay_ms =
RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY;
slot->pub.errors = g_hash_table_new(g_str_hash, g_str_equal);
return slot;
}
@@ -1153,17 +1209,67 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
strval = ril_config_get_string(file, group,
RILCONF_ALLOW_DATA_REQ);
if (strval) {
slot->allow_data_opt =
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(strval, '#');
if (comment) *comment = 0;
g_strstrip(strval);
slot->data_opt.allow_data =
!strcasecmp(strval, "on") ? RIL_ALLOW_DATA_ON :
!strcasecmp(strval, "off")? RIL_ALLOW_DATA_OFF :
RIL_ALLOW_DATA_AUTO;
DBG("%s: %s %s", group, RILCONF_ALLOW_DATA_REQ,
slot->allow_data_opt==RIL_ALLOW_DATA_ON? "on":
slot->allow_data_opt==RIL_ALLOW_DATA_OFF? "off":
"auto");
slot->data_opt.allow_data ==
RIL_ALLOW_DATA_ON ? "on":
slot->data_opt.allow_data ==
RIL_ALLOW_DATA_OFF ? "off":
"auto");
g_free(strval);
}
strval = ril_config_get_string(file, group,
RILCONF_DATA_CALL_FORMAT);
if (strval) {
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(strval, '#');
if (comment) *comment = 0;
g_strstrip(strval);
slot->data_opt.data_call_format =
!strcmp(strval, "6") ? RIL_DATA_CALL_FORMAT_6:
!strcmp(strval, "9") ? RIL_DATA_CALL_FORMAT_9:
!strcmp(strval, "11")? RIL_DATA_CALL_FORMAT_11:
RIL_DATA_CALL_FORMAT_AUTO;
if (slot->data_opt.data_call_format ==
RIL_DATA_CALL_FORMAT_AUTO) {
DBG("%s: %s auto", group,
RILCONF_DATA_CALL_FORMAT);
} else {
DBG("%s: %s %d", group,
RILCONF_DATA_CALL_FORMAT,
slot->data_opt.data_call_format);
}
g_free(strval);
}
if (ril_config_get_integer(file, group,
RILCONF_DATA_CALL_RETRY_LIMIT, &value) && value >= 0) {
DBG("%s: %s %d", group,
RILCONF_DATA_CALL_RETRY_LIMIT, value);
slot->data_opt.data_call_retry_limit = value;
}
if (ril_config_get_integer(file, group,
RILCONF_DATA_CALL_RETRY_DELAY, &value) && value >= 0) {
DBG("%s: %s %d ms", group,
RILCONF_DATA_CALL_RETRY_DELAY, value);
slot->data_opt.data_call_retry_delay_ms = value;
}
slot->ecclist_file = ril_config_get_string(file, group,
RILCONF_ECCLIST_FILE);
if (slot->ecclist_file && slot->ecclist_file[0]) {
@@ -1174,6 +1280,27 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
g_free(slot->ecclist_file);
slot->ecclist_file = NULL;
}
slot->config.local_hangup_reasons = ril_config_get_ints(file,
group, RILCONF_LOCAL_HANGUP_REASONS);
strval = ril_config_ints_to_string(
slot->config.local_hangup_reasons, ',');
if (strval) {
DBG("%s: %s %s", group, RILCONF_LOCAL_HANGUP_REASONS,
strval);
g_free(strval);
}
slot->config.remote_hangup_reasons = ril_config_get_ints(file,
group, RILCONF_REMOTE_HANGUP_REASONS);
strval = ril_config_ints_to_string(
slot->config.remote_hangup_reasons, ',');
if (strval) {
DBG("%s: %s %s", group, RILCONF_REMOTE_HANGUP_REASONS,
strval);
g_free(strval);
}
} else {
DBG("no socket path in %s", group);
}
@@ -1186,6 +1313,9 @@ static void ril_plugin_delete_slot(struct ril_slot *slot)
ril_plugin_shutdown_slot(slot, TRUE);
ril_sim_info_unref(slot->sim_info);
ril_sim_settings_unref(slot->sim_settings);
gutil_ints_unref(slot->config.local_hangup_reasons);
gutil_ints_unref(slot->config.remote_hangup_reasons);
g_hash_table_destroy(slot->pub.errors);
g_free(slot->path);
g_free(slot->imei);
g_free(slot->name);
@@ -1341,7 +1471,7 @@ static void ril_plugin_switch_user()
static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
{
if (slot->pub.enabled) {
DBG("%s enabled", slot->path + 1);
DBG("%s enabled", ril_slot_debug_prefix(slot));
ril_plugin_check_modem(slot);
}
}
@@ -1349,7 +1479,7 @@ static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
static void ril_plugin_update_disabled_slot(struct ril_slot *slot)
{
if (!slot->pub.enabled) {
DBG("%s disabled", slot->path + 1);
DBG("%s disabled", ril_slot_debug_prefix(slot));
ril_plugin_shutdown_slot(slot, FALSE);
ril_plugin_update_modem_paths_full(slot->plugin);
}

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
@@ -52,6 +52,7 @@ struct ril_slot_info {
gboolean enabled;
gboolean sim_present;
const struct ril_slot_config *config;
GHashTable *errors;
};
struct ril_plugin {
@@ -123,6 +124,8 @@ void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
gboolean present);
void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
int index, const char *id, const char *message);
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,

View File

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

View File

@@ -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
@@ -85,6 +85,7 @@ struct ril_sim {
ofono_sim_passwd_cb_t query_passwd_state_cb;
void *query_passwd_state_cb_data;
guint query_passwd_state_timeout_id;
gulong query_passwd_state_sim_status_refresh_id;
};
struct ril_sim_io_response {
@@ -379,20 +380,11 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
DBG_(sd, "");
/*
* In case sim card has been removed prior to this callback has been
* called we must not call the core call back method as otherwise the
* core will crash.
*/
if (!sd->inserted) {
ofono_error("No SIM card");
return;
}
ril_error_init_failure(&error);
res = ril_sim_parse_io_response(data, len);
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
if (!sd->inserted) {
DBG_(sd, "No SIM card");
} else if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
gboolean ok = FALSE;
guchar access[3] = { 0x00, 0x00, 0x00 };
guchar file_status = EF_STATUS_VALID;
@@ -700,6 +692,12 @@ static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
sd->query_passwd_state_timeout_id = 0;
}
if (sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
sd->query_passwd_state_sim_status_refresh_id = 0;
}
if (sd->query_passwd_state_cb) {
ofono_sim_passwd_cb_t cb = sd->query_passwd_state_cb;
void *data = sd->query_passwd_state_cb_data;
@@ -893,6 +891,15 @@ static void ril_sim_query_pin_retries(struct ofono_sim *sim,
cb(ril_error_ok(&error), sd->retries, data);
}
static void ril_sim_query_passwd_state_complete_cb(struct ril_sim_card *sc,
void *user_data)
{
struct ril_sim *sd = user_data;
GASSERT(sd->query_passwd_state_sim_status_refresh_id);
ril_sim_finish_passwd_state_query(sd, ril_sim_passwd_state(sd));
}
static gboolean ril_sim_query_passwd_state_timeout_cb(gpointer user_data)
{
struct ril_sim *sd = user_data;
@@ -908,29 +915,41 @@ static void ril_sim_query_passwd_state(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
enum ofono_sim_password_type passwd_state = ril_sim_passwd_state(sd);
struct ofono_error error;
if (sd->query_passwd_state_timeout_id) {
g_source_remove(sd->query_passwd_state_timeout_id);
sd->query_passwd_state_timeout_id = 0;
}
if (passwd_state != OFONO_SIM_PASSWORD_INVALID) {
DBG_(sd, "%d", passwd_state);
sd->query_passwd_state_cb = NULL;
sd->query_passwd_state_cb_data = NULL;
sd->ofono_passwd_state = passwd_state;
cb(ril_error_ok(&error), passwd_state, data);
if (!sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
sd->query_passwd_state_sim_status_refresh_id = 0;
}
/* Always request fresh status, just in case. */
ril_sim_card_request_status(sd->card);
sd->query_passwd_state_cb = cb;
sd->query_passwd_state_cb_data = data;
if (ril_sim_passwd_state(sd) != OFONO_SIM_PASSWORD_INVALID) {
/* Just wait for GET_SIM_STATUS completion */
DBG_(sd, "waiting for SIM status query to complete");
sd->query_passwd_state_sim_status_refresh_id =
ril_sim_card_add_status_received_handler(sd->card,
ril_sim_query_passwd_state_complete_cb, sd);
} else {
/* Wait for the state to change */
DBG_(sd, "waiting for the SIM state to change");
sd->query_passwd_state_cb = cb;
sd->query_passwd_state_cb_data = data;
sd->query_passwd_state_timeout_id =
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
ril_sim_query_passwd_state_timeout_cb, sd);
}
/*
* We still need to complete the request somehow, even if
* GET_STATUS never completes or SIM status never changes.
*/
sd->query_passwd_state_timeout_id =
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
ril_sim_query_passwd_state_timeout_cb, sd);
}
static gboolean ril_sim_pin_change_state_timeout_cb(gpointer user_data)
@@ -1289,6 +1308,11 @@ static void ril_sim_remove(struct ofono_sim *sim)
g_source_remove(sd->query_passwd_state_timeout_id);
}
if (sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
}
ril_sim_card_remove_handler(sd->card, sd->card_status_id);
ril_sim_card_unref(sd->card);

View File

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

View File

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

View File

@@ -154,22 +154,18 @@ static void ril_sim_settings_imsi_watch_done(void *user_data)
priv->imsi_watch_id = 0;
}
static void ril_sim_settings_ready(struct ril_sim_settings *self)
static void ril_sim_settings_state_check(struct ril_sim_settings *self,
enum ofono_sim_state new_state)
{
struct ril_sim_settings_priv *priv = self->priv;
GASSERT(!priv->imsi_watch_id);
priv->imsi_watch_id = ofono_sim_add_imsi_watch(priv->sim,
ril_sim_settings_imsi_watch_cb, self,
ril_sim_settings_imsi_watch_done);
if (new_state != OFONO_SIM_STATE_READY) {
ril_sim_settings_set_imsi(self, NULL);
}
}
static void ril_sim_settings_state_watch(enum ofono_sim_state new_state,
void *user_data)
{
if (new_state == OFONO_SIM_STATE_READY) {
ril_sim_settings_ready(RIL_SIM_SETTINGS(user_data));
}
ril_sim_settings_state_check(RIL_SIM_SETTINGS(user_data), new_state);
}
static void ril_sim_settings_state_watch_done(void *user_data)
@@ -191,13 +187,19 @@ void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
if (priv->imsi_watch_id) {
ofono_sim_remove_imsi_watch(priv->sim,
priv->imsi_watch_id);
/* ril_sim_settings_imsi_watch_done clears it */
/*
* ril_sim_settings_imsi_watch_done
* clears it
*/
GASSERT(!priv->imsi_watch_id);
}
if (priv->state_watch_id) {
ofono_sim_remove_state_watch(priv->sim,
priv->state_watch_id);
/* ril_sim_settings_state_watch_done clears it */
/*
* ril_sim_settings_state_watch_done
* clears it
*/
GASSERT(!priv->state_watch_id);
}
priv->sim = sim;
@@ -207,13 +209,25 @@ void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
ril_sim_settings_state_watch, self,
ril_sim_settings_state_watch_done);
GASSERT(priv->state_watch_id);
if (ofono_sim_get_state(sim) ==
OFONO_SIM_STATE_READY) {
ril_sim_settings_ready(self);
}
} else {
ril_sim_settings_set_imsi(self, NULL);
ril_sim_settings_state_check(self,
ofono_sim_get_state(sim));
/*
* ofono_sim_add_imsi_watch immediately
* calls the event callback if IMSI is
* already known. It's useless though
* because we still have to check the
* current state in case if IMSI is not
* available yet.
*/
priv->imsi_watch_id =
ofono_sim_add_imsi_watch(priv->sim,
ril_sim_settings_imsi_watch_cb, self,
ril_sim_settings_imsi_watch_done);
GASSERT(priv->state_watch_id);
}
/* Luckily, ofono_sim_get_imsi handles NULL pointer */
ril_sim_settings_set_imsi(self,
ofono_sim_get_imsi(sim));
}
}
}

View File

@@ -113,3 +113,41 @@ socket=/dev/socket/rild
# Default is true
#
#emptyPinQuery=true
# Different RILs use different data call structures which don't necessarily
# match the format specified in the data list header. The header may have
# version 9 but the list may contain RIL_Data_Call_Response_v6 structures,
# list version 10 may contain RIL_Data_Call_Response_v11 and so on. By default
# ofono assumes that the version from the list header matches the contents
# but sometimes you have to explicitly tell ofono which one to use.
# Possible values are 6, 9, 11 and auto.
#
# Default is auto
#
#dataCallFormat=auto
# Data call may fail with status 65535 which according to ril.h means that
# we need to retry silently. The maximum number of retries is limited by
# this parameter. Usually, one retry is enough. The first retry occurs
# immediately, the subsequent ones after dataCallRetryDelay (see below)
#
# Default is 4
#
#dataCallRetryLimit=4
# Delay between data call retries, in milliseconds. Note that the first
# retry occurs immediately after the first failure, the delays are only
# applied if the first retry fails too.
#
# Default is 200 ms
#
#dataCallRetryDelay=200
# Additional local and remote hangup reasons. Remote reasons are checked
# first. Normally, RIL plugin figures it out automatically. You would only
# need to define these if your RIL does something unusual.
#
# No default
#
#remoteHangupReasons=20
#localHangupReasons=23

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -53,6 +53,8 @@ struct ril_slot_config {
guint slot;
gboolean enable_4g;
gboolean empty_pin_query;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
};
#endif /* RIL_TYPES_H */

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,6 +21,7 @@
#include "common.h"
#include <gutil_ints.h>
#include <gutil_ring.h>
#define FLAG_NEED_CLIP 1
@@ -43,7 +44,9 @@ struct ril_voicecall {
ofono_voicecall_cb_t cb;
void *data;
guint timer_id;
GUtilRing* dtmf_queue;
GUtilRing *dtmf_queue;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
guint send_dtmf_id;
guint clcc_poll_id;
gulong event_id[VOICECALL_EVENT_COUNT];
@@ -60,28 +63,13 @@ struct ril_voicecall_change_state_req {
};
struct lastcause_req {
struct ofono_voicecall *vc;
struct ril_voicecall *vd;
int id;
};
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
/*
* structs ofono_voicecall and voicecall are fully defined
* in src/voicecall.c; we need (read) access to the
* call objects, so partially redefine them here.
*/
struct ofono_voicecall {
GSList *call_list;
/* ... */
};
struct voicecall {
struct ofono_call *call;
/* ... */
};
static inline struct ril_voicecall *ril_voicecall_get_data(
struct ofono_voicecall *vc)
{
@@ -166,38 +154,76 @@ static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
}
/* Valid call statuses have value >= 0 */
static int call_status_with_id(struct ofono_voicecall *vc, int id)
static int ril_voicecall_status_with_id(struct ofono_voicecall *vc,
unsigned int id)
{
GSList *l;
struct voicecall *v;
struct ofono_call *call = ofono_voicecall_find_call(vc, id);
GASSERT(vc);
return call ? call->status : -1;
}
for (l = vc->call_list; l; l = l->next) {
v = l->data;
if (v->call->id == id) {
return v->call->status;
/* Tries to parse the payload as a uint followed by a string */
static int ril_voicecall_parse_lastcause_1(const void *data, guint len)
{
int result = -1;
if (len > 8) {
int code;
char *msg = NULL;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &code) && code >= 0 &&
(msg = grilio_parser_get_utf8(&rilp)) &&
grilio_parser_at_end(&rilp)) {
DBG("%d \"%s\"", code, msg);
result = code;
}
g_free(msg);
}
return -1;
return result;
}
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct lastcause_req *reqdata = user_data;
struct ofono_voicecall *vc = reqdata->vc;
int tmp;
struct ril_voicecall *vd = reqdata->vd;
struct ofono_voicecall *vc = vd->vc;
int id = reqdata->id;
int call_status;
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
grilio_parser_get_int32(&rilp, &last_cause);
int last_cause;
/*
* According to ril.h:
*
* "response" is a "int *"
* ((int *)response)[0] is RIL_LastCallFailCause. GSM failure
* reasons are mapped to cause codes defined in TS 24.008 Annex H
* where possible.
*
* However some RILs feel free to invent their own formats,
* try those first.
*/
last_cause = ril_voicecall_parse_lastcause_1(data, len);
if (last_cause < 0) {
GRilIoParser rilp;
int num, code;
/* Default format described in ril.h */
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &num) && num == 1 &&
grilio_parser_get_int32(&rilp, &code) &&
grilio_parser_at_end(&rilp)) {
last_cause = code;
} else {
ofono_warn("Unable to parse last call fail cause");
last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
}
}
/*
@@ -208,7 +234,14 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
* from a network failure.
*/
switch (last_cause) {
if (gutil_ints_contains(vd->remote_hangup_reasons, last_cause)) {
DBG("hangup cause %d => remote hangup", last_cause);
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
} else if (gutil_ints_contains(vd->local_hangup_reasons, last_cause)) {
DBG("hangup cause %d => local hangup", last_cause);
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
} else {
switch (last_cause) {
case CALL_FAIL_UNOBTAINABLE_NUMBER:
case CALL_FAIL_NORMAL:
case CALL_FAIL_BUSY:
@@ -216,19 +249,19 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
case CALL_FAIL_CHANNEL_UNACCEPTABLE:
case CALL_FAIL_OPERATOR_DETERMINED_BARRING:
case CALL_FAIL_NO_USER_RESPONDING:
case CALL_FAIL_USER_ALERTING_NO_ANSWER:
case CALL_FAIL_NO_ANSWER_FROM_USER:
case CALL_FAIL_CALL_REJECTED:
case CALL_FAIL_NUMBER_CHANGED:
case CALL_FAIL_ANONYMOUS_CALL_REJECTION:
case CALL_FAIL_PRE_EMPTION:
case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
case CALL_FAIL_INCOMPLETE_NUMBER:
case CALL_FAIL_INVALID_NUMBER_FORMAT:
case CALL_FAIL_FACILITY_REJECTED:
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
break;
case CALL_FAIL_NORMAL_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
call_status = ril_voicecall_status_with_id(vc, id);
if (call_status == CALL_STATUS_ACTIVE ||
call_status == CALL_STATUS_HELD ||
call_status == CALL_STATUS_DIALING ||
@@ -240,7 +273,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
break;
case CALL_FAIL_ERROR_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
call_status = ril_voicecall_status_with_id(vc, id);
if (call_status == CALL_STATUS_DIALING ||
call_status == CALL_STATUS_ALERTING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
@@ -250,6 +283,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
default:
reason = OFONO_DISCONNECT_REASON_ERROR;
break;
}
}
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
@@ -295,7 +329,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
struct lastcause_req *reqdata =
g_new0(struct lastcause_req, 1);
reqdata->vc = vd->vc;
reqdata->vd = vd;
reqdata->id = oc->id;
grilio_queue_send_request_full(vd->q, NULL,
RIL_REQUEST_LAST_CALL_FAIL_CAUSE,
@@ -803,6 +837,7 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
const struct ril_slot_config *cfg = &modem->config;
struct ril_voicecall *vd;
DBG("");
@@ -810,6 +845,8 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
vd->io = grilio_channel_ref(ril_modem_io(modem));
vd->q = grilio_queue_new(vd->io);
vd->dtmf_queue = gutil_ring_new();
vd->local_hangup_reasons = gutil_ints_ref(cfg->local_hangup_reasons);
vd->remote_hangup_reasons = gutil_ints_ref(cfg->remote_hangup_reasons);
vd->vc = vc;
vd->timer_id = g_idle_add(ril_delayed_register, vd);
if (modem->ecclist_file) {
@@ -841,6 +878,8 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
grilio_queue_cancel_all(vd->q, FALSE);
grilio_queue_unref(vd->q);
gutil_ring_unref(vd->dtmf_queue);
gutil_ints_unref(vd->local_hangup_reasons);
gutil_ints_unref(vd->remote_hangup_reasons);
g_free(vd);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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

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

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

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

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

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,7 @@ Requires: dbus
Requires: systemd
Requires: ofono-configs
Requires: libgrilio >= 1.0.10
Requires: libglibutil >= 1.0.10
Requires: libglibutil >= 1.0.19
Requires(preun): systemd
Requires(post): systemd
Requires(postun): systemd
@@ -21,7 +21,7 @@ BuildRequires: pkgconfig(libudev) >= 145
BuildRequires: pkgconfig(mobile-broadband-provider-info)
BuildRequires: pkgconfig(libwspcodec) >= 2.0
BuildRequires: pkgconfig(libgrilio) >= 1.0.10
BuildRequires: pkgconfig(libglibutil) >= 1.0.10
BuildRequires: pkgconfig(libglibutil) >= 1.0.19
BuildRequires: pkgconfig(libdbuslogserver-dbus)
BuildRequires: pkgconfig(libmce-glib)
BuildRequires: libtool
@@ -71,6 +71,10 @@ autoreconf --force --install
--enable-test \
--enable-debuglog \
--enable-jolla-rilmodem \
--enable-sailfishos \
--disable-add-remove-context \
--disable-isimodem \
--disable-qmimodem \
--with-systemdunitdir="/%{_lib}/systemd/system"
make %{?jobs:-j%jobs}