Compare commits

...

148 Commits

Author SHA1 Message Date
Slava Monich
12ffd8acf9 Merge branch 'post-1.17-picks' into 'master'
Cherry-picked useful post-1.17 commits + a simple bug fix on top of it.

See merge request !25
2016-01-20 13:47:17 +00:00
Slava Monich
df9b35b440 [ril] Set correct status for the current operator. Fixes JB#33922 2016-01-20 11:33:27 +02:00
John Ernberg
76e991d3da network: Fix crash caused by empty Scan() results
When issuing a Scan() in poor reception while attached to an operator it's
fully possible to get no results, which causes the attached operator to be
cleaned up. In certain scenarios this would cause a use-after-free as there
are still references to this operator.
Transfer the attached operator to the new list regardless of removal caused
by the Scan() results.
2016-01-20 11:33:27 +02:00
John Ernberg
90803904be gprs: Fix the ContextAdded() signal Introspection
This matches the behavior described by the documentation the signal
value returned by the code. This was causing a headache when using
stricter D-Bus wrappers like dbus-c++.
2016-01-20 11:33:27 +02:00
John Ernberg
84e547c2ed cbs: Resolve a use-after-free
In situations where location changes rapidly, a use-after-free condition
can occur.  What happens is that the timeout leaks and then the cbs
struct with the callback is cleaned up, resulting in a SIGSEGV when the
callback occurs from the glib loop.
2016-01-20 11:33:27 +02:00
Denis Kenzior
652798d592 modem: Don't move to pre-sim state in case of failure
In ofono_modem_reset, if the enable() callback fails, do not
proceed to the pre-sim state
2016-01-20 11:33:27 +02:00
Denis Kenzior
979a3bcef3 gprs: Implement ofono_gprs_context_get_type 2016-01-20 11:33:27 +02:00
Denis Kenzior
69178c8ecb include: Add ofono_gprs_context_get_type 2016-01-20 11:33:27 +02:00
Slava Monich
1ac1c9268d [gprs] Remove redundant ofono_gprs_get_modem declarations
Upstream now has those too.
2016-01-20 11:33:27 +02:00
Denis Kenzior
5483a8ecc0 gprs: Implement ofono_gprs_get_modem 2016-01-20 11:33:27 +02:00
Denis Kenzior
95dacebb0c gprs: Add ofono_gprs_get_modem() 2016-01-20 11:33:27 +02:00
Simon Fels
b92b1ce13f voicecall: don't dereference a supplied null value
When the voicecall atom is unregistered we remove all HFP support as
well but were supplying a zero as value to the emulator status
callbacks which caused the process to crash as we were dereferencing
the supplied value always and not respecting a zero as indicator to
reset.
2016-01-20 11:33:27 +02:00
Denis Kenzior
70ab2175a0 gprs: Allow synchronous callbacks for set_attached 2016-01-20 11:33:27 +02:00
Denis Kenzior
9810a258a1 radio-settings: Implement get_modem() 2016-01-20 11:33:27 +02:00
Denis Kenzior
760c17052f include: Add ofono_radio_settings_get_modem() 2016-01-20 11:33:27 +02:00
Denis Kenzior
e77b62a91e doc: Add Item M17 to coding-style.txt 2016-01-20 11:33:27 +02:00
Alfonso Sanchez-Beato
7103c81a77 include: Add definitions for phone number types 2016-01-20 11:33:27 +02:00
Slava Monich
2bc610353d [ril] Removed redundant declaration of enum operator_status
It has become public
2016-01-20 11:33:27 +02:00
Tony Espy
dd04ac248d src: make bearer/operator enums public
Move enums for operator_status and packet_bearer to common.h to avoid
duplication in drivers.
2016-01-20 11:33:27 +02:00
Slava Monich
c5b3357000 Merge branch 'merge-1.17' into 'master'
Upgrade to ofono 1.17

Some of the commits look quite useful and yet the whole thing doesn't seem to be particularly destructive (unlike what started happening after 1.17).

See merge request !24
2016-01-20 09:19:42 +00:00
Slava Monich
ddbdf9f649 Merge tag '63f6a75a61e7e07cc773929acb4c13acaf8a4b00' into merge-1.17
Release 1.17

Conflicts:
	ofono/src/gprs.c
	ofono/src/log.c
	ofono/src/main.c
	ofono/src/sim.c
2016-01-19 14:30:45 +02:00
Slava Monich
7b5be51527 [ofono] Update to upstream 1.17 2016-01-19 14:26:00 +02:00
Alfonso Sanchez-Beato
5aef6a8356 sms: Add trace when datagram is not delivered 2016-01-19 14:19:33 +02:00
Alfonso Sanchez-Beato
b99cd4f8ca smsutil: Do not check the origin port
Do not check if the origin port is reserved, as some operators use that
range of values.
2016-01-19 14:18:23 +02:00
Alfonso Sanchez-Beato
47ee85e955 push-notification: Accept push from any origin
Accept push notifications regardless of the origin port, as some
operators do not insert there the WAP connectionless session service
port, and use random values instead.
2016-01-19 14:17:39 +02:00
Denis Kenzior
b500f4fa65 voicecall: Don't accept USSD strings in Dial() 2016-01-19 14:16:01 +02:00
Denis Kenzior
c2c048dc05 gprs: Try re-attaching when we switch cells 2016-01-19 14:15:09 +02:00
Alfonso Sanchez-Beato
df923b481f message-waiting: Fix reading EF_MWIS records 2016-01-19 14:14:13 +02:00
Alfonso Sanchez-Beato
ed0c1f94f6 message-waiting: Update properly EF_MWIS SIM file 2016-01-19 14:13:44 +02:00
Marko Sulejic
6d2852cdaf configure.ac: fix typo 2016-01-19 14:13:00 +02:00
Denis Kenzior
72a1ecf5d0 sim: Fix up whitespace issues 2016-01-19 14:12:14 +02:00
Alfonso Sanchez-Beato
2fa10fb265 gprs: Add comment to gprs_reset_contexts 2016-01-19 14:10:53 +02:00
Denis Kenzior
f907c3a85d test: Fix file mode for reset-contexts 2016-01-19 14:10:28 +02:00
Alfonso Sanchez-Beato
4a7b325191 gprs: Refactor to remove forward declaration 2016-01-19 14:09:58 +02:00
Alfonso Sanchez-Beato
a8103a39fa test: Add script for resetting contexts 2016-01-19 14:07:35 +02:00
Alfonso Sanchez-Beato
4076502017 doc: Add description for ResetContexts method 2016-01-19 14:07:28 +02:00
Alfonso Sanchez-Beato
7ed41beadd gprs: Add DBus method to reset contexts
Add DBus method that removes the current contexts and re-provisions
using the APN database.

Conflicts:
	ofono/src/gprs.c
2016-01-19 14:06:26 +02:00
Luiz Augusto von Dentz
e45389cf84 gdbus: Close private connection if setup fails
Private connection should be properly closed with dbus_connection_close
otherwise libdbus exits with the following error:

  'The last reference on a connection was dropped without closing the
   connection. This is a bug in an application. See
   dbus_connection_unref() documentation for details. Most likely, the
   application was supposed to call dbus_connection_close(), since this
   is a private connection.'
2016-01-19 14:01:44 +02:00
Szymon Janc
4bae61c83e gdbus: Fix crash in g_dbus_create_error_valist
Passing NULL format parameter to vsnprintf results in invalid argument
error on glibc. But with some other libc libraries (musl and uClibc)
this results in dereferencing NULL pointer and crash due to
segmentation fault.
2016-01-19 14:01:37 +02:00
Szymon Janc
11d6e76f0a gdbus: Use g_dbus_create_error_valist internally
There is no need to duplicate code in g_dbus_send_error_valist.
2016-01-19 14:01:27 +02:00
Michael Janssen
4cfa5cdf36 gdbus: Add g_dbus_get_flags function
The g_dbus_get_flags function enables detection of when the
G_DBUS_FLAG_ENABLE_EXPERIMENTAL is set.
2016-01-19 14:01:17 +02:00
Luiz Augusto von Dentz
135923532c gdbus: Make GDBusClient work without ObjectManager
This makes GDBusClient work normally without ObjectManager.
2016-01-19 14:01:11 +02:00
Arman Uguray
d112c042e3 gdbus/client: Allow specifying ObjectManager path
GDBusClient currently hard-codes "/" as the remote ObjectManager path.
This is generally incorrect, as an application can choose to expose an
ObjectManager at any well-known path. This patch fixes this by allowing
the user to pass in the ObjectManager path by introducing a new
conctructor "g_dbus_client_new_full".
2016-01-19 14:01:02 +02:00
Arman Uguray
b9407ff65f gdbus/client: Don't GetManagedObjects w/o handlers
The client code currently issues GetManagedObjects if new handlers are
set via g_dbus_client_set_proxy_handlers. An application may set these
to NULL before unref'ing a client or to simply prevent further events.
Hence, there is no need to refresh objects or properties if all handlers
are NULL.
2016-01-19 14:00:55 +02:00
Szymon Janc
5a92625c9f gdbus: Fix not calling disconnect function
If daemon gets disconnected from D-Bus sender is NULL. Watches that
was explicitly added with NULL sender (ie disconnected_signal in
g_dbus_set_disconnect_function) should be called anyway.
2016-01-19 14:00:40 +02:00
Arman Uguray
c684033671 gdbus: Don't refresh objects/props if disconnected
If g_dbus_client_set_proxy_handlers gets called from within a
proxy_removed callback, the code may end up refreshing the proxy's
properties and incorrectly access the client's proxy_list as it gets
freed. This patch fixes this, so that get_managed_objects does nothing
if it gets called during a service disconnect.
2016-01-19 13:53:41 +02:00
Slava Monich
59cb9c39b9 Merge branch 'jb33872' into 'master'
Fix eternal loop loop with roaming SIM

When ofono core is asking gprs driver to detach (because data roaming is disabled), it's expecting data registration status to change. If that doesn't happen, it starts all over again.

See merge request !22
2016-01-18 15:26:47 +00:00
Slava Monich
0831fd803a [ril] Tweaking mobile data management
Mobile data availability for all slots is now managed by the single
component called ril_data_manager.
2016-01-18 12:28:18 +02:00
Slava Monich
1b6c20759c [ril] Fix eternal loop with roaming sim. Fixes JB#33872
When ofono core is asking gprs driver to detach (because data
roaming is disabled), it's expecting data registration status
to change. If that doesn't happen, it starts all over again.
2016-01-18 12:28:18 +02:00
Slava Monich
3681eb63b1 Merge branch 'voicereg' into 'master'
Allow 3 values for registration state response

This was seen by one of the porters:
```
RIL< [0000000a] VOICE_REGISTRATION_STATE
RIL> [0000000a] OK
RIL> 0000: 00 00 00 00 0a 00 00 00  00 00 00 00 03 00 00 00    ........ ........
RIL  0010: 01 00 00 00 30 00 00 00  04 00 00 00 30 00 30 00    ....0... ....0.0.
RIL  0020: 30 00 30 00 00 00 00 00  08 00 00 00 30 00 30 00    0.0..... ....0.0.
RIL  0030: 30 00 30 00 30 00 30 00  30 00 30 00 00 00 00 00    0.0.0.0. 0.0.....
ofonod[953]: drivers/ril/ril_network.c:ril_network_parse_response() broken response
```

See merge request !23
2016-01-18 10:26:50 +00:00
Slava Monich
5303f766a9 [ril] Provide reasonable default for max_calls
Some older RILs don't provide max calls, in that case let's supply
some reasonable default. We don't need more than 2 simultaneous data
calls anyway.
2016-01-18 00:13:41 +02:00
Slava Monich
2f68eeea6c [ril] Allow 3 values for registration state response 2016-01-17 17:08:42 +02:00
Slava Monich
7a7744781a Merge branch 'imei' into 'master'
Return cached IMEI values from query_serial

Those are always queried at startup and they never change. There's no reason to perform RIL query for IMEI more than once.

See merge request !21
2016-01-14 21:15:23 +00:00
Slava Monich
fc1491c634 [ril] Return cached IMEI values from query_serial
Those are always queried at startup and they never change.
There's no reason to perform RIL query for IMEI more than once.
2016-01-14 16:48:38 +02:00
Slava Monich
c631a48c41 [ril] Set gprs cid range when registering gprs driver. Fixes JB#33861
There is no need to wait for the network state status, the network
may already be operational. Without cid range, attempts to activate
connection context will fail with org.ofono.Error.NotImplemented
2016-01-13 18:08:15 +02:00
Slava Monich
21e90e5abd Housekeeping 2016-01-13 16:52:36 +02:00
Slava Monich
bfcf8b726b Merge branch 'reg_state' into 'master'
Fixed a few issues mostly affecting startup and slowing down sim initialization

1. Don't submit the initial network state request if RIL says that radio is off. I have the impression that RIL doesn't like it; besides it won't work anyway. Instead, wait for radio on or for the network state change event, whichever comes first.
2. When the network state or sim status event occurs and the corresponding query is scheduled to be retried after a failure, retry it right away (i.e. don't wait for the retry timeout to expire).

Requires libgrilio 1.0.6 (already merged) which includes the bug fix for retries happening 1000 times too often (which rild might not like too).

See merge request !19
2016-01-13 14:49:20 +00:00
Slava Monich
3b69c9843b Merge branch 'lastcause' into 'master'
Handle more cause values for call control.

Quite many normal disconnect causes defined in 3GPP TS 24.008 Annex H
are not handled and are thus treated as errors. telepathy-ring would
then play "network out of order" tone, when "busy" tone would be more
appropriate. Add all the call control cause values not defined in ril.h
(but defined in Annex H) here and handle them appropriately.

See merge request !20
2016-01-13 13:58:48 +00:00
Juho Hämäläinen
f24252e2c6 Handle more cause values for call control. Fixes MER#1461
Quite many normal disconnect causes defined in 3GPP TS 24.008 Annex H
are not handled and are thus treated as errors. telepathy-ring would
then play "network out of order" tone, when "busy" tone would be more
appropriate. Add all the call control cause values not defined in ril.h
(but defined in Annex H) here and handle them appropriately.
2016-01-13 15:08:44 +02:00
Slava Monich
4be4cb4f57 [ril] Poke enabled modems with RADIO_POWER request after any modem gets powered off. Fixes JB#33830
If we don't do it, bad things may happen (like the enabled and
apparently powered on modem never registering on the network).
This may have something to do with certain pieces of radio
circuitry being shared by all modems.
2016-01-13 14:38:33 +02:00
Slava Monich
9d4f682b14 [ril] Fixed GET_SIM_STATUS retry 2016-01-13 00:01:02 +02:00
Slava Monich
bd736f7aa6 [ril] Only query the initial network state only if radio is on
Otherwise wait for the network state change event
2016-01-13 00:00:39 +02:00
Slava Monich
ff328c2a73 [systemd] Add $OFONO_DEBUG to the service command line
This allows to put a conf file to /var/lib/environment/ofono/ which
defines OFONO_DEBUG and avoid modifying ofono.service after each update.
2016-01-12 16:29:38 +02:00
Slava Monich
10e908fa96 Merge branch 'ril_subscription' into 'master'
Updated sample ril_subscription.conf

The comments in gril/ril_subscription.conf are not relevant to ril plugin in drivers/ril

See merge request !18
2016-01-11 12:45:56 +00:00
Slava Monich
4aa59c7274 Merge branch 'uicc_sub' into 'master'
Use different SET_UICC_SUBSCRIPTION codes for different RIL versions

RIL_REQUEST_SET_UICC_SUBSCRIPTION is 115 in RIL version 9 (or earlier) and 122 in RIL version 10 and later. Since we don't know in advance which RIL version we are dealing with, we need to make the decision at runtime.

See merge request !17
2016-01-11 12:45:29 +00:00
Slava Monich
d61be44bb4 [ril] Updated sample ril_subscription.conf 2016-01-11 13:16:10 +02:00
Slava Monich
0ed1ef1e4c [ril] Use different SET_UICC_SUBSCRIPTION codes for different RIL versions. Fixes MER#1446
RIL_REQUEST_SET_UICC_SUBSCRIPTION is 115 in RIL version 9 (or earlier)
and 122 in RIL version 10 and later. Since we don't know in advance which
RIL version we are dealing with, we need to make the decision at runtime.
2016-01-11 12:59:58 +02:00
Slava Monich
2fa193ad5b Merge branch 'sim_card' into 'master'
Refactoring of SIM card, network and radio power management

Major refactoring aimed at improving predictability, reliability and reducing RIL socket traffic. For instance, SIM card, radio and network states are now represented at the ofono side by dedicated per-socket objects and state changes are indicated to the interested parties using glib signalling mechanism (as opposed to independently listening to RIL events and performing redundant queries).

Requires libgrilio 1.0.4 (already merged)

See merge request !16
2016-01-11 08:46:48 +00:00
Slava Monich
e686240eeb [ril] Allow to control libgrilio logging with ofono -d option
It can be turned on with -d grilio or via D-Bus
2016-01-10 16:05:58 +02:00
Slava Monich
18bc7a3ad8 [ril] Use libgrilio built-in retry mechanism 2016-01-08 23:20:34 +02:00
Slava Monich
6624066917 [ril] Let gprs driver control "allow data" setting
Also added ril_network object that keeps track of the network state and
reduces the number of RIL requests.
2016-01-07 16:56:12 +02:00
Slava Monich
6015490d41 [ril] Indicate SIM card presence in appropriate radio state. Contributes to JB#33805
This also reduces the number of GET_SIM_STATUS requests. Only one object
per RIL instance makes these requests, the results are shared by all
other objects involved.

In addition to that, radio power on request is retried if radio power
unexpectedly switches off which does happen on multi-sim hardware.
2016-01-07 15:54:14 +02:00
Slava Monich
a135d0ea52 [ril] Sync constants with the latest Android ril.h 2016-01-07 15:47:30 +02:00
Slava Monich
f86159c180 [ril] Reset data modem pointer after default data SIM is gone 2015-12-15 12:38:53 +03:00
Slava Monich
de2b622f3b Merge branch 'radio-settings' into 'master'
Radio settings

Fixes `org.ofono.RadioSettings.GetProperties` failures after switching SIM cards and adds support for `"AvailableTechnologies"` property.

See merge request !13
2015-12-15 09:33:36 +00:00
Slava Monich
077f3f2e1e [ril] radio_settings: Implemented query_available_rats, removed obsolete code 2015-12-09 16:49:20 +03:00
Slava Monich
acbd40f9ad [ofono] radio-settings: Queue GetProperties requests
Just after the modem is added and org.ofono.RadioSettings interface
is registered, ofono may receive a number of GetProperties calls for
this interface. The first one would wait for initial queries to
complete while others may fail.

I guess it was expected that clients would retry the call later
but in practice pretty much all clients treat any D-Bus error as
a permanent failure.

This commit introduces the list of pending GetProperties requests
which all get completed after the initial query is done.
2015-12-09 14:03:24 +03:00
Marcel Holtmann
8929d131a3 Release 1.17 2015-09-13 17:08:07 +02:00
Alfonso Sanchez-Beato
51fc828c5e sms: Add trace when datagram is not delivered 2015-09-08 09:14:03 -05:00
Alfonso Sanchez-Beato
ac14de37ca smsutil: Do not check the origin port
Do not check if the origin port is reserved, as some operators use that
range of values.
2015-09-08 09:14:03 -05:00
Alfonso Sanchez-Beato
665c053803 push-notification: Accept push from any origin
Accept push notifications regardless of the origin port, as some
operators do not insert there the WAP connectionless session service
port, and use random values instead.
2015-09-08 09:14:03 -05:00
Kuba Pawlak
4e9cbcdb89 hfp: Handle extra CCWA event
When a call is waitng, CCWA event is sent and call object
in state WAITING is created. on ReleaseAndAnswer it is
promoted to INCOMING and later to ACTIVE.
iPhones send an extra CCWA event when active call is ended.
This extra event is creating a second call object in state
WAITING. It is not possible to have two WAITING calls, but
previously waiting call was already promoted to INCOMING.
For a brief time we have two calls from the same number,
one INCOMING and one WAITING. Later WAITING one is removed.
As we cannot have a waiting and incoming call at the same
time, ignore CCWA when there is already an INCOMING call.

< \r\n+CIEV: 3,3\r\n
< \r\n+CIEV: 2,1\r\n
< \r\n+CIEV: 3,0\r\n
< \r\n+CCWA: "01234567890",129,1,"Me"\r\n
< \r\n+CIEV: 3,1\r\n
> AT+CLCC\r
< \r\n+CLCC: 1,0,0,0,0,"09876543210",129,"Me"\r\n
< \r\n+CLCC: 2,1,5,0,0,"01234567890",129,"Me"\r\n
< \r\nOK\r\n
< \r\n+CIEV: 2,0\r\n
< \r\n+CCWA: "01234567890",129,1,"Me"\r\n
< \r\n+CIEV: 2,1\r\n
< \r\n+CIEV: 3,0\r\n
> AT+CLCC\r
< \r\n+CLCC: 2,1,0,0,0,"01234567890",129,"Me"\r\n
< \r\nOK\r\n
2015-08-24 16:29:29 -05:00
Denis Kenzior
9ec8d03c7c voicecall: Don't accept USSD strings in Dial() 2015-08-06 17:16:03 -05:00
Kuba Pawlak
3e6bbc676f hfp: Synchronize call state in case of +CHUP error
It is possible for the phone to accept Dial request
but not actually dial. This leaves a voicecall object
in state 'dialling' that cannot be removed.
Proposed workaround is to trigger AT+CLCC when an error
is returned for Hangup. As the call is not on the list,
this would remove this hanging object and signal CallRemoved.

Windows Phone trace with this fix:
ofonod[273]: > ATD1;\r
ofonod[273]: < \r\nOK\r\n
ofonod[273]: src/voicecall.c:dial_handle_result() Registering new call: 1
ofonod[273]: < \r\n+CIEV: 5,4\r\n
ofonod[273]: src/network.c:ofono_netreg_strength_notify() strength 80
ofonod[273]: > AT+CHUP\r
ofonod[273]: < \r\nERROR\r\n
ofonod[273]: src/voicecall.c:generic_callback() command failed with error: Unknown error type
ofonod[273]: > AT+CLCC\r
ofonod[273]: < \r\nOK\r\n
ofonod[273]: src/voicecall.c:ofono_voicecall_disconnected() Got disconnection event for id: 1, reason: 2
2015-08-05 11:15:33 -05:00
Denis Kenzior
8be0245664 cdma-connman: Make static analysis tools happy
The kernel simply puts a null terminator at index 15 prior to ifr_name
processing.  So we do the same.

Original report by:
Sabas Rosales, Blanca E <blanca.e.sabas.rosales@intel.com>

 Buffer not null terminated (BUFFER_SIZE_WARNING) buffer_size_warning:
 Calling strncpy with a maximum size argument of 16 bytes on destination
 array ifr.ifr_ifrn.ifrn_name of size 16 bytes might leave the
 destination string unterminated.

  92        strncpy(ifr.ifr_name, interface, IFNAMSIZ);
2015-07-28 10:18:26 -05:00
Denis Kenzior
ca105f7040 ppp_net: Make static analysis tools happy
The kernel simply puts a null terminator at index 15 prior to ifr_name
processing.  So we do the same.

Original report by:
Sabas Rosales, Blanca E <blanca.e.sabas.rosales@intel.com>

 Buffer not null terminated (BUFFER_SIZE_WARNING) buffer_size_warning:
 Calling strncpy with a maximum size argument of 16 bytes on destination
 array ifr.ifr_ifrn.ifrn_name of size 16 bytes might leave the
 destination string unterminated.

  67        strncpy(ifr.ifr_name, net->if_name, sizeof(ifr.ifr_name));
2015-07-28 10:16:16 -05:00
Denis Kenzior
dbb3ec13e5 gprs: Try re-attaching when we switch cells 2015-07-20 13:51:29 -05:00
Alfonso Sanchez-Beato
1b3302322a message-waiting: Fix reading EF_MWIS records 2015-07-16 20:22:38 -05:00
Alfonso Sanchez-Beato
cd76f913f0 message-waiting: Update properly EF_MWIS SIM file 2015-07-16 20:17:27 -05:00
Denis Kenzior
8dc220bc11 AUTHORS: Mention Johannes' contributions 2015-07-16 14:11:14 -05:00
Johannes 'josch' Schauer
b04fabcda3 udevng: add support for Ericsson N5321 gw 2015-07-16 14:10:41 -05:00
Kuba Pawlak
71df8bb15e hfp_hf_bluez5: Fix crash on re-pairing a Device
It may happen that a Device object is unpaired an paired again
without being removed from DBus. This in turn triggers second
modem object to be created, but not fully initialized.
If this modem object is used, oFono will crash.
2015-07-12 21:19:31 -05:00
Denis Kenzior
35ebbf4c97 handsfree: Mark GetProperties method ASYNC 2015-07-06 04:06:45 -05:00
Marcel Holtmann
a2acb227fd u8500: Fix compiler warning with logical expression
CC       plugins/u8500.o
plugins/u8500.c: In function ‘reachable_cb’:
plugins/u8500.c:235:28: error: logical not is only applied to the left hand side of comparison [-Werror=logical-not-parentheses]
  if (!g_isi_msg_error(msg) < 0)
                            ^
2015-07-07 11:35:54 +02:00
Marcel Holtmann
def77f7653 n900: Fix compiler warning with logical expression
CC       plugins/n900.o
plugins/n900.c: In function ‘mtc_reachable_cb’:
plugins/n900.c:241:28: error: logical not is only applied to the left hand side of comparison [-Werror=logical-not-parentheses]
  if (!g_isi_msg_error(msg) < 0)
                            ^
2015-07-07 11:35:54 +02:00
Marcel Holtmann
c3af639874 isiusb: Fix compiler warning with logical expression
CC       plugins/isiusb.o
plugins/isiusb.c: In function ‘reachable_cb’:
plugins/isiusb.c:207:28: error: logical not is only applied to the left hand side of comparison [-Werror=logical-not-parentheses]
  if (!g_isi_msg_error(msg) < 0)
                            ^
2015-07-07 11:35:54 +02:00
Marcel Holtmann
b2b67fa74e gatchat: Fix compiler warning with logical expression
CC       gatchat/gatchat.o
gatchat/gatchat.c: In function ‘have_line’:
gatchat/gatchat.c:586:28: error: logical not is only applied to the left hand side of comparison [-Werror=logical-not-parentheses]
  if (!strncmp(str, "AT", 2) == TRUE)
                            ^
2015-07-07 11:35:54 +02:00
Denis Kenzior
96754c0dfc AUTHORS: Mention Marko's contributions 2015-07-05 05:44:46 -05:00
Marko Sulejic
f2c474c55a configure.ac: fix typo 2015-07-05 05:43:56 -05:00
Denis Kenzior
58076d9a00 AUTHORS: Mention Sergey's contributions 2015-07-01 08:10:39 -05:00
Sergey Alirzaev
4a937b96aa build: make ofono build against musl
ifdef away GNU libc extensions and use a POSIXly correct pointer type
2015-07-01 08:09:53 -05:00
Denis Kenzior
fceb5a41c2 handsfree: Fix potential buffer overflow
Function: ag_features_list
 static const char *list[10];  (Out of bounds write, line 75)
  Incrementing i the value is now 10, for “hf-indicators”

Reported by: blanca.e.sabas.rosales@intel.com
2015-06-30 16:58:36 -05:00
Denis Kenzior
48da783732 sim: Fix up whitespace issues 2015-06-18 14:59:06 -05:00
Tommi Kenakkala
eebe2f3ac2 Emit LockedPins after pin_type is queried
Fixes property change not being emited when hot-swapping a
PIN-enabled card.
2015-06-18 14:56:05 -05:00
Tommi Kenakkala
4677729502 sim: Reset pin_type on card remove
Fixes PinRequired not being emitted when a card is inserted
2015-06-17 23:09:03 -05:00
Kuba Pawlak
93ccb84761 hfpmodem: Fix connecting to AG with existing mpty
If there is more then one active or held call, we are in mpty calls.
We won't get indicator update if any of them is released by CHLD=1x.
So we have to poll it.
2015-06-04 16:18:08 -05:00
Alfonso Sanchez-Beato
e70afdd9dc gprs: Add comment to gprs_reset_contexts 2015-05-18 12:13:04 -05:00
Denis Kenzior
1edb6eec9b test: Fix file mode for reset-contexts 2015-05-18 10:02:10 -05:00
Alfonso Sanchez-Beato
946b568f43 gprs: Refactor to remove forward declaration 2015-05-18 09:08:33 -05:00
Alfonso Sanchez-Beato
f3f3dabfac test: Add script for resetting contexts 2015-05-18 09:08:28 -05:00
Alfonso Sanchez-Beato
4c0f783f5c doc: Add description for ResetContexts method 2015-05-18 09:08:20 -05:00
Alfonso Sanchez-Beato
444611c086 gprs: Add DBus method to reset contexts
Add DBus method that removes the current contexts and re-provisions
using the APN database.
2015-05-18 09:08:13 -05:00
Alex J Lennon
f8d9485dc2 cinterion: Correct use of freed structure
On error struct cb_data *cbd was used after in cinterion_set_online
after already being freed.
2015-05-13 15:56:34 -05:00
Denis Kenzior
23c45abd57 ste: Fix out-of-order free
CALLBACK_WITH_FAILURE used data structure freed just beforehand
2015-05-13 15:55:00 -05:00
Denis Kenzior
a371f46735 dundee: Fix out-of-order free
CALLBACK_WITH_FAILURE used data structure freed just beforehand
2015-05-13 15:44:39 -05:00
Denis Kenzior
ce0529fcf6 AUTHORS: Mention Alex's contributions 2015-05-13 09:57:53 -05:00
Alex J Lennon
fc3f937a67 udev: Add support for ehs6 name
As with tc65, ehs6 makes use of cinterion plugin
2015-05-13 09:57:53 -05:00
Alex J Lennon
7d4a19b114 cinterion: Register as OFONO_VENDOR_CINTERION
This enables us to take advantage of vendor specific quirks
(e.g. signal strength handling specifics for tc65)
2015-05-13 09:57:53 -05:00
Alex J Lennon
4242f6ee72 atmodem: Add Cinterion quirk for signal strength
Implement OFONO_VENDOR_CINTERION specific vendor support to register
textual +CIEV indications for signal strength using AT^SIND command.
2015-05-13 09:57:53 -05:00
Alex J Lennon
b31a3c2390 tc65: Replace tc65 plugin with cinterion plugin
On the basis that tc6x and other Cinterion devices will likely
have similar firmware requirements, provide a generic Cinterion
plugin which is functionally identical to the replaced tc65 plugin.

The udev implementation retains support for "tc65" name for
backwards compatibility, and adds support for the new "cinterion"
name.
2015-05-13 09:57:53 -05:00
Denis Kenzior
8d47f97106 hfp_hf_bluez5: Implement sco_connected_hint 2015-05-13 09:57:53 -05:00
Denis Kenzior
fdba39b8ed handsfree-audio: Call sco_connected_hint 2015-05-13 09:57:52 -05:00
Denis Kenzior
288364295c include: Add sco_connected_hint to handsfree-audio 2015-05-13 09:57:52 -05:00
Denis Kenzior
bce5d9579c gatchat: Introduce g_at_chat_get_userdata 2015-05-13 09:57:52 -05:00
Denis Kenzior
1c2987670d handsfree-audio: Add additional debugs 2015-05-13 09:57:52 -05:00
Luiz Augusto von Dentz
a5b040b781 gdbus: Close private connection if setup fails
Private connection should be properly closed with dbus_connection_close
otherwise libdbus exits with the following error:

  'The last reference on a connection was dropped without closing the
   connection. This is a bug in an application. See
   dbus_connection_unref() documentation for details. Most likely, the
   application was supposed to call dbus_connection_close(), since this
   is a private connection.'
2015-04-20 09:04:39 +02:00
Szymon Janc
97abe1751d gdbus: Fix crash in g_dbus_create_error_valist
Passing NULL format parameter to vsnprintf results in invalid argument
error on glibc. But with some other libc libraries (musl and uClibc)
this results in dereferencing NULL pointer and crash due to
segmentation fault.
2015-04-09 16:59:08 +02:00
Szymon Janc
2f75b13ecd gdbus: Use g_dbus_create_error_valist internally
There is no need to duplicate code in g_dbus_send_error_valist.
2015-04-09 16:59:08 +02:00
Michael Janssen
73e517bcca gdbus: Add g_dbus_get_flags function
The g_dbus_get_flags function enables detection of when the
G_DBUS_FLAG_ENABLE_EXPERIMENTAL is set.
2015-04-07 19:00:45 +02:00
Luiz Augusto von Dentz
dae225a0d6 gdbus: Make GDBusClient work without ObjectManager
This makes GDBusClient work normally without ObjectManager.
2015-03-26 10:02:05 +01:00
Arman Uguray
97ac3f7c76 gdbus/client: Allow specifying ObjectManager path
GDBusClient currently hard-codes "/" as the remote ObjectManager path.
This is generally incorrect, as an application can choose to expose an
ObjectManager at any well-known path. This patch fixes this by allowing
the user to pass in the ObjectManager path by introducing a new
conctructor "g_dbus_client_new_full".
2015-03-26 10:02:05 +01:00
Arman Uguray
26a00f2f31 gdbus/client: Don't GetManagedObjects w/o handlers
The client code currently issues GetManagedObjects if new handlers are
set via g_dbus_client_set_proxy_handlers. An application may set these
to NULL before unref'ing a client or to simply prevent further events.
Hence, there is no need to refresh objects or properties if all handlers
are NULL.
2015-03-26 10:02:05 +01:00
Kuba Pawlak
cede3700f7 hfpmodem: slc.c: make sure to use none_prefix 2015-03-24 11:05:03 -05:00
Kuba Pawlak
318d313fc9 hfpmodem: hfpmodem.c make sure to use none_prefix 2015-03-24 11:04:48 -05:00
Kuba Pawlak
8e6ebab83b hfp_ag_bluez5: use none prefix for AT+BCC.
iPhone 5s with iOS8.2 sometimes failes to acknowledge AT+BCC
with OK. This means +CIEV events get consumed by this command
and call ended notification is not parsed.

Nov 30 00:00:19 ofonod[938]: > AT+BCC\r
Nov 30 00:00:28 ofonod[938]: < \r\n+CIEV: 2,0\r\n
2015-03-24 09:12:58 -05:00
Szymon Janc
d8edd49535 gdbus: Fix not calling disconnect function
If daemon gets disconnected from D-Bus sender is NULL. Watches that
was explicitly added with NULL sender (ie disconnected_signal in
g_dbus_set_disconnect_function) should be called anyway.
2015-02-24 18:24:42 +01:00
Arman Uguray
8660527b11 gdbus: Don't refresh objects/props if disconnected
If g_dbus_client_set_proxy_handlers gets called from within a
proxy_removed callback, the code may end up refreshing the proxy's
properties and incorrectly access the client's proxy_list as it gets
freed. This patch fixes this, so that get_managed_objects does nothing
if it gets called during a service disconnect.
2015-02-22 19:42:25 +01:00
Denis Kenzior
d6bc91ebfc hfpmodem: Make sure to use none_prefix
ofonod[253]: > AT+CCWA=1\r
ofonod[253]: < \r\n+BCS:2\r\n
ofonod[253]: < \r\nOK\r\n
2015-02-20 10:30:21 -06:00
Denis Kenzior
3d592d7d46 hfpmodem: Make sure to set the prefix properly
ofonod[1239]: > AT+COPS=3,0\r
ofonod[1239]: < \r\n+BCS:2\r\n
ofonod[1239]: < \r\nOK\r\n
2015-02-20 10:28:24 -06:00
Denis Kenzior
e2398b4dfa smsutil: Add additional sanity check
We make sure that after performing the UTF8 -> GSM conversion, the
number of GSM bytes is not greater than 11, which is the maximum
payload.
2015-02-13 09:59:59 -06:00
Tommi Kenakkala
42deee76a1 unit: Add test to encode / decode 11 char TP-OA 2015-02-13 09:55:16 -06:00
Tommi Kenakkala
2af3c733b7 sms: Fix alphanumeric TP-OA handling
TP-OA max length comparisons were incorrect because TP-OA's 7-bit
coded octets transport eleven 8-bit chars.  The current code assumed
only 10 chars were possible.

The patch
- increases the array size to 23, (maximum of 22 bytes for UTF8
  encoding + null terminator)
- Updates the sanity check to account for the correct maximum
- For encoding, checks the maximum length in UTF8 characters instead of
  bytes
2015-02-13 09:49:39 -06:00
Denis Kenzior
604fa223f4 AUTHORS: Mention Tommi's contributions 2015-02-02 09:29:46 -06:00
Tommi Kenakkala
04218d3a86 handsfree-audio: Refactor manager init / cleanup 2015-02-02 09:28:34 -06:00
Tommi Kenakkala
41fadd3787 main: Remove handsfree_audio_manager init/cleanup
Init allocates a SCO audio socket always. oFono should do that
with bluez5 but not with bluez4.  This patch starts the refactoring of
the handsfree_audio_manager init/cleanup functionality.
2015-02-02 09:26:58 -06:00
Cedric Jehasse
d539ed19f3 atmodem: fix retries reporting from AT+CPINR
The retries array was not correctly filled in.
2015-02-02 09:22:21 -06:00
Cedric Jehasse
25f926c733 atmodem: Sierra modems should be polled after CPIN
Sierra modem will return "CME ERROR: 14" when polled right after pin has
been entered. Use the existing vendor quirk to handle this.
2015-02-02 09:21:10 -06:00
Cedric Jehasse
151b837428 sierra: add sim state polling after CFUN enable
When pin is queried shortly after a Siera dongle is plugged in,
"AT+CPIN?" responds with "CME ERROR 14: SIM".
Poll the sim, as already done by several other vendor plugins.
2015-01-31 10:20:18 -06:00
82 changed files with 4534 additions and 2034 deletions

View File

@@ -99,3 +99,8 @@ Jussi Pakkanen <jussi.pakkanen@canonical.com>
Sergio Checa Blanco <sergio.checa@bmw-carit.de>
Philip Paeps <philip@paeps.cx>
Kuba Pawlak <kubax.t.pawlak@intel.com>
Tommi Kenakkala <tommi.kenakkala@tieto.com>
Alex J Lennon <ajlennon@dynamicdevices.co.uk>
Sergey Alirzaev <zl29ah@gmail.com>
Marko Sulejic <marko.sulejic@hale.at>
Johannes 'josch' Schauer <josch@mister-muffin.de>

View File

@@ -1,3 +1,13 @@
ver 1.17:
Fix issue with alphanumeric TP-OA handling.
Fix issue with push notification origin port.
Fix issue with reading of EF_MWIS records.
Fix issue with handling AT+CPINR results.
Fix issue with SIM state polling for Sierra modems.
Fix issue with HFP handling and AT command prefixes.
Fix issue with HFP and extra CCWA event handling.
Fix issue with HFP call state and +CHUP errors.
ver 1.16:
Fix issue with PIN retry handling.
Fix issue with HFP and multiple calls.

View File

@@ -126,24 +126,33 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_call_settings.c \
drivers/ril/ril_call_volume.c \
drivers/ril/ril_cbs.c \
drivers/ril/ril_data.c \
drivers/ril/ril_devinfo.c \
drivers/ril/ril_gprs.c \
drivers/ril/ril_gprs_context.c \
drivers/ril/ril_mce.c \
drivers/ril/ril_modem.c \
drivers/ril/ril_netreg.c \
drivers/ril/ril_network.c \
drivers/ril/ril_oem_raw.c \
drivers/ril/ril_phonebook.c \
drivers/ril/ril_plugin.c \
drivers/ril/ril_plugin_dbus.c \
drivers/ril/ril_radio.c \
drivers/ril/ril_radio_settings.c \
drivers/ril/ril_sim.c \
drivers/ril/ril_sim_card.c \
drivers/ril/ril_sim_dbus.c \
drivers/ril/ril_sms.c \
drivers/ril/ril_stk.c \
drivers/ril/ril_ussd.c \
drivers/ril/ril_util.c \
drivers/ril/ril_voicecall.c
if DATAFILES
dist_conf_DATA += drivers/ril/ril_subscription.conf
endif
else
builtin_sources += $(gril_sources)
@@ -175,6 +184,11 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
drivers/rilmodem/oemraw-messages.c \
drivers/rilmodem/call-barring.c \
drivers/rilmodem/stk.c
if DATAFILES
dist_conf_DATA += gril/ril_subscription.conf
endif
endif
endif
@@ -407,9 +421,6 @@ builtin_sources += plugins/phonesim.c
if DATAFILES
dist_conf_DATA += plugins/phonesim.conf
if RILMODEM
dist_conf_DATA += gril/ril_subscription.conf
endif
endif
endif
@@ -465,8 +476,8 @@ builtin_sources += plugins/stemgr.c
builtin_modules += caif
builtin_sources += plugins/caif.c
builtin_modules += tc65
builtin_sources += plugins/tc65.c
builtin_modules += cinterion
builtin_sources += plugins/cinterion.c
builtin_modules += nokia
builtin_sources += plugins/nokia.c

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(ofono, 1.16)
AC_INIT(ofono, 1.17)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)
@@ -173,8 +173,8 @@ AC_ARG_ENABLE(jolla-rilmodem,
AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_rilmodem}" != "no")
if (test "${enable_jolla_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio, dummy=yes,
AC_MSG_ERROR(libgrilio is required))
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.6, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.6 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil, dummy=yes,
AC_MSG_ERROR(libglibutil is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS"
@@ -216,7 +216,7 @@ AC_ARG_WITH([provisiondb], AC_HELP_STRING([--with-provisiondb=FILE],
[location of provision database]), [path_provisiondb=${withval}])
AC_ARG_ENABLE(provision, AC_HELP_STRING([--disable-provision],
[disable provisioning suport]),
[disable provisioning support]),
[enable_provision=${enableval}])
if (test "${enable_provision}" != "no"); then
if (test -n "${path_provisiondb}"); then

View File

@@ -306,6 +306,13 @@ Example:
2)
0x1 << y // Wrong
M17: Avoid forward-declaration of static functions
==================================================
Functions that are static should not be forward-declared. The only exception
to this rule is if a circular dependency condition exists, and the forward
declaration cannot be avoided.
O1: Shorten the name
====================
Better to use abbreviation, rather than full name, to name a variable,

View File

@@ -60,6 +60,16 @@ Methods dict GetProperties()
[service].Error.NotFound
[service].Error.Failed
void ResetContexts()
Removes all contexts and re-provisions from the APN
database. Contexts must all be deactivated for this
method to work, and the atom must not be powered.
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.NotAllowed
Signals PropertyChanged(string property, variant value)
This signal indicates a changed value of the given

View File

@@ -838,6 +838,39 @@ static void telit_ciev_notify(GAtResult *result, gpointer user_data)
ofono_netreg_strength_notify(netreg, strength);
}
static void cinterion_ciev_notify(GAtResult *result, gpointer user_data)
{
struct ofono_netreg *netreg = user_data;
struct netreg_data *nd = ofono_netreg_get_data(netreg);
const char *signal_identifier = "rssi";
const char *ind_str;
int strength;
GAtResultIter iter;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CIEV:"))
return;
if (!g_at_result_iter_next_unquoted_string(&iter, &ind_str))
return;
if (!g_str_equal(signal_identifier, ind_str))
return;
if (!g_at_result_iter_next_number(&iter, &strength))
return;
DBG("rssi %d", strength);
if (strength == nd->signal_invalid)
strength = -1;
else
strength = (strength * 100) / (nd->signal_max - nd->signal_min);
ofono_netreg_strength_notify(netreg, strength);
}
static void ctzv_notify(GAtResult *result, gpointer user_data)
{
struct ofono_netreg *netreg = user_data;
@@ -1915,6 +1948,27 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
g_at_chat_send(nd->chat, "AT*TLTS=1", none_prefix,
NULL, NULL, NULL);
break;
case OFONO_VENDOR_CINTERION:
/*
* We can't set rssi bounds from Cinterion responses
* so set them up to specified values here
*
* Cinterion rssi signal strength specified as:
* 0 <= -112dBm
* 1 - 4 signal strengh in 15 dB steps
* 5 >= -51 dBm
* 99 not known or undetectable
*/
nd->signal_min = 0;
nd->signal_max = 5;
nd->signal_invalid = 99;
/* Register for specific signal strength reports */
g_at_chat_send(nd->chat, "AT^SIND=\"rssi\",1", none_prefix,
NULL, NULL, NULL);
g_at_chat_register(nd->chat, "+CIEV:",
cinterion_ciev_notify, FALSE, netreg, NULL);
break;
case OFONO_VENDOR_NOKIA:
case OFONO_VENDOR_SAMSUNG:
/* Signal strength reporting via CIND is not supported */

View File

@@ -827,7 +827,7 @@ static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
for (i = 1; i < len; i++) {
if (!strcmp(name, at_sim_name[i].name)) {
retries[i] = val;
retries[at_sim_name[i].type] = val;
break;
}
}
@@ -1350,6 +1350,7 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
case OFONO_VENDOR_ALCATEL:
case OFONO_VENDOR_HUAWEI:
case OFONO_VENDOR_SIMCOM:
case OFONO_VENDOR_SIERRA:
/*
* On ZTE modems, after pin is entered, SIM state is checked
* by polling CPIN as their modem doesn't provide unsolicited

View File

@@ -45,4 +45,5 @@ enum ofono_vendor {
OFONO_VENDOR_ALCATEL,
OFONO_VENDOR_QUECTEL,
OFONO_VENDOR_UBLOX,
OFONO_VENDOR_CINTERION,
};

View File

@@ -45,6 +45,7 @@
static const char *binp_prefix[] = { "+BINP:", NULL };
static const char *bvra_prefix[] = { "+BVRA:", NULL };
static const char *none_prefix[] = { NULL };
struct hf_data {
GAtChat *chat;
@@ -197,7 +198,7 @@ static void hfp_cnum_query(struct ofono_handsfree *hf,
struct hf_data *hd = ofono_handsfree_get_data(hf);
struct cb_data *cbd = cb_data_new(cb, data);
if (g_at_chat_send(hd->chat, "AT+CNUM", NULL,
if (g_at_chat_send(hd->chat, "AT+CNUM", none_prefix,
cnum_query_cb, cbd, g_free) > 0)
return;
@@ -382,8 +383,8 @@ static void hfp_disable_nrec(struct ofono_handsfree *hf,
struct cb_data *cbd = cb_data_new(cb, data);
const char *buf = "AT+NREC=0";
if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
cbd, g_free) > 0)
if (g_at_chat_send(hd->chat, buf, none_prefix,
hf_generic_set_cb, cbd, g_free) > 0)
return;
g_free(cbd);
@@ -401,8 +402,8 @@ static void hfp_hf_indicator(struct ofono_handsfree *hf,
snprintf(buf, sizeof(buf), "AT+BIEV=%u,%u", indicator, value);
if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
cbd, g_free) > 0)
if (g_at_chat_send(hd->chat, buf, none_prefix,
hf_generic_set_cb, cbd, g_free) > 0)
return;
g_free(cbd);

View File

@@ -46,6 +46,7 @@
static const char *cops_prefix[] = { "+COPS:", NULL };
static const char *cind_prefix[] = { "+CIND:", NULL };
static const char *none_prefix[] = { NULL };
struct netreg_data {
GAtChat *chat;
@@ -263,7 +264,7 @@ static void hfp_current_operator(struct ofono_netreg *netreg,
cbd->user = netreg;
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", NULL,
ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix,
NULL, cbd, NULL);
if (ok)

View File

@@ -113,7 +113,8 @@ static void slc_established(struct slc_establish_data *sed)
{
struct hfp_slc_info *info = sed->info;
g_at_chat_send(info->chat, "AT+CMEE=1", NULL, NULL, NULL, NULL);
g_at_chat_send(info->chat, "AT+CMEE=1", none_prefix,
NULL, NULL, NULL);
sed->connect_cb(sed->userdata);
}
@@ -434,8 +435,8 @@ static void brsf_cb(gboolean ok, GAtResult *result, gpointer user_data)
sprintf(str, "AT+BAC=%d", HFP_CODEC_CVSD);
slc_establish_data_ref(sed);
g_at_chat_send(info->chat, str, NULL, bac_cb, sed,
slc_establish_data_unref);
g_at_chat_send(info->chat, str, none_prefix, bac_cb,
sed, slc_establish_data_unref);
return;
}

View File

@@ -333,6 +333,10 @@ static void generic_cb(gboolean ok, GAtResult *result, gpointer user_data)
}
}
if (!ok && vd->calls)
g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix,
clcc_poll_cb, req->vc, NULL);
req->cb(&error, req->data);
}
@@ -711,6 +715,16 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
at_util_call_compare_by_status))
return;
/* some phones may send extra CCWA after active call is ended
* this would trigger creation of second call in state 'WAITING'
* as our previous WAITING call has been promoted to INCOMING
*/
if (g_slist_find_custom(vd->calls,
GINT_TO_POINTER(CALL_STATUS_INCOMING),
at_util_call_compare_by_status))
return;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CCWA:"))
@@ -1134,6 +1148,10 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
struct ofono_voicecall *vc = user_data;
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
unsigned int mpty_ids;
GSList *n;
struct ofono_call *nc;
unsigned int num_active = 0;
unsigned int num_held = 0;
if (!ok)
return;
@@ -1142,6 +1160,22 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
g_slist_foreach(vd->calls, voicecall_notify, vc);
ofono_voicecall_mpty_hint(vc, mpty_ids);
n = vd->calls;
while (n) {
nc = n->data;
if (nc->status == CALL_STATUS_ACTIVE)
num_active++;
else if (nc->status == CALL_STATUS_HELD)
num_held++;
n = n->next;
}
if ((num_active > 1 || num_held > 1) && !vd->clcc_source)
vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL, poll_clcc, vc);
}
static void hfp_voicecall_initialized(gboolean ok, GAtResult *result,
@@ -1183,8 +1217,8 @@ static int hfp_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
ofono_voicecall_set_data(vc, vd);
g_at_chat_send(vd->chat, "AT+CLIP=1", NULL, NULL, NULL, NULL);
g_at_chat_send(vd->chat, "AT+CCWA=1", NULL,
g_at_chat_send(vd->chat, "AT+CLIP=1", none_prefix, NULL, NULL, NULL);
g_at_chat_send(vd->chat, "AT+CCWA=1", none_prefix,
hfp_voicecall_initialized, vc, NULL);
return 0;
}

View File

@@ -5,7 +5,7 @@
* /hardware/ril/reference_ril/ril.h
*
* Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2013-2015 Jolla Ltd.
* Copyright (C) 2013-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -54,67 +54,67 @@
/* call states */
enum ril_call_state {
RIL_CALL_ACTIVE,
RIL_CALL_HOLDING,
RIL_CALL_DIALING,
RIL_CALL_ALERTING,
RIL_CALL_INCOMING,
RIL_CALL_WAITING
RIL_CALL_ACTIVE = 0,
RIL_CALL_HOLDING = 1,
RIL_CALL_DIALING = 2,
RIL_CALL_ALERTING = 3,
RIL_CALL_INCOMING = 4,
RIL_CALL_WAITING = 5
};
/* Radio state */
enum ril_radio_state {
RADIO_STATE_OFF,
RADIO_STATE_UNAVAILABLE,
RADIO_STATE_SIM_NOT_READY,
RADIO_STATE_SIM_LOCKED_OR_ABSENT,
RADIO_STATE_SIM_READY,
RADIO_STATE_RUIM_NOT_READY,
RADIO_STATE_RUIM_READY,
RADIO_STATE_RUIM_LOCKED_OR_ABSENT,
RADIO_STATE_NV_NOT_READY,
RADIO_STATE_NV_READY,
RADIO_STATE_ON
RADIO_STATE_OFF = 0,
RADIO_STATE_UNAVAILABLE = 1,
RADIO_STATE_SIM_NOT_READY = 2,
RADIO_STATE_SIM_LOCKED_OR_ABSENT = 3,
RADIO_STATE_SIM_READY = 4,
RADIO_STATE_RUIM_NOT_READY = 5,
RADIO_STATE_RUIM_READY = 6,
RADIO_STATE_RUIM_LOCKED_OR_ABSENT = 7,
RADIO_STATE_NV_NOT_READY = 8,
RADIO_STATE_NV_READY = 9,
RADIO_STATE_ON = 10
};
/* Preferred network types */
enum ril_pref_net_type {
PREF_NET_TYPE_GSM_WCDMA,
PREF_NET_TYPE_GSM_ONLY,
PREF_NET_TYPE_WCDMA,
PREF_NET_TYPE_GSM_WCDMA_AUTO,
PREF_NET_TYPE_CDMA_EVDO_AUTO,
PREF_NET_TYPE_CDMA_ONLY,
PREF_NET_TYPE_EVDO_ONLY,
PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO,
PREF_NET_TYPE_LTE_CDMA_EVDO,
PREF_NET_TYPE_LTE_GSM_WCDMA,
PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA,
PREF_NET_TYPE_LTE_ONLY,
PREF_NET_TYPE_LTE_WCDMA
PREF_NET_TYPE_GSM_WCDMA = 0,
PREF_NET_TYPE_GSM_ONLY = 1,
PREF_NET_TYPE_WCDMA = 2,
PREF_NET_TYPE_GSM_WCDMA_AUTO = 3,
PREF_NET_TYPE_CDMA_EVDO_AUTO = 4,
PREF_NET_TYPE_CDMA_ONLY = 5,
PREF_NET_TYPE_EVDO_ONLY = 6,
PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7,
PREF_NET_TYPE_LTE_CDMA_EVDO = 8,
PREF_NET_TYPE_LTE_GSM_WCDMA = 9,
PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10,
PREF_NET_TYPE_LTE_ONLY = 11,
PREF_NET_TYPE_LTE_WCDMA = 12
};
/* Radio technologies */
enum ril_radio_tech {
RADIO_TECH_UNKNOWN,
RADIO_TECH_GPRS,
RADIO_TECH_EDGE,
RADIO_TECH_UMTS,
RADIO_TECH_IS95A,
RADIO_TECH_IS95B,
RADIO_TECH_1xRTT ,
RADIO_TECH_EVDO_0,
RADIO_TECH_EVDO_A,
RADIO_TECH_HSDPA,
RADIO_TECH_HSUPA ,
RADIO_TECH_HSPA,
RADIO_TECH_EVDO_B,
RADIO_TECH_EHRPD,
RADIO_TECH_LTE,
RADIO_TECH_HSPAP,
RADIO_TECH_GSM,
RADIO_TECH_TD_SCDMA,
RADIO_TECH_DC_HSDPA
RADIO_TECH_UNKNOWN = 0,
RADIO_TECH_GPRS = 1,
RADIO_TECH_EDGE = 2,
RADIO_TECH_UMTS = 3,
RADIO_TECH_IS95A = 4,
RADIO_TECH_IS95B = 5,
RADIO_TECH_1xRTT = 6,
RADIO_TECH_EVDO_0 = 7,
RADIO_TECH_EVDO_A = 8,
RADIO_TECH_HSDPA = 9,
RADIO_TECH_HSUPA = 10,
RADIO_TECH_HSPA = 11,
RADIO_TECH_EVDO_B = 12,
RADIO_TECH_EHRPD = 13,
RADIO_TECH_LTE = 14,
RADIO_TECH_HSPAP = 15,
RADIO_TECH_GSM = 16,
RADIO_TECH_TD_SCDMA = 17,
RADIO_TECH_IWLAN = 18
};
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
@@ -142,7 +142,23 @@ enum ril_radio_tech {
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
/* see RIL_REQUEST_DEACTIVATE_DATA_CALL parameter*/
/* 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
/* see RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
#define RIL_DEACTIVATE_DATA_CALL_NO_REASON 0
#define RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN 1
@@ -160,62 +176,75 @@ enum ril_radio_tech {
#define RIL_AUTH_CHAP 2
#define RIL_AUTH_BOTH 3
#define RIL_CARD_MAX_APPS 8
/* SIM card states */
#define RIL_CARDSTATE_ABSENT 0
#define RIL_CARDSTATE_PRESENT 1
#define RIL_CARDSTATE_ERROR 2
enum ril_card_state {
RIL_CARDSTATE_UNKNOWN = -1,
RIL_CARDSTATE_ABSENT = 0,
RIL_CARDSTATE_PRESENT = 1,
RIL_CARDSTATE_ERROR = 2
};
/* SIM personalization substates */
#define RIL_PERSOSUBSTATE_UNKNOWN 0
#define RIL_PERSOSUBSTATE_IN_PROGRESS 1
#define RIL_PERSOSUBSTATE_READY 2
#define RIL_PERSOSUBSTATE_SIM_NETWORK 3
#define RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET 4
#define RIL_PERSOSUBSTATE_SIM_CORPORATE 5
#define RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER 6
#define RIL_PERSOSUBSTATE_SIM_SIM 7
#define RIL_PERSOSUBSTATE_SIM_NETWORK_PUK 8
#define RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK 9
#define RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK 10
#define RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK 11
#define RIL_PERSOSUBSTATE_SIM_SIM_PUK 12
#define RIL_PERSOSUBSTATE_RUIM_NETWORK1 13
#define RIL_PERSOSUBSTATE_RUIM_NETWORK2 14
#define RIL_PERSOSUBSTATE_RUIM_HRPD 15
#define RIL_PERSOSUBSTATE_RUIM_CORPORATE 16
#define RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER 17
#define RIL_PERSOSUBSTATE_RUIM_RUIM 18
#define RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK 19
#define RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK 20
#define RIL_PERSOSUBSTATE_RUIM_HRPD_PUK 21
#define RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK 22
#define RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK 23
#define RIL_PERSOSUBSTATE_RUIM_RUIM_PUK 24
enum ril_perso_substate {
RIL_PERSOSUBSTATE_UNKNOWN = 0,
RIL_PERSOSUBSTATE_IN_PROGRESS = 1,
RIL_PERSOSUBSTATE_READY = 2,
RIL_PERSOSUBSTATE_SIM_NETWORK = 3,
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4,
RIL_PERSOSUBSTATE_SIM_CORPORATE = 5,
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6,
RIL_PERSOSUBSTATE_SIM_SIM = 7,
RIL_PERSOSUBSTATE_SIM_NETWORK_PUK = 8,
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9,
RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10,
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11,
RIL_PERSOSUBSTATE_SIM_SIM_PUK = 12,
RIL_PERSOSUBSTATE_RUIM_NETWORK1 = 13,
RIL_PERSOSUBSTATE_RUIM_NETWORK2 = 14,
RIL_PERSOSUBSTATE_RUIM_HRPD = 15,
RIL_PERSOSUBSTATE_RUIM_CORPORATE = 16,
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17,
RIL_PERSOSUBSTATE_RUIM_RUIM = 18,
RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19,
RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20,
RIL_PERSOSUBSTATE_RUIM_HRPD_PUK = 21,
RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22,
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23,
RIL_PERSOSUBSTATE_RUIM_RUIM_PUK = 24
};
/* SIM - App states */
#define RIL_APPSTATE_ILLEGAL -1
#define RIL_APPSTATE_UNKNOWN 0
#define RIL_APPSTATE_DETECTED 1
#define RIL_APPSTATE_PIN 2
#define RIL_APPSTATE_PUK 3
#define RIL_APPSTATE_SUBSCRIPTION_PERSO 4
#define RIL_APPSTATE_READY 5
enum ril_app_state {
RIL_APPSTATE_ILLEGAL = -1,
RIL_APPSTATE_UNKNOWN = 0,
RIL_APPSTATE_DETECTED = 1,
RIL_APPSTATE_PIN = 2,
RIL_APPSTATE_PUK = 3,
RIL_APPSTATE_SUBSCRIPTION_PERSO = 4,
RIL_APPSTATE_READY = 5
};
/* SIM - PIN states */
#define RIL_PINSTATE_UNKNOWN 0
#define RIL_PINSTATE_ENABLED_NOT_VERIFIED 1
#define RIL_PINSTATE_ENABLED_VERIFIED 2
#define RIL_PINSTATE_DISABLED 3
#define RIL_PINSTATE_ENABLED_BLOCKED 4
#define RIL_PINSTATE_ENABLED_PERM_BLOCKED 5
enum ril_pin_state {
RIL_PINSTATE_UNKNOWN = 0,
RIL_PINSTATE_ENABLED_NOT_VERIFIED = 1,
RIL_PINSTATE_ENABLED_VERIFIED = 2,
RIL_PINSTATE_DISABLED = 3,
RIL_PINSTATE_ENABLED_BLOCKED = 4,
RIL_PINSTATE_ENABLED_PERM_BLOCKED = 5
};
/* SIM - App types */
#define RIL_APPTYPE_UNKNOWN 0
#define RIL_APPTYPE_SIM 1
#define RIL_APPTYPE_USIM 2
#define RIL_APPTYPE_RUIM 3
#define RIL_APPTYPE_CSIM 4
#define RIL_APPTYPE_ISIM 5
enum ril_app_type {
RIL_APPTYPE_UNKNOWN = 0,
RIL_APPTYPE_SIM = 1,
RIL_APPTYPE_USIM = 2,
RIL_APPTYPE_RUIM = 3,
RIL_APPTYPE_CSIM = 4,
RIL_APPTYPE_ISIM = 5
};
/* RIL Request Messages */
#define RIL_REQUEST_GET_SIM_STATUS 1
@@ -339,6 +368,8 @@ enum ril_radio_tech {
#define RIL_REQUEST_NV_WRITE_ITEM 119
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
#define RIL_REQUEST_NV_RESET_CONFIG 121
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
#define RIL_REQUEST_ALLOW_DATA 123
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
@@ -406,3 +437,11 @@ enum ril_radio_tech {
#define RIL_FACILITY_LOCK "1"
#endif /*__RIL_CONSTANTS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,313 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_data.h"
#include "ril_log.h"
#include <grilio_queue.h>
#include <grilio_request.h>
typedef GObjectClass RilDataClass;
typedef struct ril_data RilData;
struct ril_data_manager {
gint ref_count;
struct ril_data *selected;
guint pending_id;
GSList *data_list;
};
struct ril_data {
GObject object;
GRilIoQueue *q;
const char *log_prefix;
char *custom_log_prefix;
struct ril_data_manager *dm;
gboolean allowed;
};
enum ril_data_signal {
SIGNAL_ALLOW_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_ALLOW_CHANGED_NAME "ril-data-allow-changed"
static guint ril_data_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilData, ril_data, G_TYPE_OBJECT)
#define RIL_DATA_TYPE (ril_data_get_type())
#define RIL_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, RIL_DATA_TYPE,RilData))
static void ril_data_manager_check(struct ril_data_manager *self);
/*==========================================================================*
* ril_data
*==========================================================================*/
gulong ril_data_add_allow_changed_handler(struct ril_data *self,
ril_data_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_ALLOW_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_data_remove_handler(struct ril_data *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
struct ril_data *ril_data_new(struct ril_data_manager *dm, GRilIoChannel *io)
{
GASSERT(dm);
if (G_LIKELY(dm)) {
struct ril_data *self = g_object_new(RIL_DATA_TYPE, NULL);
self->q = grilio_queue_new(io);
self->dm = ril_data_manager_ref(dm);
dm->data_list = g_slist_append(dm->data_list, self);
return self;
}
return NULL;
}
struct ril_data *ril_data_ref(struct ril_data *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_DATA(self));
return self;
} else {
return NULL;
}
}
void ril_data_unref(struct ril_data *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_DATA(self));
}
}
G_INLINE_FUNC void ril_data_signal(struct ril_data *self)
{
g_signal_emit(self, ril_data_signals[SIGNAL_ALLOW_CHANGED], 0);
}
void ril_data_allow(struct ril_data *self, gboolean allow)
{
if (G_LIKELY(self)) {
struct ril_data_manager *dm = self->dm;
DBG("%s%s", self->log_prefix, allow ? "yes" : "no");
if (allow) {
if (!self->allowed) {
self->allowed = TRUE;
ril_data_manager_check(dm);
}
} else {
if (self->allowed) {
self->allowed = FALSE;
if (dm->selected == self) {
ril_data_manager_check(dm);
}
}
}
}
}
gboolean ril_data_allowed(struct ril_data *self)
{
return G_LIKELY(self) && self->allowed && self->dm->selected == self;
}
void ril_data_set_name(struct ril_data *self, const char *name)
{
if (G_LIKELY(self)) {
g_free(self->custom_log_prefix);
if (name) {
self->custom_log_prefix = g_strconcat(name, " ", NULL);
self->log_prefix = self->custom_log_prefix;
} else {
self->custom_log_prefix = NULL;
self->log_prefix = "";
}
}
}
static void ril_data_init(struct ril_data *self)
{
self->log_prefix = "";
}
static void ril_data_dispose(GObject *object)
{
struct ril_data *self = RIL_DATA(object);
struct ril_data_manager *dm = self->dm;
dm->data_list = g_slist_remove(dm->data_list, self);
grilio_queue_cancel_all(self->q, FALSE);
ril_data_manager_check(dm);
G_OBJECT_CLASS(ril_data_parent_class)->dispose(object);
}
static void ril_data_finalize(GObject *object)
{
struct ril_data *self = RIL_DATA(object);
g_free(self->custom_log_prefix);
grilio_queue_unref(self->q);
ril_data_manager_unref(self->dm);
G_OBJECT_CLASS(ril_data_parent_class)->finalize(object);
}
static void ril_data_class_init(RilDataClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_data_dispose;
object_class->finalize = ril_data_finalize;
ril_data_signals[SIGNAL_ALLOW_CHANGED] =
g_signal_new(SIGNAL_ALLOW_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*==========================================================================*
* ril_data_manager
*==========================================================================*/
struct ril_data_manager *ril_data_manager_new()
{
struct ril_data_manager *self = g_new0(struct ril_data_manager, 1);
self->ref_count = 1;
return self;
}
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *self)
{
if (self) {
GASSERT(self->ref_count > 0);
g_atomic_int_inc(&self->ref_count);
}
return self;
}
void ril_data_manager_unref(struct ril_data_manager *self)
{
if (self) {
GASSERT(self->ref_count > 0);
if (g_atomic_int_dec_and_test(&self->ref_count)) {
GASSERT(!self->selected);
g_free(self);
}
}
}
static void ril_data_manager_allow_data_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_data_manager *self = user_data;
GASSERT(self->selected);
GASSERT(self->pending_id);
self->pending_id = 0;
if (ril_status == RIL_E_SUCCESS) {
DBG("%sselected", self->selected->log_prefix);
} else {
DBG("%srequest failed", self->selected->log_prefix);
}
}
static struct ril_data *ril_data_manager_pick(struct ril_data_manager *self)
{
GSList *list = self->data_list;
while (list) {
struct ril_data *data = list->data;
if (data->allowed) {
return data;
}
list = list->next;
}
return NULL;
}
static GRilIoRequest *ril_data_allow_req(gboolean allow)
{
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, allow != FALSE);
return req;
}
static void ril_data_manager_check(struct ril_data_manager *self)
{
struct ril_data *data = ril_data_manager_pick(self);
if (data) {
if (self->selected != data) {
GRilIoRequest *req = ril_data_allow_req(TRUE);
struct ril_data *prev = self->selected;
/* Cancel pending request, if any */
GASSERT(prev || !self->pending_id);
if (prev) {
grilio_queue_cancel_request(prev->q,
self->pending_id, FALSE);
}
/*
* Submit the RIL request. Note that with
* some older RILs this request will never
* get completed (no reply from rild will
* ever come).
*/
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
self->pending_id =
grilio_queue_send_request_full(data->q, req,
RIL_REQUEST_ALLOW_DATA,
ril_data_manager_allow_data_cb,
NULL, self);
grilio_request_unref(req);
DBG("%srequested", data->log_prefix);
self->selected = data;
if (prev) {
ril_data_signal(prev);
}
ril_data_signal(data);
}
} else {
if (self->selected) {
struct ril_data *prev = self->selected;
if (self->pending_id) {
grilio_queue_cancel_request(prev->q,
self->pending_id, FALSE);
self->pending_id = 0;
}
self->selected = NULL;
ril_data_signal(prev);
}
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,46 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_DATA_H
#define RIL_DATA_H
#include "ril_types.h"
struct ril_data_manager;
struct ril_data_manager *ril_data_manager_new(void);
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
void ril_data_manager_unref(struct ril_data_manager *dm);
struct ril_data *ril_data_new(struct ril_data_manager *dm, GRilIoChannel *io);
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
void ril_data_set_name(struct ril_data *data, const char *name);
void ril_data_allow(struct ril_data *data, gboolean allow);
gboolean ril_data_allowed(struct ril_data *data);
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
ril_data_cb_t cb, void *arg);
void ril_data_remove_handler(struct ril_data *data, gulong id);
#endif /* RIL_DATA_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,7 +14,6 @@
*/
#include "ril_plugin.h"
#include "ril_constants.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -26,15 +25,18 @@
struct ril_devinfo {
struct ofono_devinfo *info;
GRilIoQueue *q;
guint timer_id;
guint register_id;
guint imei_id;
char *imei;
};
struct ril_devinfo_req {
struct ril_devinfo_cbd {
struct ril_devinfo *di;
ofono_devinfo_query_cb_t cb;
gpointer data;
};
#define ril_devinfo_req_free g_free
#define ril_devinfo_cbd_free g_free
static inline struct ril_devinfo *ril_devinfo_get_data(
struct ofono_devinfo *info)
@@ -42,11 +44,12 @@ static inline struct ril_devinfo *ril_devinfo_get_data(
return ofono_devinfo_get_data(info);
}
struct ril_devinfo_req *ril_devinfo_req_new(ofono_devinfo_query_cb_t cb,
void *data)
struct ril_devinfo_cbd *ril_devinfo_cbd_new(struct ril_devinfo *di,
ofono_devinfo_query_cb_t cb, void *data)
{
struct ril_devinfo_req *cbd = g_new0(struct ril_devinfo_req, 1);
struct ril_devinfo_cbd *cbd = g_new0(struct ril_devinfo_cbd, 1);
cbd->di = di;
cbd->cb = cb;
cbd->data = data;
return cbd;
@@ -63,10 +66,10 @@ static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_devinfo_req *cbd = user_data;
struct ril_devinfo_cbd *cbd = user_data;
if (status == RIL_E_SUCCESS) {
gchar *res;
char *res;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
res = grilio_parser_get_utf8(&rilp);
@@ -78,37 +81,47 @@ static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
}
}
static void ril_devinfo_query(struct ofono_devinfo *info, guint cmd,
static void ril_devinfo_query_revision(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb, void *data)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
/* See comment in ril_devinfo_remove */
if (di->q) {
grilio_queue_send_request_full(di->q, NULL, cmd,
ril_devinfo_query_cb, ril_devinfo_req_free,
ril_devinfo_req_new(cb, data));
} else {
struct ofono_error error;
cb(ril_error_failure(&error), NULL, data);
}
DBG("");
grilio_queue_send_request_full(di->q, NULL, RIL_REQUEST_BASEBAND_VERSION,
ril_devinfo_query_cb, ril_devinfo_cbd_free,
ril_devinfo_cbd_new(di, cb, data));
}
static void ril_devinfo_query_revision(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb, void *data)
static gboolean ril_devinfo_query_serial_cb(void *user_data)
{
DBG("");
ril_devinfo_query(info, RIL_REQUEST_BASEBAND_VERSION, cb, data);
struct ril_devinfo_cbd *cbd = user_data;
struct ril_devinfo *di = cbd->di;
struct ofono_error error;
GASSERT(di->imei_id);
di->imei_id = 0;
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
return FALSE;
}
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb,
void *data)
{
/* TODO: make it support both RIL_REQUEST_GET_IMEI (deprecated) and
* RIL_REQUEST_DEVICE_IDENTITY depending on the rild version used */
DBG("");
ril_devinfo_query(info, RIL_REQUEST_GET_IMEI, cb, data);
struct ril_devinfo *di = ril_devinfo_get_data(info);
GASSERT(!di->imei_id);
if (di->imei_id) {
g_source_remove(di->imei_id);
di->imei_id = 0;
}
DBG("%s", di->imei);
di->imei_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_devinfo_query_serial_cb,
ril_devinfo_cbd_new(di, cb, data),
ril_devinfo_cbd_free);
}
static gboolean ril_devinfo_register(gpointer user_data)
@@ -116,7 +129,7 @@ static gboolean ril_devinfo_register(gpointer user_data)
struct ril_devinfo *di = user_data;
DBG("");
di->timer_id = 0;
di->register_id = 0;
ofono_devinfo_register(di->info);
/* This makes the timeout a single-shot */
@@ -129,11 +142,13 @@ static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
struct ril_modem *modem = data;
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
DBG("");
DBG("%s %s %p", ril_modem_get_path(modem), modem->imei, di);
GASSERT(modem->imei);
di->q = grilio_queue_new(ril_modem_io(modem));
di->info = info;
di->imei = g_strdup(modem->imei);
di->timer_id = g_idle_add(ril_devinfo_register, di);
di->register_id = g_idle_add(ril_devinfo_register, di);
ofono_devinfo_set_data(info, di);
return 0;
}
@@ -142,15 +157,20 @@ static void ril_devinfo_remove(struct ofono_devinfo *info)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG("");
DBG("%p", di);
ofono_devinfo_set_data(info, NULL);
if (di->timer_id > 0) {
g_source_remove(di->timer_id);
if (di->register_id > 0) {
g_source_remove(di->register_id);
}
if (di->imei_id > 0) {
g_source_remove(di->imei_id);
}
grilio_queue_cancel_all(di->q, FALSE);
grilio_queue_unref(di->q);
g_free(di->imei);
g_free(di);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,7 +14,8 @@
*/
#include "ril_plugin.h"
#include "ril_constants.h"
#include "ril_network.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -40,85 +41,96 @@
struct ril_gprs {
struct ofono_gprs *gprs;
struct ril_modem *md;
struct ril_data *data;
struct ril_network *network;
GRilIoChannel *io;
GRilIoQueue *q;
gboolean ofono_attached;
gboolean ofono_registered;
gboolean attached;
int max_cids;
int last_status;
int ril_data_tech;
gulong event_id;
guint poll_id;
guint timer_id;
enum network_registration_status registration_status;
guint register_id;
gulong network_event_id;
gulong data_event_id;
guint set_attached_id;
};
struct ril_gprs_cbd {
struct ril_gprs *gd;
union _ofono_gprs_cb {
ofono_gprs_status_cb_t status;
ofono_gprs_cb_t cb;
gpointer ptr;
} cb;
ofono_gprs_cb_t cb;
gpointer data;
};
#define ril_gprs_cbd_free g_free
static void ril_gprs_poll_data_reg_state_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data);
static inline struct ril_gprs *ril_gprs_get_data(struct ofono_gprs *b)
static struct ril_gprs *ril_gprs_get_data(struct ofono_gprs *ofono)
{
return ofono_gprs_get_data(b);
return ofono ? ofono_gprs_get_data(ofono) : NULL;
}
static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd, void *cb,
void *data)
static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd,
ofono_gprs_cb_t cb, void *data)
{
struct ril_gprs_cbd *cbd = g_new0(struct ril_gprs_cbd, 1);
cbd->gd = gd;
cbd->cb.ptr = cb;
cbd->cb = cb;
cbd->data = data;
return cbd;
}
int ril_gprs_ril_data_tech(struct ofono_gprs *gprs)
static enum network_registration_status ril_gprs_fix_registration_status(
struct ril_gprs *gd, enum network_registration_status status)
{
struct ril_gprs *gd = ril_gprs_get_data(gprs);
return gd ? gd->ril_data_tech : -1;
}
static void ril_gprs_poll_data_reg_state(struct ril_gprs *gd)
{
if (!gd->poll_id) {
DBG("");
gd->poll_id = grilio_queue_send_request_full(gd->q, NULL,
RIL_REQUEST_DATA_REGISTRATION_STATE,
ril_gprs_poll_data_reg_state_cb, NULL, gd);
if (!ril_data_allowed(gd->data)) {
return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
} else {
/* TODO: need a way to make sure that SPDI information has
* already been read from the SIM (i.e. sim_spdi_read_cb in
* network.c has been called) */
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gd->md);
return ril_netreg_check_if_really_roaming(netreg, status);
}
}
static void ril_gprs_state_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
static void ril_gprs_data_update_registration_state(struct ril_gprs *gd)
{
struct ril_gprs *gd = user_data;
const enum network_registration_status status =
ril_gprs_fix_registration_status(gd, gd->network->data.status);
DBG("%s", ril_modem_get_path(gd->md));
ril_gprs_poll_data_reg_state(gd);
if (gd->registration_status != status) {
ofono_info("data reg changed %d -> %d (%s), attached %d",
gd->registration_status, status,
registration_status_to_string(status),
gd->attached);
gd->registration_status = status;
ofono_gprs_status_notify(gd->gprs, gd->registration_status);
}
}
static gboolean ril_gprs_set_attached_callback(gpointer user_data)
static void ril_gprs_check_data_allowed(struct ril_gprs *gd)
{
DBG("%s %d %d", ril_modem_get_path(gd->md), ril_data_allowed(gd->data),
gd->attached);
if (!ril_data_allowed(gd->data) && gd->attached) {
gd->attached = FALSE;
if (gd->gprs) {
ofono_gprs_detached_notify(gd->gprs);
}
}
ril_gprs_data_update_registration_state(gd);
}
static gboolean ril_gprs_set_attached_cb(gpointer user_data)
{
struct ofono_error error;
struct ril_gprs_cbd *cbd = user_data;
struct ril_gprs *gd = cbd->gd;
DBG("%s", ril_modem_get_path(cbd->gd->md));
cbd->gd->timer_id = 0;
cbd->cb.cb(ril_error_ok(&error), cbd->data);
ril_gprs_cbd_free(cbd);
/* Single shot */
GASSERT(gd->set_attached_id);
gd->set_attached_id = 0;
ril_gprs_check_data_allowed(gd);
cbd->cb(ril_error_ok(&error), cbd->data);
return FALSE;
}
@@ -127,209 +139,84 @@ static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
{
struct ril_gprs *gd = ril_gprs_get_data(gprs);
DBG("%s attached: %d", ril_modem_get_path(gd->md), attached);
/*
* As RIL offers no actual control over the GPRS 'attached'
* state, we save the desired state, and use it to override
* the actual modem's state in the 'attached_status' function.
* This is similar to the way the core ofono gprs code handles
* data roaming ( see src/gprs.c gprs_netreg_update().
*
* The core gprs code calls driver->set_attached() when a netreg
* notification is received and any configured roaming conditions
* are met.
*/
gd->ofono_attached = attached;
/*
* However we cannot respond immediately, since core sets the
* value of driver_attached after calling set_attached and that
* leads to comparison failure in gprs_attached_update in
* connection drop phase
*/
gd->timer_id = g_idle_add(ril_gprs_set_attached_callback,
ril_gprs_cbd_new(gd, cb, data));
}
static int ril_gprs_parse_data_reg_state(struct ril_gprs *gd,
const void *data, guint len)
{
struct ofono_gprs *gprs = gd->gprs;
struct ril_reg_data reg;
if (!ril_util_parse_reg(data, len, &reg)) {
ofono_error("Failure parsing data registration response.");
gd->ril_data_tech = -1;
return NETWORK_REGISTRATION_STATUS_UNKNOWN;
if (ril_data_allowed(gd->data) || !attached) {
DBG("%s attached: %d", ril_modem_get_path(gd->md), attached);
if (gd->set_attached_id) {
g_source_remove(gd->set_attached_id);
}
gd->attached = attached;
gd->set_attached_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_gprs_set_attached_cb,
ril_gprs_cbd_new(gd, cb, data),
ril_gprs_cbd_free);
} else {
const int rawstatus = reg.status;
if (gd->ril_data_tech != reg.ril_tech) {
gd->ril_data_tech = reg.ril_tech;
DBG("ril data tech %d", reg.ril_tech);
}
if (!gd->ofono_registered) {
ofono_gprs_register(gprs);
gd->ofono_registered = TRUE;
}
if (reg.max_calls > gd->max_cids) {
DBG("Setting max cids to %d", reg.max_calls);
gd->max_cids = reg.max_calls;
ofono_gprs_set_cid_range(gprs, 1, reg.max_calls);
}
if (reg.status == NETWORK_REGISTRATION_STATUS_ROAMING) {
reg.status = ril_netreg_check_if_really_roaming(
ril_modem_ofono_netreg(gd->md), reg.status);
}
if (rawstatus != reg.status) {
ofono_info("data registration modified %d => %d",
rawstatus, reg.status);
}
return reg.status;
struct ofono_error error;
DBG("%s not allowed to attach", ril_modem_get_path(gd->md));
cb(ril_error_failure(&error), data);
}
}
static void ril_gprs_registration_status_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_gprs_cbd *cbd = user_data;
ofono_gprs_status_cb_t cb = cbd->cb.status;
struct ril_gprs *gd = cbd->gd;
struct ofono_gprs *gprs = gd->gprs;
struct ofono_error error;
int status = -1;
DBG("%s", ril_modem_get_path(gd->md));
if (gd && ril_status == RIL_E_SUCCESS) {
ril_error_init_ok(&error);
} else {
ofono_error("ril_gprs_data_reg_cb: reply failure: %s",
ril_error_to_string(ril_status));
ril_error_init_failure(&error);
goto cb_out;
}
status = ril_gprs_parse_data_reg_state(gd, data, len);
if (status == NETWORK_REGISTRATION_STATUS_UNKNOWN) {
ril_error_init_failure(&error);
goto cb_out;
}
/* Let's minimize logging */
if (status != gd->last_status) {
ofono_info("data reg changes %d (%d), attached %d",
status, gd->last_status, gd->ofono_attached);
}
/* Must be attached if registered or roaming */
if (gd->last_status != NETWORK_REGISTRATION_STATUS_REGISTERED &&
gd->last_status != NETWORK_REGISTRATION_STATUS_ROAMING) {
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED) {
gd->ofono_attached = TRUE;
} else if ((status == NETWORK_REGISTRATION_STATUS_ROAMING) &&
ofono_gprs_get_roaming_allowed(gd->gprs)) {
gd->ofono_attached = TRUE;
}
}
if (!ofono_modem_get_online(ofono_gprs_get_modem(gprs)))
gd->ofono_attached = FALSE;
/* if unsolicitated and no state change let's not notify core */
if ((status == gd->last_status) && gd->ofono_attached) {
goto cb_out;
}
if (!gd->ofono_attached) {
if (!cb) {
if (status == NETWORK_REGISTRATION_STATUS_ROAMING) {
if (!ofono_gprs_get_roaming_allowed(gd->gprs)) {
ofono_gprs_detached_notify(gprs);
}
/*
* This prevents core ending
* into eternal loop with driver
*/
ril_error_init_failure(&error);
}
ofono_gprs_status_notify(gprs, status);
} else {
/*
* This prevents core ending
* into eternal loop with driver
*/
ril_error_init_failure(&error);
}
gd->last_status = status;
goto exit;
}
if (!cb) {
ofono_gprs_status_notify(gprs, status);
}
gd->last_status = status;
exit:
DBG("data reg status %d, last status %d, attached %d",
status, gd->last_status, gd->ofono_attached);
cb_out:
if (cb) {
cb(&error, status, cbd->data);
}
}
static void ril_gprs_poll_data_reg_state_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
static void ril_gprs_allow_data_changed(struct ril_data *data, void *user_data)
{
struct ril_gprs *gd = user_data;
int status;
DBG("%s", ril_modem_get_path(gd->md));
GASSERT(gd->poll_id);
gd->poll_id = 0;
GASSERT(gd->data == data);
DBG("%s %d", ril_modem_get_path(gd->md), ril_data_allowed(data));
if (!gd->set_attached_id) {
ril_gprs_check_data_allowed(gd);
}
}
if (ril_status != RIL_E_SUCCESS) {
ofono_error("ril_gprs_data_probe_reg_cb: reply failure: %s",
ril_error_to_string(ril_status));
status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
} else {
status = ril_gprs_parse_data_reg_state(gd, data, len);
ofono_info("data reg status probed %d", status);
static void ril_gprs_data_registration_state_changed(struct ril_network *net,
void *user_data)
{
struct ril_gprs *gd = user_data;
const struct ril_registration_state *data = &net->data;
GASSERT(gd->network == net);
if (data->max_calls > gd->max_cids) {
DBG("Setting max cids to %d", data->max_calls);
gd->max_cids = data->max_calls;
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
}
if (status != gd->last_status) {
ofono_info("data reg changes %d (%d), attached %d",
status, gd->last_status, gd->ofono_attached);
gd->last_status = status;
if (gd->ofono_attached) {
ofono_gprs_status_notify(gd->gprs, status);
}
}
ril_gprs_data_update_registration_state(gd);
}
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
ofono_gprs_status_cb_t cb, void *data)
{
struct ril_gprs *gd = ril_gprs_get_data(gprs);
struct ofono_error error;
const enum network_registration_status status = gd->attached ?
gd->registration_status :
NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
DBG("");
if (gd) {
grilio_queue_send_request_full(gd->q, NULL,
RIL_REQUEST_DATA_REGISTRATION_STATE,
ril_gprs_registration_status_cb, ril_gprs_cbd_free,
ril_gprs_cbd_new(gd, cb, data));
DBG("%d (%s)", status, registration_status_to_string(status));
cb(ril_error_ok(&error), status, data);
}
static gboolean ril_gprs_register(gpointer user_data)
{
struct ril_gprs *gd = user_data;
gd->register_id = 0;
gd->network_event_id = ril_network_add_data_state_changed_handler(
gd->network, ril_gprs_data_registration_state_changed, gd);
gd->data_event_id = ril_data_add_allow_changed_handler(gd->data,
ril_gprs_allow_data_changed, gd);
gd->registration_status = ril_gprs_fix_registration_status(gd,
gd->network->data.status);
gd->max_cids = gd->network->data.max_calls;
if (gd->max_cids > 0) {
DBG("Setting max cids to %d", gd->max_cids);
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
}
ofono_gprs_register(gd->gprs);
return FALSE;
}
static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
@@ -342,15 +229,13 @@ static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
gd->md = modem;
gd->io = grilio_channel_ref(ril_modem_io(modem));
gd->q = grilio_queue_new(gd->io);
gd->last_status = -1;
gd->ril_data_tech = -1;
gd->data = ril_data_ref(modem->data);
gd->network = ril_network_ref(modem->network);
gd->gprs = gprs;
ofono_gprs_set_data(gprs, gd);
ril_gprs_poll_data_reg_state(gd);
gd->event_id = grilio_channel_add_unsol_event_handler(gd->io,
ril_gprs_state_changed,
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, gd);
/* ofono crashes if we register right away */
gd->register_id = g_idle_add(ril_gprs_register, gd);
return 0;
}
@@ -361,11 +246,20 @@ static void ril_gprs_remove(struct ofono_gprs *gprs)
DBG("%s", ril_modem_get_path(gd->md));
ofono_gprs_set_data(gprs, NULL);
if (gd->timer_id > 0) {
g_source_remove(gd->timer_id);
}
if (gd->set_attached_id) {
g_source_remove(gd->set_attached_id);
}
if (gd->register_id) {
g_source_remove(gd->register_id);
}
ril_network_remove_handler(gd->network, gd->network_event_id);
ril_network_unref(gd->network);
ril_data_remove_handler(gd->data, gd->data_event_id);
ril_data_unref(gd->data);
grilio_channel_remove_handler(gd->io, gd->event_id);
grilio_channel_unref(gd->io);
grilio_queue_cancel_all(gd->q, FALSE);
grilio_queue_unref(gd->q);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,7 +14,7 @@
*/
#include "ril_plugin.h"
#include "ril_constants.h"
#include "ril_network.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -55,6 +55,7 @@ enum ril_gprs_context_state {
struct ril_gprs_context {
struct ofono_gprs_context *gc;
struct ril_modem *modem;
struct ril_network *network;
GRilIoChannel *io;
GRilIoQueue *q;
guint active_ctx_cid;
@@ -760,7 +761,7 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
*
* Makes little sense but it is what it is.
*/
tech = ril_gprs_ril_data_tech(gprs);
tech = gcd->network->data.ril_tech;
if (tech > 2) {
tech += 2;
} else {
@@ -918,6 +919,7 @@ static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
DBG("");
gcd->gc = gc;
gcd->modem = modem;
gcd->network = ril_network_ref(modem->network);
gcd->io = grilio_channel_ref(ril_modem_io(modem));
gcd->q = grilio_queue_new(gcd->io);
gcd->regid = grilio_channel_add_unsol_event_handler(gcd->io,
@@ -943,6 +945,7 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
gcd->deactivate_req->cbd.gcd = NULL;
}
ril_network_unref(gcd->network);
grilio_channel_remove_handler(gcd->io, gcd->regid);
grilio_channel_unref(gcd->io);
grilio_queue_cancel_all(gcd->q, FALSE);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,13 +14,17 @@
*/
#include "ril_plugin.h"
#include "ril_constants.h"
#include "ril_network.h"
#include "ril_radio.h"
#include "ril_sim_card.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ofono.h"
#define MAX_PDP_CONTEXTS (2)
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
enum ril_modem_power_state {
POWERED_OFF,
@@ -37,19 +41,22 @@ enum ril_modem_online_state {
struct ril_modem_online_request {
ofono_modem_online_cb_t cb;
struct ril_modem_data *md;
void *data;
guint id;
guint timeout_id;
};
struct ril_modem {
GRilIoChannel *io;
struct ril_modem_data {
struct ril_modem modem;
GRilIoQueue *q;
struct ofono_modem *modem;
struct ofono_radio_settings *radio_settings;
struct ril_modem_config config;
char *default_name;
char *imei;
gboolean pre_sim_done;
gboolean devinfo_created;
gboolean allow_data;
enum ril_radio_state radio_state;
guint online_check_id;
enum ril_modem_power_state power_state;
gulong radio_state_event_id;
@@ -60,83 +67,92 @@ struct ril_modem {
struct ril_modem_online_request set_offline;
};
static guint ril_modem_request_power(struct ril_modem *md, gboolean on,
GRilIoChannelResponseFunc cb);
#define RADIO_POWER_TAG(md) (md)
static inline struct ril_modem *ril_modem_from_ofono(struct ofono_modem *modem)
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
{
return ofono_modem_get_data(modem);
struct ril_modem_data *md = ofono_modem_get_data(o);
GASSERT(md->modem.ofono == o);
return md;
}
GRilIoChannel *ril_modem_io(struct ril_modem *md)
static struct ril_modem_data *ril_modem_data_from_modem(struct ril_modem *m)
{
return md ? md->io : NULL;
return m ? G_CAST(m, struct ril_modem_data, modem) : NULL;
}
const struct ril_modem_config *ril_modem_config(struct ril_modem *md)
static void *ril_modem_get_atom_data(struct ril_modem *modem,
enum ofono_atom_type type)
{
return md ? &md->config : NULL;
if (modem && modem->ofono) {
struct ofono_atom *atom =
__ofono_modem_find_atom(modem->ofono, type);
if (atom) {
return __ofono_atom_get_data(atom);
}
}
return NULL;
}
struct ofono_modem *ril_modem_ofono_modem(struct ril_modem *md)
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem)
{
return md ? md->modem : NULL;
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_SIM);
}
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *md)
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem)
{
return (md && md->modem) ?
__ofono_atom_find(OFONO_ATOM_TYPE_SIM, md->modem) :
NULL;
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_GPRS);
}
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *md)
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
{
return (md && md->modem) ?
__ofono_atom_find(OFONO_ATOM_TYPE_GPRS, md->modem) :
NULL;
}
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *md)
{
return (md && md->modem) ?
__ofono_atom_find(OFONO_ATOM_TYPE_NETREG, md->modem) :
NULL;
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
}
void ril_modem_delete(struct ril_modem *md)
{
if (md && md->modem) {
ofono_modem_remove(md->modem);
if (md && md->ofono) {
ofono_modem_remove(md->ofono);
}
}
void ril_modem_set_removed_cb(struct ril_modem *md, ril_modem_cb_t cb,
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
void *data)
{
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
md->removed_cb = cb;
md->removed_cb_data = data;
}
void ril_modem_allow_data(struct ril_modem *md)
static void ril_modem_check_devinfo(struct ril_modem_data *md)
{
if (md && md->modem) {
GRilIoRequest *req = grilio_request_sized_new(8);
DBG("%s", ofono_modem_get_path(md->modem));
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, TRUE);
grilio_queue_send_request(md->q, req, RIL_REQUEST_ALLOW_DATA);
grilio_request_unref(req);
/* devinfo driver assumes that IMEI is known */
if (md->imei && md->pre_sim_done && !md->devinfo_created &&
md->modem.ofono) {
md->devinfo_created = TRUE;
ofono_devinfo_create(md->modem.ofono, 0, RILMODEM_DRIVER, md);
}
}
static void ril_modem_online_request_ok(GRilIoChannel* io,
struct ril_modem_online_request *req)
void ril_modem_set_imei(struct ril_modem *modem, const char *imei)
{
if (req->id) {
grilio_channel_cancel_request(io, req->id, FALSE);
req->id = 0;
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
if (md) {
g_free(md->imei);
modem->imei = md->imei = g_strdup(imei);
ril_modem_check_devinfo(md);
}
}
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
{
if (req->timeout_id) {
g_source_remove(req->timeout_id);
req->timeout_id = 0;
}
if (req->cb) {
@@ -150,121 +166,124 @@ static void ril_modem_online_request_ok(GRilIoChannel* io,
}
}
static void ril_modem_update_online_state(struct ril_modem *md)
static void ril_modem_update_online_state(struct ril_modem_data *md)
{
switch (md->radio_state) {
switch (md->modem.radio->state) {
case RADIO_STATE_ON:
ril_modem_online_request_ok(md->io, &md->set_online);
DBG("online");
ril_modem_online_request_ok(&md->set_online);
break;
case RADIO_STATE_OFF:
case RADIO_STATE_UNAVAILABLE:
ril_modem_online_request_ok(md->io, &md->set_offline);
DBG("offline");
ril_modem_online_request_ok(&md->set_offline);
break;
default:
break;
}
if (!md->set_offline.id && !md->set_online.id &&
if (!md->set_offline.timeout_id && !md->set_online.timeout_id &&
md->power_state == POWERING_OFF) {
md->power_state = POWERED_OFF;
ofono_modem_set_powered(md->modem, FALSE);
if (md->modem.ofono) {
ofono_modem_set_powered(md->modem.ofono, FALSE);
}
}
}
static void ril_modem_online_request_done(struct ril_modem *md,
struct ril_modem_online_request *req, int ril_status)
static gboolean ril_modem_online_request_timeout(gpointer data)
{
GASSERT(req->id);
GASSERT(req->cb);
GASSERT(req->data);
req->id = 0;
struct ril_modem_online_request *req = data;
struct ofono_error error;
ofono_modem_online_cb_t cb = req->cb;
void *cb_data = req->data;
/* If this request has completed successfully, we will
* invoke the callback and notify ofono core when we get
* RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, i.e. the power
* state has actually changed */
if (ril_status != RIL_E_SUCCESS) {
struct ofono_error error;
ofono_modem_online_cb_t cb = req->cb;
void *data = req->data;
GASSERT(req->timeout_id);
GASSERT(cb);
req->cb = NULL;
req->data = NULL;
cb(ril_error_failure(&error), data);
}
req->timeout_id = 0;
req->cb = NULL;
req->data = NULL;
cb(ril_error_failure(&error), cb_data);
ril_modem_update_online_state(req->md);
return FALSE;
}
static gboolean ril_modem_online_check(gpointer data)
{
struct ril_modem_data *md = data;
GASSERT(md->online_check_id);
md->online_check_id = 0;
ril_modem_update_online_state(md);
return FALSE;
}
static void ril_modem_set_online_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
static void ril_modem_schedule_online_check(struct ril_modem_data *md)
{
struct ril_modem *md = user_data;
DBG("Power on status %s", ril_error_to_string(status));
ril_modem_online_request_done(md, &md->set_online, status);
}
static void ril_modem_set_offline_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_modem *md = user_data;
DBG("Power on status %s", ril_error_to_string(status));
ril_modem_online_request_done(md, &md->set_offline, status);
}
static GRilIoRequest *ril_modem_request_radio_power(gboolean on)
{
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, on); /* Radio ON=1, OFF=0 */
return req;
}
static guint ril_modem_request_power(struct ril_modem *md, gboolean on,
GRilIoChannelResponseFunc cb)
{
guint id = 0;
if (md->q) {
GRilIoRequest *req = ril_modem_request_radio_power(on);
DBG("[%u] %s", md->config.slot, on ? "ON" : "OFF");
id = grilio_queue_send_request_full(md->q, req,
RIL_REQUEST_RADIO_POWER, cb, NULL, md);
grilio_request_unref(req);
if (!md->online_check_id) {
md->online_check_id = g_idle_add(ril_modem_online_check, md);
}
return id;
}
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);
}
} else if (md->radio_settings) {
DBG("Removing radio settings interface");
ofono_radio_settings_remove(md->radio_settings);
md->radio_settings = NULL;
}
}
static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
{
struct ril_modem_data *md = data;
GASSERT(md->modem.radio == radio);
ril_modem_update_radio_settings(md);
ril_modem_update_online_state(md);
};
static void ril_modem_pre_sim(struct ofono_modem *modem)
{
struct ril_modem *md = ril_modem_from_ofono(modem);
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("");
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
DBG("%s", ofono_modem_get_path(modem));
md->pre_sim_done = TRUE;
ril_modem_check_devinfo(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,
ril_modem_radio_state_cb, md);
}
}
static void ril_modem_post_sim(struct ofono_modem *modem)
{
struct ril_modem *md = ril_modem_from_ofono(modem);
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
struct ofono_gprs *gprs;
struct ofono_gprs_context *gc;
int i;
DBG("");
DBG("%s", ofono_modem_get_path(modem));
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
if (gprs) {
int i;
for (i = 0; i < MAX_PDP_CONTEXTS; i++) {
gc = ofono_gprs_context_create(modem, 0,
struct ofono_gprs_context *gc =
ofono_gprs_context_create(modem, 0,
RILMODEM_DRIVER, md);
if (gc == NULL)
break;
@@ -282,9 +301,9 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
static void ril_modem_post_online(struct ofono_modem *modem)
{
struct ril_modem *md = ril_modem_from_ofono(modem);
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("");
DBG("%s", ofono_modem_get_path(modem));
ofono_call_volume_create(modem, 0, RILMODEM_DRIVER, md);
ofono_netreg_create(modem, 0, RILMODEM_DRIVER, md);
ofono_ussd_create(modem, 0, RILMODEM_DRIVER, md);
@@ -295,36 +314,33 @@ static void ril_modem_post_online(struct ofono_modem *modem)
static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
ofono_modem_online_cb_t cb, void *data)
{
struct ril_modem *md = ril_modem_from_ofono(modem);
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
struct ril_modem_online_request *req;
DBG("%s going %sline", ofono_modem_get_path(modem),
online ? "on" : "off");
if (online) {
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
req = &md->set_online;
GASSERT(!req->id);
req->id = ril_modem_request_power(md, TRUE,
ril_modem_set_online_cb);
} else {
ril_radio_power_off(md->modem.radio, RADIO_POWER_TAG(md));
req = &md->set_offline;
GASSERT(!req->id);
req->id = ril_modem_request_power(md, FALSE,
ril_modem_set_offline_cb);
}
if (req->id) {
req->cb = cb;
req->data = data;
} else {
struct ofono_error error;
cb(ril_error_failure(&error), data);
req->cb = cb;
req->data = data;
if (req->timeout_id) {
g_source_remove(req->timeout_id);
}
req->timeout_id = g_timeout_add_seconds(ONLINE_TIMEOUT_SECS,
ril_modem_online_request_timeout, req);
ril_modem_schedule_online_check(md);
}
static int ril_modem_enable(struct ofono_modem *modem)
{
struct ril_modem *md = ril_modem_from_ofono(modem);
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("%s", ofono_modem_get_path(modem));
md->power_state = POWERED_ON;
@@ -333,10 +349,10 @@ static int ril_modem_enable(struct ofono_modem *modem)
static int ril_modem_disable(struct ofono_modem *modem)
{
struct ril_modem *md = ril_modem_from_ofono(modem);
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("%s", ofono_modem_get_path(modem));
if (md->set_online.id || md->set_offline.id) {
if (md->set_online.timeout_id || md->set_offline.timeout_id) {
md->power_state = POWERING_OFF;
return -EINPROGRESS;
} else {
@@ -351,108 +367,99 @@ static int ril_modem_probe(struct ofono_modem *modem)
return 0;
}
static void ril_modem_remove(struct ofono_modem *modem)
static void ril_modem_remove(struct ofono_modem *ofono)
{
struct ril_modem *md = ril_modem_from_ofono(modem);
DBG("%s", ofono_modem_get_path(modem));
GASSERT(md->modem);
if (md->radio_state > RADIO_STATE_UNAVAILABLE) {
GRilIoRequest *req = ril_modem_request_radio_power(FALSE);
grilio_channel_send_request(md->io, req,
RIL_REQUEST_RADIO_POWER);
grilio_request_unref(req);
}
struct ril_modem_data *md = ril_modem_data_from_ofono(ofono);
struct ril_modem *modem = &md->modem;
DBG("%s", ril_modem_get_path(modem));
if (md->removed_cb) {
ril_modem_cb_t cb = md->removed_cb;
void *data = md->removed_cb_data;
md->removed_cb = NULL;
md->removed_cb_data = NULL;
cb(md, data);
cb(modem, data);
}
ofono_modem_set_data(modem, NULL);
ofono_modem_set_data(ofono, NULL);
grilio_channel_remove_handler(md->io, md->radio_state_event_id);
grilio_channel_unref(md->io);
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
ril_radio_unref(modem->radio);
if (md->online_check_id) {
g_source_remove(md->online_check_id);
}
if (md->set_online.timeout_id) {
g_source_remove(md->set_online.timeout_id);
}
if (md->set_offline.timeout_id) {
g_source_remove(md->set_offline.timeout_id);
}
ril_network_unref(modem->network);
ril_sim_card_unref(modem->sim_card);
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->default_name);
g_free(md->imei);
g_free(md);
}
static void ril_modem_radio_state_changed(GRilIoChannel *io, guint ril_event,
const void *data, guint len, void *user_data)
struct ril_modem *ril_modem_create(GRilIoChannel *io,
const struct ril_slot_info *slot, struct ril_radio *radio,
struct ril_network *network, struct ril_sim_card *card,
struct ril_data *data)
{
struct ril_modem *md = user_data;
GRilIoParser rilp;
int radio_state;
GASSERT(ril_event == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &radio_state) &&
grilio_parser_at_end(&rilp)) {
DBG("%s %s", ofono_modem_get_path(md->modem),
ril_radio_state_to_string(radio_state));
md->radio_state = radio_state;
if (radio_state == RADIO_STATE_ON && !md->radio_settings) {
DBG("Initializing radio settings interface");
md->radio_settings =
ofono_radio_settings_create(md->modem, 0,
RILMODEM_DRIVER, md);
}
ril_modem_update_online_state(md);
} else {
ofono_error("Error parsing RADIO_STATE_CHANGED");
}
}
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *dev,
const struct ril_modem_config *config)
{
struct ofono_modem *modem = ofono_modem_create(dev, RILMODEM_DRIVER);
if (modem) {
/* Skip the slash from the path, it looks like "/ril_0" */
struct ofono_modem *ofono = ofono_modem_create(slot->path + 1,
RILMODEM_DRIVER);
if (ofono) {
int err;
struct ril_modem *md = g_new0(struct ril_modem, 1);
struct ril_modem_data *md = g_new0(struct ril_modem_data, 1);
struct ril_modem *modem = &md->modem;
/* Copy config */
md->config = *config;
if (config->default_name && config->default_name[0]) {
md->default_name = g_strdup(config->default_name);
modem->config = *slot->config;
modem->imei = md->imei = g_strdup(slot->imei);
if (slot->config->default_name &&
slot->config->default_name[0]) {
md->default_name = g_strdup(slot->config->default_name);
} else {
md->default_name = g_strdup_printf("SIM%u",
config->slot + 1);
slot->config->slot + 1);
}
md->config.default_name = md->default_name;
modem->config.default_name = md->default_name;
md->modem = modem;
md->io = grilio_channel_ref(io);
modem->ofono = ofono;
modem->radio = ril_radio_ref(radio);
modem->network = ril_network_ref(network);
modem->sim_card = ril_sim_card_ref(card);
modem->data = ril_data_ref(data);
modem->io = grilio_channel_ref(io);
md->q = grilio_queue_new(io);
ofono_modem_set_data(modem, md);
err = ofono_modem_register(modem);
md->set_online.md = md;
md->set_offline.md = md;
ofono_modem_set_data(ofono, md);
err = ofono_modem_register(ofono);
if (!err) {
md->radio_state_event_id =
grilio_channel_add_unsol_event_handler(io,
ril_modem_radio_state_changed,
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
md);
ril_radio_power_cycle(modem->radio);
ril_radio_power_on(modem->radio, RADIO_POWER_TAG(md));
GASSERT(io->connected);
ril_modem_request_power(md, FALSE, NULL);
/*
* ofono_modem_reset sets Powered to TRUE without
* issuing PropertyChange signal.
*/
ofono_modem_set_powered(md->modem, FALSE);
ofono_modem_set_powered(md->modem, TRUE);
ofono_modem_set_powered(modem->ofono, FALSE);
ofono_modem_set_powered(modem->ofono, TRUE);
md->power_state = POWERED_ON;
return md;
return modem;
} else {
ofono_error("Error %d registering %s",
err, RILMODEM_DRIVER);
@@ -462,10 +469,10 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *dev,
* ofono_modem_remove() won't invoke
* ril_modem_remove() callback.
*/
ril_modem_remove(modem);
ril_modem_remove(ofono);
}
ofono_modem_remove(modem);
ofono_modem_remove(ofono);
}
return NULL;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,41 +14,36 @@
*/
#include "ril_plugin.h"
#include "ril_network.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "common.h"
#include "simutil.h"
#include <ctype.h>
enum ril_netreg_events {
NETREG_EVENT_VOICE_NETWORK_STATE_CHANGED,
NETREG_EVENT_NITZ_TIME_RECEIVED,
NETREG_EVENT_SIGNAL_STRENGTH,
NETREG_EVENT_COUNT
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
NETREG_RIL_EVENT_COUNT
};
enum ril_netreg_network_events {
NETREG_NETWORK_EVENT_OPERATOR_CHANGED,
NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED,
NETREG_NETWORK_EVENT_COUNT
};
struct ril_netreg {
GRilIoChannel *io;
GRilIoQueue *q;
struct ofono_netreg *netreg;
char mcc[OFONO_MAX_MCC_LENGTH + 1];
char mnc[OFONO_MAX_MNC_LENGTH + 1];
int tech;
struct ofono_network_time time;
struct ril_network *network;
char *log_prefix;
guint timer_id;
int corestatus; /* Registration status previously reported to core */
gulong event_id[NETREG_EVENT_COUNT];
};
/* 27.007 Section 7.3 <stat> */
enum operator_status {
OPERATOR_STATUS_UNKNOWN = 0,
OPERATOR_STATUS_AVAILABLE = 1,
OPERATOR_STATUS_CURRENT = 2,
OPERATOR_STATUS_FORBIDDEN = 3,
guint notify_id;
guint current_operator_id;
gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
};
struct ril_netreg_cbd {
@@ -66,9 +61,9 @@ struct ril_netreg_cbd {
#define ril_netreg_cbd_free g_free
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *nr)
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
{
return ofono_netreg_get_data(nr);
return ofono ? ofono_netreg_get_data(ofono) : NULL;
}
static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
@@ -82,190 +77,86 @@ static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
return cbd;
}
static gboolean ril_netreg_extract_mcc_mnc(const char *str,
struct ofono_network_operator *op)
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
gint status)
{
if (str) {
int i;
const char *ptr = str;
if (status == NETWORK_REGISTRATION_STATUS_ROAMING) {
/* These functions tolerate NULL argument */
const char *net_mcc = ofono_netreg_get_mcc(netreg);
const char *net_mnc = ofono_netreg_get_mnc(netreg);
struct sim_spdi *spdi = ofono_netreg_get_spdi(netreg);
/* Three digit country code */
for (i = 0;
i < OFONO_MAX_MCC_LENGTH && *ptr && isdigit(*ptr);
i++) {
op->mcc[i] = *ptr++;
}
op->mcc[i] = 0;
if (i == OFONO_MAX_MCC_LENGTH) {
/* Usually a 2 but sometimes 3 digit network code */
for (i=0;
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
i++) {
op->mnc[i] = *ptr++;
}
op->mnc[i] = 0;
if (i > 0) {
/*
* Sometimes MCC/MNC are followed by + and
* what looks like the technology code. This
* is of course completely undocumented.
*/
if (*ptr == '+') {
int tech = ril_parse_tech(ptr+1, NULL);
if (tech >= 0) {
op->tech = tech;
}
}
return TRUE;
if (spdi && net_mcc && net_mnc) {
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
ofono_info("not roaming based on spdi");
return NETWORK_REGISTRATION_STATUS_REGISTERED;
}
}
}
return status;
}
static int ril_netreg_check_status(struct ril_netreg *nd, int status)
{
return (nd && nd->netreg) ?
ril_netreg_check_if_really_roaming(nd->netreg, status) :
status;
}
static gboolean ril_netreg_status_notify_cb(gpointer user_data)
{
struct ril_netreg *nd = user_data;
const struct ril_registration_state *reg = &nd->network->voice;
DBG("%s", nd->log_prefix);
GASSERT(nd->notify_id);
nd->notify_id = 0;
ofono_netreg_status_notify(nd->netreg,
ril_netreg_check_status(nd, reg->status),
reg->lac, reg->ci, reg->access_tech);
return FALSE;
}
static void ril_netreg_state_cb(GRilIoChannel *io, int call_status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_netreg_cbd *cbd = user_data;
ofono_netreg_status_cb_t cb = cbd->cb.status;
struct ril_netreg *nd = cbd->nd;
struct ril_reg_data reg;
int rawstatus;
DBG("");
if (call_status != RIL_E_SUCCESS || !nd->netreg) {
ofono_error("voice registration status query fail");
nd->corestatus = -1;
cb(ril_error_failure(&error), -1, -1, -1, -1, cbd->data);
return;
}
if (!ril_util_parse_reg(data, len, &reg)) {
DBG("voice registration status parsing fail");
nd->corestatus = -1;
cb(ril_error_failure(&error), -1, -1, -1, -1, cbd->data);
return;
}
rawstatus = reg.status;
if (reg.status == NETWORK_REGISTRATION_STATUS_ROAMING) {
reg.status = ril_netreg_check_if_really_roaming(nd->netreg,
reg.status);
}
if (rawstatus != reg.status) {
ofono_info("voice registration modified %d => %d",
rawstatus, reg.status);
}
DBG("status:%d corestatus:%d", reg.status, nd->corestatus);
if (nd->corestatus != reg.status) {
ofono_info("voice registration changes %d (%d)",
reg.status, nd->corestatus);
}
nd->corestatus = reg.status;
nd->tech = reg.access_tech;
cb(ril_error_ok(&error), reg.status, reg.lac, reg.ci, reg.access_tech,
cbd->data);
}
static void ril_netreg_status_notify(struct ofono_error *error, int status,
int lac, int ci, int tech, gpointer user_data)
static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
{
struct ril_netreg *nd = user_data;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error during status notification");
} else if (nd->netreg) {
ofono_netreg_status_notify(nd->netreg, status, lac, ci, tech);
/* Coalesce multiple notifications into one */
if (nd->notify_id) {
DBG("%snotification aready queued", nd->log_prefix);
} else {
DBG("%squeuing notification", nd->log_prefix);
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
}
}
static void ril_netreg_network_state_change(GRilIoChannel *io,
guint ril_event, const void *data, guint len, void *user_data)
{
struct ril_netreg *nd = user_data;
GASSERT(ril_event == RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
grilio_queue_send_request_full(nd->q, NULL,
RIL_REQUEST_VOICE_REGISTRATION_STATE,
ril_netreg_state_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, ril_netreg_status_notify, nd));
}
static void ril_netreg_registration_status(struct ofono_netreg *netreg,
ofono_netreg_status_cb_t cb, void *data)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
const struct ril_registration_state *reg = &nd->network->voice;
struct ofono_error error;
grilio_queue_send_request_full(nd->q, NULL,
RIL_REQUEST_VOICE_REGISTRATION_STATE, ril_netreg_state_cb,
ril_netreg_cbd_free, ril_netreg_cbd_new(nd, cb, data));
DBG("%s", nd->log_prefix);
cb(ril_error_ok(&error),
ril_netreg_check_status(nd, reg->status),
reg->lac, reg->ci, reg->access_tech, data);
}
static void ril_netreg_current_operator_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
static gboolean ril_netreg_current_operator_cb(void *user_data)
{
struct ril_netreg_cbd *cbd = user_data;
struct ril_netreg *nd = cbd->nd;
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
struct ofono_error error;
struct ofono_network_operator op;
struct ofono_network_operator *result = NULL;
gchar *lalpha = NULL, *salpha = NULL, *numeric = NULL;
int tmp;
GRilIoParser rilp;
ril_error_init_failure(&error);
if (status != RIL_E_SUCCESS) {
ofono_error("Failed to retrive the current operator: %s",
ril_error_to_string(status));
goto done;
}
DBG("%s", nd->log_prefix);
GASSERT(nd->current_operator_id);
nd->current_operator_id = 0;
grilio_parser_init(&rilp, data, len);
if (!grilio_parser_get_int32(&rilp, &tmp) || !tmp) {
goto done;
}
lalpha = grilio_parser_get_utf8(&rilp);
salpha = grilio_parser_get_utf8(&rilp);
numeric = grilio_parser_get_utf8(&rilp);
/* Try to use long by default */
if (lalpha) {
strncpy(op.name, lalpha, OFONO_MAX_OPERATOR_NAME_LENGTH);
} else if (salpha) {
strncpy(op.name, salpha, OFONO_MAX_OPERATOR_NAME_LENGTH);
} else {
goto done;
}
if (!ril_netreg_extract_mcc_mnc(numeric, &op)) {
goto done;
}
/* Set to current */
op.status = OPERATOR_STATUS_CURRENT;
op.tech = nd->tech;
result = &op;
ril_error_init_ok(&error);
DBG("lalpha=%s, salpha=%s, numeric=%s, %s, mcc=%s, mnc=%s, %s",
lalpha, salpha, numeric, op.name, op.mcc, op.mnc,
registration_tech_to_string(op.tech));
done:
cbd->cb.operator(&error, result, cbd->data);
g_free(lalpha);
g_free(salpha);
g_free(numeric);
cb(ril_error_ok(&error), nd->network->operator, cbd->data);
return FALSE;
}
static void ril_netreg_current_operator(struct ofono_netreg *netreg,
@@ -273,9 +164,15 @@ static void ril_netreg_current_operator(struct ofono_netreg *netreg,
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
grilio_queue_send_request_full(nd->q, NULL, RIL_REQUEST_OPERATOR,
ril_netreg_current_operator_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, cb, data));
GASSERT(!nd->current_operator_id);
if (nd->current_operator_id) {
g_source_remove(nd->current_operator_id);
}
nd->current_operator_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_netreg_current_operator_cb,
ril_netreg_cbd_new(nd, cb, data),
ril_netreg_cbd_free);
}
static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
@@ -334,11 +231,16 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
list[i].status = OPERATOR_STATUS_UNKNOWN;
}
op->tech = ACCESS_TECHNOLOGY_GSM;
ok = ril_netreg_extract_mcc_mnc(numeric, op);
op->tech = -1;
ok = ril_parse_mcc_mnc(numeric, op);
if (ok) {
if (op->tech < 0) {
op->tech = cbd->nd->network->voice.access_tech;
}
DBG("[operator=%s, %s, %s, status: %s]", op->name,
op->mcc, op->mnc, status);
} else {
DBG("failed to parse operator list");
}
g_free(lalpha);
@@ -506,6 +408,7 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
{
struct ril_netreg *nd = user_data;
GRilIoParser rilp;
struct ofono_network_time time;
int year, mon, mday, hour, min, sec, dst, tzi;
char tzs, tz[4];
gchar *nitz;
@@ -520,37 +423,19 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
&hour, &min, &sec, &tzs, &tzi, &dst);
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
nd->time.utcoff = atoi(tz) * 15 * 60;
nd->time.dst = dst;
nd->time.sec = sec;
nd->time.min = min;
nd->time.hour = hour;
nd->time.mday = mday;
nd->time.mon = mon;
nd->time.year = 2000 + year;
time.utcoff = atoi(tz) * 15 * 60;
time.dst = dst;
time.sec = sec;
time.min = min;
time.hour = hour;
time.mday = mday;
time.mon = mon;
time.year = 2000 + year;
ofono_netreg_time_notify(nd->netreg, &nd->time);
ofono_netreg_time_notify(nd->netreg, &time);
g_free(nitz);
}
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
gint status)
{
/* These functions tolerate NULL argument */
const char *net_mcc = ofono_netreg_get_mcc(netreg);
const char *net_mnc = ofono_netreg_get_mnc(netreg);
struct sim_spdi *spdi = ofono_netreg_get_spdi(netreg);
if (spdi && net_mcc && net_mnc) {
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
ofono_info("voice reg: not roaming based on spdi");
return NETWORK_REGISTRATION_STATUS_REGISTERED;
}
}
return status;
}
static gboolean ril_netreg_register(gpointer user_data)
{
struct ril_netreg *nd = user_data;
@@ -560,19 +445,21 @@ static gboolean ril_netreg_register(gpointer user_data)
ofono_netreg_register(nd->netreg);
/* Register for network state changes */
nd->event_id[NETREG_EVENT_VOICE_NETWORK_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(nd->io,
ril_netreg_network_state_change,
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, nd);
nd->network_event_id[NETREG_NETWORK_EVENT_OPERATOR_CHANGED] =
ril_network_add_operator_changed_handler(nd->network,
ril_netreg_status_notify, nd);
nd->network_event_id[NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED] =
ril_network_add_voice_state_changed_handler(nd->network,
ril_netreg_status_notify, nd);
/* Register for network time update reports */
nd->event_id[NETREG_EVENT_NITZ_TIME_RECEIVED] =
/* Register for network time updates */
nd->ril_event_id[NETREG_RIL_EVENT_NITZ_TIME_RECEIVED] =
grilio_channel_add_unsol_event_handler(nd->io,
ril_netreg_nitz_notify,
RIL_UNSOL_NITZ_TIME_RECEIVED, nd);
/* Register for signal strength changes */
nd->event_id[NETREG_EVENT_SIGNAL_STRENGTH] =
nd->ril_event_id[NETREG_RIL_EVENT_SIGNAL_STRENGTH] =
grilio_channel_add_unsol_event_handler(nd->io,
ril_netreg_strength_notify,
RIL_UNSOL_SIGNAL_STRENGTH, nd);
@@ -586,21 +473,14 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
{
struct ril_modem *modem = data;
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
guint slot = ril_modem_slot(modem);
DBG("[%u] %p", ril_modem_slot(modem), netreg);
DBG("[%u] %p", slot, netreg);
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
nd->io = grilio_channel_ref(ril_modem_io(modem));
nd->q = grilio_queue_new(nd->io);
nd->network = ril_network_ref(modem->network);
nd->netreg = netreg;
nd->tech = -1;
nd->time.sec = -1;
nd->time.min = -1;
nd->time.hour = -1;
nd->time.mday = -1;
nd->time.mon = -1;
nd->time.year = -1;
nd->time.dst = 0;
nd->time.utcoff = 0;
nd->corestatus = -1;
ofono_netreg_set_data(netreg, nd);
nd->timer_id = g_idle_add(ril_netreg_register, nd);
@@ -609,23 +489,36 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
static void ril_netreg_remove(struct ofono_netreg *netreg)
{
int i;
struct ril_netreg *nd = ril_netreg_get_data(netreg);
int i;
DBG("%p", netreg);
grilio_queue_cancel_all(nd->q, FALSE);
ofono_netreg_set_data(netreg, NULL);
for (i=0; i<G_N_ELEMENTS(nd->event_id); i++) {
grilio_channel_remove_handler(nd->io, nd->event_id[i]);
}
if (nd->timer_id > 0) {
g_source_remove(nd->timer_id);
}
if (nd->notify_id) {
g_source_remove(nd->notify_id);
}
if (nd->current_operator_id) {
g_source_remove(nd->current_operator_id);
}
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
}
ril_network_unref(nd->network);
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
G_N_ELEMENTS(nd->ril_event_id));
grilio_channel_unref(nd->io);
grilio_queue_unref(nd->q);
g_free(nd->log_prefix);
g_free(nd);
}

View File

@@ -0,0 +1,501 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_network.h"
#include "ril_radio.h"
#include "ril_util.h"
#include "ril_log.h"
#include <grilio_queue.h>
#include <grilio_request.h>
#include <grilio_parser.h>
#include <ofono/netreg.h>
#include "common.h"
typedef GObjectClass RilNetworkClass;
typedef struct ril_network RilNetwork;
struct ril_network_priv {
GRilIoChannel *io;
GRilIoQueue *q;
struct ril_radio *radio;
char *log_prefix;
gulong event_id;
guint operator_poll_id;
guint voice_poll_id;
guint data_poll_id;
gulong radio_event_id;
struct ofono_network_operator operator;
};
enum ril_network_signal {
SIGNAL_OPERATOR_CHANGED,
SIGNAL_VOICE_STATE_CHANGED,
SIGNAL_DATA_STATE_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilNetwork, ril_network, G_TYPE_OBJECT)
#define RIL_NETWORK_TYPE (ril_network_get_type())
#define RIL_NETWORK(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,\
RIL_NETWORK_TYPE,RilNetwork))
static void ril_network_reset_state(struct ril_registration_state *reg)
{
memset(reg, 0, sizeof(*reg));
reg->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
reg->access_tech = -1;
reg->ril_tech = -1;
reg->lac = -1;
reg->ci = -1;
}
static gboolean ril_network_parse_response(struct ril_network *self,
const void *data, guint len, struct ril_registration_state *reg)
{
struct ril_network_priv *priv = self->priv;
int nparams, ril_status;
gchar *sstatus = NULL, *slac = NULL, *sci = NULL;
gchar *stech = NULL, *sreason = NULL, *smax = NULL;
GRilIoParser rilp;
ril_network_reset_state(reg);
/* Size of response string array. The minimum seen in the wild is 3 */
grilio_parser_init(&rilp, data, len);
if (!grilio_parser_get_int32(&rilp, &nparams) || nparams < 3) {
DBG("%sbroken response", priv->log_prefix);
return FALSE;
}
sstatus = grilio_parser_get_utf8(&rilp); /* response[0] */
if (!sstatus) {
DBG("%sNo sstatus value returned!", priv->log_prefix);
return FALSE;
}
slac = grilio_parser_get_utf8(&rilp); /* response[1] */
sci = grilio_parser_get_utf8(&rilp); /* response[2] */
if (nparams > 3) {
stech = grilio_parser_get_utf8(&rilp); /* response[3] */
}
ril_status = atoi(sstatus);
if (ril_status > 10) {
reg->status = ril_status - 10;
} else {
reg->status = ril_status;
}
/* FIXME: need to review VOICE_REGISTRATION response
* as it returns up to 15 parameters ( vs. 6 for DATA ).
*
* The first four parameters are the same for both
* responses ( although status includes values for
* emergency calls for VOICE response ).
*
* Parameters 5 & 6 have different meanings for
* voice & data response.
*/
if (nparams > 4) {
/* TODO: different use for CDMA */
sreason = grilio_parser_get_utf8(&rilp); /* response[4] */
if (nparams > 5) {
/* TODO: different use for CDMA */
smax = grilio_parser_get_utf8(&rilp); /* response[5] */
if (smax) {
reg->max_calls = atoi(smax);
}
}
}
/*
* Some older RILs don't provide max calls, in that case let's
* supply some reasonable default. We don't need more than 2
* simultaneous data calls anyway.
*/
if (nparams <= 5) {
reg->max_calls = 2;
}
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
reg->access_tech = ril_parse_tech(stech, &reg->ril_tech);
DBG("%s%s,%s,%s,%d,%s,%s,%s", priv->log_prefix,
registration_status_to_string(reg->status),
slac, sci, reg->ril_tech,
registration_tech_to_string(reg->access_tech),
sreason, smax);
g_free(sstatus);
g_free(slac);
g_free(sci);
g_free(stech);
g_free(sreason);
g_free(smax);
return TRUE;
}
static void ril_network_op_copy(struct ofono_network_operator *dest,
const struct ofono_network_operator *src)
{
strncpy(dest->mcc, src->mcc, sizeof(dest->mcc));
strncpy(dest->mnc, src->mnc, sizeof(dest->mnc));
strncpy(dest->name, src->name, sizeof(dest->name));
dest->mcc[sizeof(dest->mcc)-1] = 0;
dest->mnc[sizeof(dest->mnc)-1] = 0;
dest->name[sizeof(dest->name)-1] = 0;
dest->status = src->status;
dest->tech = src->tech;
}
static gboolean ril_network_op_equal(const struct ofono_network_operator *op1,
const struct ofono_network_operator *op2)
{
if (op1 == op2) {
return TRUE;
} else if (!op1 || !op2) {
return FALSE;
} else {
return op1->status == op2->status &&
op1->tech == op2->tech &&
!strncmp(op1->mcc, op2->mcc, sizeof(op2->mcc)) &&
!strncmp(op1->mnc, op2->mnc, sizeof(op2->mnc)) &&
!strncmp(op1->name, op2->name, sizeof(op2->name));
}
}
static void ril_network_poll_operator_cb(GRilIoChannel *io, int req_status,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
GASSERT(priv->operator_poll_id);
priv->operator_poll_id = 0;
if (req_status == RIL_E_SUCCESS) {
struct ofono_network_operator op;
gboolean changed = FALSE;
gchar *lalpha;
char *salpha;
char *numeric;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
grilio_parser_get_int32(&rilp, NULL);
lalpha = grilio_parser_get_utf8(&rilp);
salpha = grilio_parser_get_utf8(&rilp);
numeric = grilio_parser_get_utf8(&rilp);
op.tech = -1;
if (ril_parse_mcc_mnc(numeric, &op)) {
if (op.tech < 0) op.tech = self->voice.access_tech;
op.status = OPERATOR_STATUS_CURRENT;
op.name[0] = 0;
if (lalpha) {
strncpy(op.name, lalpha, sizeof(op.name));
} else if (salpha) {
strncpy(op.name, salpha, sizeof(op.name));
} else {
strncpy(op.name, numeric, sizeof(op.name));
}
op.name[sizeof(op.name)-1] = 0;
if (!self->operator) {
self->operator = &priv->operator;
ril_network_op_copy(&priv->operator, &op);
changed = TRUE;
} else if (!ril_network_op_equal(&op, &priv->operator)) {
ril_network_op_copy(&priv->operator, &op);
changed = TRUE;
}
} else if (self->operator) {
self->operator = NULL;
changed = TRUE;
}
if (changed) {
if (self->operator) {
DBG("%slalpha=%s, salpha=%s, numeric=%s, %s, "
"mcc=%s, mnc=%s, %s", priv->log_prefix,
lalpha, salpha, numeric,
op.name, op.mcc, op.mnc,
registration_tech_to_string(op.tech));
} else {
DBG("%sno operator", priv->log_prefix);
}
g_signal_emit(self, ril_network_signals[
SIGNAL_OPERATOR_CHANGED], 0);
}
g_free(lalpha);
g_free(salpha);
g_free(numeric);
}
}
static void ril_network_poll_voice_state_cb(GRilIoChannel *io, int req_status,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
GASSERT(priv->voice_poll_id);
priv->voice_poll_id = 0;
if (req_status == RIL_E_SUCCESS) {
struct ril_registration_state state;
ril_network_parse_response(self, data, len, &state);
if (memcmp(&state, &self->voice, sizeof(state))) {
DBG("%svoice registration changed", priv->log_prefix);
self->voice = state;
g_signal_emit(self, ril_network_signals[
SIGNAL_VOICE_STATE_CHANGED], 0);
}
}
}
static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
GASSERT(priv->data_poll_id);
priv->data_poll_id = 0;
if (req_status == RIL_E_SUCCESS) {
struct ril_registration_state state;
ril_network_parse_response(self, data, len, &state);
if (memcmp(&state, &self->data, sizeof(state))) {
DBG("%sdata registration changed", priv->log_prefix);
self->data = state;
g_signal_emit(self, ril_network_signals[
SIGNAL_DATA_STATE_CHANGED], 0);
}
}
}
static guint ril_network_poll_and_retry(struct ril_network *self, guint id,
int code, GRilIoChannelResponseFunc fn)
{
struct ril_network_priv *priv = self->priv;
if (id) {
/* Retry right away, don't wait for retry timeout to expire */
grilio_channel_retry_request(priv->io, id);
} else {
GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
id = grilio_queue_send_request_full(priv->q, req, code, fn,
NULL, self);
grilio_request_unref(req);
}
return id;
}
static void ril_network_poll_state(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
priv->operator_poll_id = ril_network_poll_and_retry(self,
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
ril_network_poll_operator_cb);
priv->voice_poll_id = ril_network_poll_and_retry(self,
priv->voice_poll_id, RIL_REQUEST_VOICE_REGISTRATION_STATE,
ril_network_poll_voice_state_cb);
priv->data_poll_id = ril_network_poll_and_retry(self,
priv->data_poll_id, RIL_REQUEST_DATA_REGISTRATION_STATE,
ril_network_poll_data_state_cb);
}
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_OPERATOR_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_network_add_voice_state_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_VOICE_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_network_add_data_state_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_DATA_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_network_remove_handler(struct ril_network *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
GASSERT(code == RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
ril_network_poll_state(self);
}
static void ril_network_radio_state_cb(struct ril_radio *radio, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(self);
}
}
struct ril_network *ril_network_new(GRilIoChannel *io, struct ril_radio *radio)
{
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
struct ril_network_priv *priv = self->priv;
priv->io = grilio_channel_ref(io);
priv->q = grilio_queue_new(priv->io);
priv->radio = ril_radio_ref(radio);
priv->log_prefix =
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
g_strconcat(io->name, " ", NULL) : g_strdup("");
DBG("%s", priv->log_prefix);
priv->event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_network_voice_state_changed_cb,
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
priv->radio_event_id = ril_radio_add_state_changed_handler(priv->radio,
ril_network_radio_state_cb, self);
/*
* Query the initial state. Querying network state before the radio
* has been turned on makes RIL unhappy.
*/
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(self);
}
return self;
}
struct ril_network *ril_network_ref(struct ril_network *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_NETWORK(self));
return self;
} else {
return NULL;
}
}
void ril_network_unref(struct ril_network *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_NETWORK(self));
}
}
static void ril_network_init(struct ril_network *self)
{
struct ril_network_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_NETWORK_TYPE, struct ril_network_priv);
self->priv = priv;
ril_network_reset_state(&self->voice);
ril_network_reset_state(&self->data);
}
static void ril_network_dispose(GObject *object)
{
struct ril_network *self = RIL_NETWORK(object);
struct ril_network_priv *priv = self->priv;
if (priv->event_id) {
grilio_channel_remove_handler(priv->io, priv->event_id);
priv->event_id = 0;
}
if (priv->radio_event_id) {
ril_radio_remove_handler(priv->radio, priv->radio_event_id);
priv->radio_event_id = 0;
}
grilio_queue_cancel_all(priv->q, FALSE);
G_OBJECT_CLASS(ril_network_parent_class)->dispose(object);
}
static void ril_network_finalize(GObject *object)
{
struct ril_network *self = RIL_NETWORK(object);
struct ril_network_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
g_free(priv->log_prefix);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
ril_radio_unref(priv->radio);
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
}
static void ril_network_class_init(RilNetworkClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_network_dispose;
object_class->finalize = ril_network_finalize;
g_type_class_add_private(klass, sizeof(struct ril_network_priv));
ril_network_signals[SIGNAL_OPERATOR_CHANGED] =
g_signal_new(SIGNAL_OPERATOR_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
ril_network_signals[SIGNAL_VOICE_STATE_CHANGED] =
g_signal_new(SIGNAL_VOICE_STATE_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
ril_network_signals[SIGNAL_DATA_STATE_CHANGED] =
g_signal_new(SIGNAL_DATA_STATE_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,62 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_NETWORK_H
#define RIL_NETWORK_H
#include "ril_types.h"
struct ofono_network_operator;
struct ril_registration_state {
int status; /* enum network_registration_status */
int access_tech; /* enum access_technology or -1 if none */
int ril_tech;
int max_calls;
int lac;
int ci;
};
struct ril_network {
GObject object;
struct ril_network_priv *priv;
struct ril_registration_state voice;
struct ril_registration_state data;
const struct ofono_network_operator *operator;
};
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
struct ril_network *ril_network_new(GRilIoChannel *io, struct ril_radio *radio);
struct ril_network *ril_network_ref(struct ril_network *net);
void ril_network_unref(struct ril_network *net);
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
void ril_network_remove_handler(struct ril_network *net, gulong id);
#endif /* RIL_NETWORK */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,8 +14,11 @@
*/
#include "ril_plugin.h"
#include "ril_sim_card.h"
#include "ril_network.h"
#include "ril_radio.h"
#include "ril_data.h"
#include "ril_mce.h"
#include "ril_constants.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -42,6 +45,7 @@
#define RILMODEM_DEFAULT_4G TRUE /* 4G is on by default */
#define RILMODEM_DEFAULT_SLOT 0xffffffff
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
#define RILCONF_DEV_PREFIX "ril_"
#define RILCONF_PATH_PREFIX "/" RILCONF_DEV_PREFIX
@@ -51,6 +55,7 @@
#define RILCONF_SUB "sub"
#define RILCONF_TIMEOUT "timeout"
#define RILCONF_4G "enable4G"
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
#define RIL_STORE "ril"
#define RIL_STORE_GROUP "Settings"
@@ -63,19 +68,20 @@ enum ril_plugin_io_events {
IO_EVENT_CONNECTED,
IO_EVENT_ERROR,
IO_EVENT_EOF,
IO_EVENT_SIM_STATUS,
IO_EVENT_RADIO_STATE_CHANGED,
IO_EVENT_COUNT
};
struct ril_plugin_priv {
struct ril_plugin pub;
struct ril_plugin_dbus *dbus;
struct ril_data_manager *data_manager;
GSList *slots;
struct ril_modem *data_modem;
ril_slot_info_ptr *slots_info;
struct ril_slot *data_slot;
struct ril_slot *voice_slot;
char *default_voice_imsi;
char *default_data_imsi;
char *default_voice_path;
char *default_data_path;
GKeyFile *storage;
};
@@ -86,18 +92,23 @@ struct ril_slot {
char *name;
char *sockpath;
char *sub;
gint timeout; /* RIL timeout, in seconds */
gint timeout; /* RIL timeout, in milliseconds */
int index;
struct ril_modem_config config;
int sim_flags;
struct ril_slot_config config;
struct ril_plugin_priv *plugin;
struct ril_sim_dbus *sim_dbus;
struct ril_modem *modem;
struct ril_mce *mce;
struct ofono_sim *sim;
struct ril_radio *radio;
struct ril_network *network;
struct ril_sim_card *sim_card;
struct ril_data *data;
GRilIoChannel *io;
gulong io_event_id[IO_EVENT_COUNT];
gulong sim_status_req_id;
gulong imei_req_id;
gulong sim_card_state_event_id;
guint trace_id;
guint dump_id;
guint retry_id;
@@ -108,7 +119,9 @@ struct ril_slot {
static void ril_debug_trace_notify(struct ofono_debug_desc *desc);
static void ril_debug_dump_notify(struct ofono_debug_desc *desc);
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc);
static void ril_plugin_retry_init_io(struct ril_slot *slot);
static void ril_plugin_update_modem_paths_full(struct ril_plugin_priv *plugin);
GLOG_MODULE_DEFINE("rilmodem");
@@ -117,17 +130,29 @@ static struct ofono_debug_desc ril_debug_trace OFONO_DEBUG_ATTR = {
.flags = OFONO_DEBUG_FLAG_DEFAULT,
.notify = ril_debug_trace_notify
};
static struct ofono_debug_desc ril_debug_dump OFONO_DEBUG_ATTR = {
.name = "ril_dump",
.flags = OFONO_DEBUG_FLAG_DEFAULT,
.notify = ril_debug_dump_notify
};
static inline struct ril_plugin_priv *ril_plugin_cast(struct ril_plugin *pub)
static struct ofono_debug_desc grilio_debug OFONO_DEBUG_ATTR = {
.name = "grilio",
.flags = OFONO_DEBUG_FLAG_DEFAULT,
.notify = ril_debug_grilio_notify
};
static struct ril_plugin_priv *ril_plugin_cast(struct ril_plugin *pub)
{
return G_CAST(pub, struct ril_plugin_priv, pub);
}
static gboolean ril_plugin_multisim(struct ril_plugin_priv *plugin)
{
return plugin->slots && plugin->slots->next;
}
static void ril_plugin_foreach_slot_proc(gpointer data, gpointer user_data)
{
void (*fn)(struct ril_slot *) = user_data;
@@ -160,7 +185,7 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
}
if (slot->modem) {
struct ofono_modem *m = ril_modem_ofono_modem(slot->modem);
struct ofono_modem *m = slot->modem->ofono;
if (m && slot->sim_watch_id) {
__ofono_modem_remove_atom_watch(m, slot->sim_watch_id);
@@ -188,6 +213,30 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
slot->retry_id = 0;
}
if (slot->data) {
ril_data_allow(slot->data, FALSE);
ril_data_unref(slot->data);
slot->data = NULL;
}
if (slot->radio) {
ril_radio_unref(slot->radio);
slot->radio = NULL;
}
if (slot->network) {
ril_network_unref(slot->network);
slot->network = NULL;
}
if (slot->sim_card) {
ril_sim_card_remove_handler(slot->sim_card,
slot->sim_card_state_event_id);
ril_sim_card_unref(slot->sim_card);
slot->sim_card_state_event_id = 0;
slot->sim_card = NULL;
}
if (slot->io) {
int i;
@@ -198,10 +247,7 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
grilio_channel_cancel_request(slot->io,
slot->imei_req_id, FALSE);
grilio_channel_cancel_request(slot->io,
slot->sim_status_req_id, FALSE);
slot->imei_req_id = 0;
slot->sim_status_req_id = 0;
for (i=0; i<IO_EVENT_COUNT; i++) {
ril_plugin_remove_slot_handler(slot, i);
@@ -274,57 +320,86 @@ static struct ril_slot *ril_plugin_find_slot_number(GSList *slots, guint number)
static int ril_plugin_update_modem_paths(struct ril_plugin_priv *plugin)
{
int mask = 0;
struct ril_slot *voice = ril_plugin_find_slot_imsi(plugin->slots,
plugin->default_voice_imsi);
struct ril_slot *data = ril_plugin_find_slot_imsi(plugin->slots,
plugin->default_data_imsi);
struct ril_slot *slot = NULL;
if (!voice) {
/* If there's no default voice SIM, find any SIM instead.
* One should always be able to make and receive a phone call
* if there's a working SIM in the phone. However if the
* previously selected voice SIM is inserted, we will switch
* back to it. */
voice = ril_plugin_find_slot_imsi(plugin->slots, NULL);
/* Voice */
if (plugin->default_voice_imsi) {
slot = ril_plugin_find_slot_imsi(plugin->slots,
plugin->default_voice_imsi);
} else if (plugin->voice_slot) {
/* Make sure that the slot is enabled and SIM is in */
slot = ril_plugin_find_slot_imsi(plugin->slots,
plugin->voice_slot->modem ?
ofono_sim_get_imsi(plugin->voice_slot->sim) :
NULL);
}
if (voice) {
if (g_strcmp0(plugin->default_voice_path, voice->path)) {
DBG("Default voice SIM at %s", voice->path);
g_free(plugin->default_voice_path);
plugin->default_voice_path = g_strdup(voice->path);
mask |= RIL_PLUGIN_SIGNAL_VOICE_PATH;
}
} else if (plugin->default_voice_path) {
DBG("No default voice SIM");
g_free(plugin->default_voice_path);
plugin->default_voice_path = NULL;
/*
* If there's no default voice SIM, we will find any SIM instead.
* One should always be able to make and receive a phone call
* if there's a working SIM in the phone. However if the
* previously selected voice SIM is inserted, we will switch
* back to it.
*
* There is no such fallback for the data.
*/
if (!slot) {
slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
}
if (plugin->voice_slot != slot) {
mask |= RIL_PLUGIN_SIGNAL_VOICE_PATH;
plugin->voice_slot = slot;
if (slot) {
DBG("Default voice SIM at %s", slot->path);
plugin->pub.default_voice_path = slot->path;
} else {
DBG("No default voice SIM");
plugin->pub.default_voice_path = NULL;
}
}
if (data) {
if (g_strcmp0(plugin->default_data_path, data->path)) {
DBG("Default data SIM at %s", data->path);
g_free(plugin->default_data_path);
plugin->default_data_path = g_strdup(data->path);
mask |= RIL_PLUGIN_SIGNAL_DATA_PATH;
}
if (plugin->data_modem != data->modem) {
plugin->data_modem = data->modem;
ril_modem_allow_data(data->modem);
}
} else if (plugin->default_data_path) {
DBG("No default data SIM");
g_free(plugin->default_data_path);
plugin->default_data_path = NULL;
/* Data */
if (plugin->default_data_imsi) {
slot = ril_plugin_find_slot_imsi(plugin->slots,
plugin->default_data_imsi);
} else if (plugin->data_slot) {
/* Make sure that the slot is enabled and SIM is in */
slot = ril_plugin_find_slot_imsi(plugin->slots,
plugin->data_slot->modem ?
ofono_sim_get_imsi(plugin->data_slot->sim) :
NULL);
} else {
slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
}
if (plugin->data_slot != slot) {
mask |= RIL_PLUGIN_SIGNAL_DATA_PATH;
if (plugin->data_slot) {
/* Data no longer required for this slot */
ril_data_allow(plugin->data_slot->data, FALSE);
}
plugin->data_slot = slot;
if (slot) {
DBG("Default data SIM at %s", slot->path);
plugin->pub.default_data_path = slot->path;
ril_data_allow(slot->data, TRUE);
} else {
DBG("No default data SIM");
plugin->pub.default_data_path = NULL;
}
}
plugin->pub.default_voice_path = plugin->default_voice_path;
plugin->pub.default_data_path = plugin->default_data_path;
return mask;
}
/* Update modem paths and emit D-Bus signal if necessary */
static void ril_plugin_update_modem_paths_full(struct ril_plugin_priv *plugin)
{
ril_plugin_dbus_signal(plugin->dbus,
ril_plugin_update_modem_paths(plugin));
}
static void ril_plugin_check_sim_state(struct ril_slot *slot)
{
const char *slot_imsi = ofono_sim_get_imsi(slot->sim);
@@ -341,53 +416,25 @@ static void ril_plugin_check_sim_state(struct ril_slot *slot)
}
}
static void ril_plugin_request_sim_status_cb(GRilIoChannel *io, int err,
const void *data, guint len, void *user_data)
static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
{
struct ril_slot *slot = user_data;
struct ril_slot *slot = data;
gboolean present;
slot->sim_status_req_id = 0;
if (err != RIL_E_SUCCESS) {
ofono_error("SIM status error %s", ril_error_to_string(err));
if (card && card->status &&
card->status->card_state == RIL_CARDSTATE_PRESENT) {
DBG("SIM found in slot %u", slot->config.slot);
present = TRUE;
} else {
GRilIoParser rilp;
guint32 cardstate;
gboolean present;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &cardstate) &&
(cardstate == RIL_CARDSTATE_PRESENT)) {
DBG("SIM found in slot %u", slot->config.slot);
present = TRUE;
} else {
DBG("No SIM in slot %u", slot->config.slot);
present = FALSE;
}
if (slot->pub.sim_present != present) {
slot->pub.sim_present = present;
ril_plugin_dbus_signal_sim(slot->plugin->dbus,
slot->index, present);
}
DBG("No SIM in slot %u", slot->config.slot);
present = FALSE;
}
}
static void ril_plugin_request_sim_status(struct ril_slot *slot)
{
grilio_channel_cancel_request(slot->io, slot->sim_status_req_id, FALSE);
slot->sim_status_req_id = grilio_channel_send_request_full(slot->io,
NULL, RIL_REQUEST_GET_SIM_STATUS,
ril_plugin_request_sim_status_cb, NULL, slot);
}
static void ril_plugin_slot_status_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_slot *slot = user_data;
DBG("%s", slot->path);
GASSERT(code == RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED);
ril_plugin_request_sim_status(slot);
if (slot->pub.sim_present != present) {
slot->pub.sim_present = present;
ril_plugin_dbus_signal_sim(slot->plugin->dbus,
slot->index, present);
}
}
static void ril_plugin_sim_watch_done(void *data)
@@ -412,8 +459,7 @@ static void ril_plugin_sim_state_watch(enum ofono_sim_state new_state,
DBG("%s sim state %d", slot->path + 1, new_state);
slot->sim_state = new_state;
ril_plugin_check_sim_state(slot);
ril_plugin_dbus_signal(slot->plugin->dbus,
ril_plugin_update_modem_paths(slot->plugin));
ril_plugin_update_modem_paths_full(slot->plugin);
}
static void ril_plugin_register_sim(struct ril_slot *slot, struct ofono_sim *sim)
@@ -443,13 +489,13 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
}
ril_plugin_check_sim_state(slot);
ril_plugin_dbus_signal(slot->plugin->dbus,
ril_plugin_update_modem_paths(slot->plugin));
ril_plugin_update_modem_paths_full(slot->plugin);
}
static void ril_plugin_handle_error(struct ril_slot *slot)
{
ril_plugin_shutdown_slot(slot, TRUE);
ril_plugin_update_modem_paths_full(slot->plugin);
ril_plugin_retry_init_io(slot);
}
@@ -478,9 +524,8 @@ static void ril_plugin_modem_removed(struct ril_modem *modem, void *data)
}
slot->modem = NULL;
if (slot->plugin->data_modem == modem) {
slot->plugin->data_modem = NULL;
}
ril_data_allow(slot->data, FALSE);
ril_plugin_update_modem_paths_full(slot->plugin);
}
static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
@@ -488,12 +533,20 @@ static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
{
/* Use log sub-module to turn prefix off */
static GLOG_MODULE_DEFINE2_(log_module, NULL, GLOG_MODULE_NAME);
const char *prefix = io->name ? io->name : "";
const char dir = (type == GRILIO_PACKET_REQ) ? '<' : '>';
const char *prefix = io->name ? io->name : "";
const char dir = (type == GRILIO_PACKET_REQ) ? '<' : '>';
const char *scode;
switch (type) {
case GRILIO_PACKET_REQ:
if (io->ril_version <= 9 &&
code == RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION) {
scode = "V9_SET_UICC_SUBSCRIPTION";
} else {
scode = ril_request_to_string(code);
}
gutil_log(&log_module, GLOG_LEVEL_INFO, "%s%c [%08x] %s",
prefix, dir, id, ril_request_to_string(code));
prefix, dir, id, scode);
break;
case GRILIO_PACKET_RESP:
gutil_log(&log_module, GLOG_LEVEL_INFO, "%s%c [%08x] %s",
@@ -562,14 +615,14 @@ static void ril_plugin_create_modem(struct ril_slot *slot)
GASSERT(slot->io && slot->io->connected);
GASSERT(!slot->modem);
modem = ril_modem_create(slot->io, slot->path + 1, &slot->config);
modem = ril_modem_create(slot->io, &slot->pub, slot->radio,
slot->network, slot->sim_card, slot->data);
if (modem) {
struct ofono_sim *sim = ril_modem_ofono_sim(modem);
slot->modem = modem;
slot->sim_watch_id = __ofono_modem_add_atom_watch(
ril_modem_ofono_modem(modem),
slot->sim_watch_id = __ofono_modem_add_atom_watch(modem->ofono,
OFONO_ATOM_TYPE_SIM, ril_plugin_sim_watch,
slot, ril_plugin_sim_watch_done);
if (sim) {
@@ -580,6 +633,8 @@ static void ril_plugin_create_modem(struct ril_slot *slot)
} else {
ril_plugin_shutdown_slot(slot, TRUE);
}
ril_plugin_update_modem_paths_full(slot->plugin);
}
static void ril_plugin_imei_cb(GRilIoChannel *io, int status,
@@ -599,6 +654,9 @@ static void ril_plugin_imei_cb(GRilIoChannel *io, int status,
grilio_parser_init(&rilp, data, len);
slot->pub.imei = slot->imei = grilio_parser_get_utf8(&rilp);
DBG("%s", slot->imei);
if (slot->modem) {
ril_modem_set_imei(slot->modem, slot->imei);
}
} else {
ofono_error("Slot %u IMEI query error: %s", slot->config.slot,
ril_error_to_string(status));
@@ -616,9 +674,32 @@ static void ril_plugin_imei_cb(GRilIoChannel *io, int status,
}
}
/*
* It seems to be necessary to kick (with RIL_REQUEST_RADIO_POWER) the
* modems with power on after one of the modems has been powered off.
* Otherwise bad things may happen (like the modem never registering
* on the network).
*/
static void ril_plugin_power_check(struct ril_slot *slot)
{
ril_radio_confirm_power_on(slot->radio);
}
static void ril_plugin_radio_state_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
if (ril_radio_state_parse(data, len) == RADIO_STATE_OFF) {
struct ril_slot *slot = user_data;
DBG("power off for slot %u", slot->config.slot);
ril_plugin_foreach_slot(slot->plugin, ril_plugin_power_check);
}
}
static void ril_plugin_slot_connected(struct ril_slot *slot)
{
ofono_debug("%s version %u", slot->name, slot->io->ril_version);
ofono_debug("%s version %u", (slot->name && slot->name[0]) ?
slot->name : "RIL", slot->io->ril_version);
GASSERT(slot->io->connected);
GASSERT(!slot->io_event_id[IO_EVENT_CONNECTED]);
@@ -630,7 +711,29 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
slot->imei_req_id = grilio_channel_send_request_full(slot->io, NULL,
RIL_REQUEST_GET_IMEI, ril_plugin_imei_cb, NULL, slot);
ril_plugin_request_sim_status(slot);
GASSERT(!slot->radio);
slot->radio = ril_radio_new(slot->io);
slot->network = ril_network_new(slot->io, slot->radio);
GASSERT(!slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED]);
slot->io_event_id[IO_EVENT_RADIO_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(slot->io,
ril_plugin_radio_state_changed,
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, slot);
GASSERT(!slot->sim_card);
slot->sim_card = ril_sim_card_new(slot->io, slot->config.slot,
slot->sim_flags);
slot->sim_card_state_event_id = ril_sim_card_add_state_changed_handler(
slot->sim_card, ril_plugin_sim_state_changed, slot);
GASSERT(!slot->data);
slot->data = ril_data_new(slot->plugin->data_manager, slot->io);
if (ril_plugin_multisim(slot->plugin)) {
ril_data_set_name(slot->data, slot->path + 1);
}
if (ril_plugin_can_create_modem(slot) && !slot->modem) {
ril_plugin_create_modem(slot);
}
@@ -664,11 +767,6 @@ static void ril_plugin_init_io(struct ril_slot *slot)
slot->io_event_id[IO_EVENT_EOF] =
grilio_channel_add_disconnected_handler(slot->io,
ril_plugin_slot_disconnected, slot);
slot->io_event_id[IO_EVENT_SIM_STATUS] =
grilio_channel_add_unsol_event_handler(slot->io,
ril_plugin_slot_status_changed,
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
slot);
if (slot->io->connected) {
ril_plugin_slot_connected(slot);
@@ -724,6 +822,7 @@ static GSList *ril_plugin_create_default_config()
slot->name = g_strdup("RIL1");
slot->config.enable_4g = RILMODEM_DEFAULT_4G;
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
list = g_slist_append(list, slot);
slot = g_new0(struct ril_slot, 1);
@@ -732,6 +831,7 @@ static GSList *ril_plugin_create_default_config()
slot->name = g_strdup("RIL2");
slot->config.enable_4g = RILMODEM_DEFAULT_4G;
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
slot->config.slot = 1;
list = g_slist_append(list, slot);
} else {
@@ -744,6 +844,7 @@ static GSList *ril_plugin_create_default_config()
slot->name = g_strdup("");
slot->config.enable_4g = RILMODEM_DEFAULT_4G;
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
list = g_slist_append(list, slot);
}
} else {
@@ -753,6 +854,20 @@ static GSList *ril_plugin_create_default_config()
return list;
}
static void ril_plugin_read_config_flag(GKeyFile *file, const char *group,
const char *key, int flag, int *flags)
{
GError *err = NULL;
if (g_key_file_get_boolean(file, group, key, &err)) {
*flags |= flag;
} else if (!err) {
*flags &= ~flag;
} else {
g_error_free(err);
}
}
static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
const char *group)
{
@@ -769,6 +884,7 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
slot->path = g_strconcat("/", group, NULL);
slot->name = g_key_file_get_string(file, group, RILCONF_NAME,
NULL);
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
if (sub && strlen(sub) == RIL_SUB_SIZE) {
DBG("%s: %s:%s", group, sock, sub);
@@ -812,6 +928,14 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
err = NULL;
}
DBG("%s: 4G %s", group, slot->config.enable_4g ? "on" : "off");
ril_plugin_read_config_flag(file, group,
RILCONF_UICC_WORKAROUND,
RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND,
&slot->sim_flags);
DBG("%s: UICC workaround %s", group, (slot->sim_flags &
RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND) ?
"on" : "off");
} else {
DBG("no socket path in %s", group);
}
@@ -972,6 +1096,7 @@ static void ril_plugin_update_disabled_slot(struct ril_slot *slot)
if (!slot->pub.enabled) {
DBG("%s disabled", slot->path + 1);
ril_plugin_shutdown_slot(slot, FALSE);
ril_plugin_update_modem_paths_full(slot->plugin);
}
}
@@ -979,8 +1104,7 @@ static void ril_plugin_update_slots(struct ril_plugin_priv *plugin)
{
ril_plugin_foreach_slot(plugin, ril_plugin_update_disabled_slot);
ril_plugin_foreach_slot(plugin, ril_plugin_update_enabled_slot);
ril_plugin_dbus_signal(plugin->dbus,
ril_plugin_update_modem_paths(plugin));
ril_plugin_update_modem_paths_full(plugin);
}
struct ril_plugin_set_enabled_slots_data {
@@ -1101,21 +1225,21 @@ static void ril_plugin_init_slots(struct ril_plugin_priv *plugin)
{
int i;
GSList *link;
const struct ril_slot_info **pub =
g_new0(const struct ril_slot_info*,
ril_slot_info_ptr *info = g_new0(ril_slot_info_ptr,
g_slist_length(plugin->slots) + 1);
plugin->pub.slots = pub;
plugin->pub.slots = plugin->slots_info = info;
for (i = 0, link = plugin->slots; link; link = link->next, i++) {
struct ril_slot *slot = link->data;
*pub++ = &slot->pub;
*info++ = &slot->pub;
slot->index = i;
slot->plugin = plugin;
slot->pub.path = slot->path;
slot->pub.config = &slot->config;
}
*pub = NULL;
*info = NULL;
}
static void ril_plugin_enable_disable_slot(gpointer data, gpointer user_data)
@@ -1145,6 +1269,15 @@ static void ril_debug_dump_notify(struct ofono_debug_desc *desc)
}
}
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc)
{
if (desc->flags & OFONO_DEBUG_FLAG_PRINT) {
grilio_log.level = GLOG_LEVEL_VERBOSE;
} else {
grilio_log.level = GLOG_LEVEL_INHERIT;
}
}
static int ril_plugin_init(void)
{
char *enabled_slots;
@@ -1152,6 +1285,7 @@ static int ril_plugin_init(void)
DBG("");
GASSERT(!ril_plugin);
/* ofono core calls openlog() */
gutil_log_func = gutil_log_syslog;
ril_plugin_switch_user();
@@ -1160,6 +1294,7 @@ static int ril_plugin_init(void)
ril_plugin->slots = ril_plugin_load_config(RILMODEM_CONF_FILE);
ril_plugin_init_slots(ril_plugin);
ril_plugin->dbus = ril_plugin_dbus_new(&ril_plugin->pub);
ril_plugin->data_manager = ril_data_manager_new();
if (ril_plugin->slots) {
/*
@@ -1257,12 +1392,11 @@ static void ril_plugin_exit(void)
if (ril_plugin) {
g_slist_free_full(ril_plugin->slots, ril_plugin_destroy_slot);
ril_plugin_dbus_free(ril_plugin->dbus);
ril_data_manager_unref(ril_plugin->data_manager);
g_key_file_free(ril_plugin->storage);
g_free(ril_plugin->pub.slots);
g_free(ril_plugin->slots_info);
g_free(ril_plugin->default_voice_imsi);
g_free(ril_plugin->default_data_imsi);
g_free(ril_plugin->default_voice_path);
g_free(ril_plugin->default_data_path);
g_free(ril_plugin);
ril_plugin = NULL;
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -42,14 +42,21 @@
#include <grilio_parser.h>
#define RILMODEM_DRIVER "ril"
#define RIL_RETRY_SECS (2)
#define MAX_SIM_STATUS_RETRIES (15)
typedef struct ril_slot_info const *ril_slot_info_ptr;
struct ril_slot_config {
guint slot;
gboolean enable_4g;
const char *default_name;
};
struct ril_slot_info {
const char *path;
const char *imei;
gboolean enabled;
gboolean sim_present;
const struct ril_slot_config *config;
};
struct ril_plugin {
@@ -57,13 +64,18 @@ struct ril_plugin {
const char *default_data_imsi;
const char *default_voice_path;
const char *default_data_path;
const struct ril_slot_info **slots;
const ril_slot_info_ptr *slots;
};
struct ril_modem_config {
guint slot;
gboolean enable_4g;
const char *default_name;
struct ril_modem {
GRilIoChannel *io;
const char *imei;
struct ofono_modem *ofono;
struct ril_radio *radio;
struct ril_data *data;
struct ril_network *network;
struct ril_sim_card *sim_card;
struct ril_slot_config config;
};
#define RIL_PLUGIN_SIGNAL_VOICE_IMSI (0x01)
@@ -72,8 +84,6 @@ struct ril_modem_config {
#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x10)
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x20)
struct ril_modem;
struct ril_plugin_dbus;
typedef void (*ril_modem_cb_t)(struct ril_modem *modem, void *data);
void ril_plugin_set_enabled_slots(struct ril_plugin *plugin, char **slots);
@@ -94,22 +104,22 @@ void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
gboolean present);
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *dev,
const struct ril_modem_config *config);
struct ril_modem *ril_modem_create(GRilIoChannel *io,
const struct ril_slot_info *slot, struct ril_radio *radio,
struct ril_network *network, struct ril_sim_card *card,
struct ril_data *data);
void ril_modem_delete(struct ril_modem *modem);
void ril_modem_allow_data(struct ril_modem *modem);
GRilIoChannel *ril_modem_io(struct ril_modem *modem);
const struct ril_modem_config *ril_modem_config(struct ril_modem *modem);
void ril_modem_set_imei(struct ril_modem *modem, const char *imei);
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
struct ofono_modem *ril_modem_ofono_modem(struct ril_modem *modem);
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
void *data);
#define ril_modem_slot(md) (ril_modem_config(modem)->slot)
#define ril_modem_4g_enabled(md) (ril_modem_config(modem)->enable_4g)
#define ril_modem_get_path(md) ofono_modem_get_path(ril_modem_ofono_modem(md))
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
#define ril_modem_slot(modem) ((modem)->config.slot)
#define ril_modem_io(modem) ((modem)->io)
void ril_sim_read_file_linear(struct ofono_sim *sim, int fileid,
int record, int length, const unsigned char *path,
@@ -125,9 +135,7 @@ void ril_sim_read_file_info(struct ofono_sim *sim, int fileid,
ofono_sim_file_info_cb_t cb, void *data);
int ril_sim_app_type(struct ofono_sim *sim);
int ril_gprs_ril_data_tech(struct ofono_gprs *gprs);
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
gint status);
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
extern const struct ofono_call_barring_driver ril_call_barring_driver;
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;

View File

@@ -0,0 +1,405 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_radio.h"
#include "ril_util.h"
#include "ril_log.h"
#include <grilio_queue.h>
#include <grilio_request.h>
#include <grilio_parser.h>
typedef GObjectClass RilRadioClass;
typedef struct ril_radio RilRadio;
/*
* Object states:
*
* 1. Idle (!pending && !retry)
* 2. Power on/off request pending (pending)
* 3. Power on retry has been scheduled (retry)
*/
struct ril_radio_priv {
GRilIoChannel *io;
GRilIoQueue *q;
gulong state_event_id;
char *log_prefix;
GHashTable *req_table;
guint pending_id;
guint retry_id;
guint state_changed_while_request_pending;
enum ril_radio_state last_known_state;
gboolean power_cycle;
gboolean next_state_valid;
gboolean next_state;
};
enum ril_radio_signal {
SIGNAL_STATE_CHANGED,
SIGNAL_COUNT
};
#define POWER_RETRY_SECS (1)
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
#define RIL_RADIO_TYPE (ril_radio_get_type())
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
G_INLINE_FUNC gboolean ril_radio_power_should_be_on(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
return g_hash_table_size(priv->req_table) && !priv->power_cycle;
}
G_INLINE_FUNC gboolean ril_radio_state_off(enum ril_radio_state radio_state)
{
return radio_state == RADIO_STATE_OFF;
}
G_INLINE_FUNC gboolean ril_radio_state_on(enum ril_radio_state radio_state)
{
return !ril_radio_state_off(radio_state);
}
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
{
struct ril_radio *self = user_data;
struct ril_radio_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
GASSERT(priv->retry_id);
priv->retry_id = 0;
ril_radio_submit_power_request(self, ril_radio_power_should_be_on(self));
return FALSE;
}
static void ril_radio_cancel_retry(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
if (priv->retry_id) {
DBG("%sretry cancelled", priv->log_prefix);
g_source_remove(priv->retry_id);
priv->retry_id = 0;
}
}
static void ril_radio_check_state(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
if (!priv->pending_id) {
const gboolean should_be_on = ril_radio_power_should_be_on(self);
if (ril_radio_state_on(self->priv->last_known_state) ==
should_be_on) {
/* All is good, cancel pending retry if there is one */
ril_radio_cancel_retry(self);
} else if (priv->state_changed_while_request_pending) {
/* Hmm... RIL's reaction was inadequate, repeat */
ril_radio_submit_power_request(self, should_be_on);
} else if (!priv->retry_id) {
/* There has been no reaction so far, wait a bit */
DBG("%sretry scheduled", priv->log_prefix);
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
ril_radio_power_request_retry_cb, self);
}
}
/* Don't update public state while something is pending */
if (!priv->pending_id && !priv->retry_id &&
self->state != priv->last_known_state) {
DBG("%s%s -> %s", priv->log_prefix,
ril_radio_state_to_string(self->state),
ril_radio_state_to_string(priv->last_known_state));
self->state = priv->last_known_state;
g_signal_emit(self, ril_radio_signals[SIGNAL_STATE_CHANGED], 0);
}
}
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_radio *self = user_data;
struct ril_radio_priv *priv = self->priv;
GASSERT(priv->pending_id);
priv->pending_id = 0;
if (ril_status != RIL_E_SUCCESS) {
ofono_error("Power request failed: %s",
ril_error_to_string(ril_status));
}
if (priv->next_state_valid) {
ril_radio_submit_power_request(self, priv->next_state);
} else {
ril_radio_check_state(self);
}
}
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
{
struct ril_radio_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, on); /* Radio ON=1, OFF=0 */
priv->next_state_valid = FALSE;
priv->next_state = on;
priv->state_changed_while_request_pending = 0;
ril_radio_cancel_retry(self);
GASSERT(!priv->pending_id);
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb, NULL, self);
grilio_request_unref(req);
}
static void ril_radio_power_request(struct ril_radio *self, gboolean on,
gboolean allow_repeat)
{
struct ril_radio_priv *priv = self->priv;
const char *on_off = on ? "on" : "off";
if (priv->pending_id) {
if (allow_repeat || priv->next_state != on) {
/* Wait for the pending request to complete */
priv->next_state_valid = TRUE;
priv->next_state = on;
DBG("%s%s (queued)", priv->log_prefix, on_off);
} else {
DBG("%s%s (ignored)", priv->log_prefix, on_off);
}
} else {
DBG("%s%s", priv->log_prefix, on_off);
ril_radio_submit_power_request(self, on);
}
}
void ril_radio_confirm_power_on(struct ril_radio *self)
{
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
ril_radio_power_request(self, TRUE, TRUE);
}
}
void ril_radio_power_cycle(struct ril_radio *self)
{
if (G_LIKELY(self)) {
struct ril_radio_priv *priv = self->priv;
if (ril_radio_state_off(priv->last_known_state)) {
DBG("%spower is already off", priv->log_prefix);
GASSERT(!priv->power_cycle);
} else if (priv->power_cycle) {
DBG("%salready in progress", priv->log_prefix);
} else {
DBG("%sinitiated", priv->log_prefix);
priv->power_cycle = TRUE;
if (!priv->pending_id) {
ril_radio_submit_power_request(self, FALSE);
}
}
}
}
void ril_radio_power_on(struct ril_radio *self, gpointer tag)
{
if (G_LIKELY(self)) {
struct ril_radio_priv *priv = self->priv;
const gboolean was_on = ril_radio_power_should_be_on(self);
DBG("%s%p", priv->log_prefix, tag);
g_hash_table_insert(priv->req_table, tag, tag);
if (!was_on) {
ril_radio_power_request(self, TRUE, FALSE);
}
}
}
void ril_radio_power_off(struct ril_radio *self, gpointer tag)
{
if (G_LIKELY(self)) {
struct ril_radio_priv *priv = self->priv;
DBG("%s%p", priv->log_prefix, tag);
if (g_hash_table_remove(priv->req_table, tag) &&
!ril_radio_power_should_be_on(self)) {
/* The last one turns the lights off */
ril_radio_power_request(self, FALSE, FALSE);
}
}
}
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
ril_radio_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_radio_remove_handler(struct ril_radio *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
{
GRilIoParser rilp;
int radio_state;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &radio_state)) {
return radio_state;
} else {
ofono_error("Error parsing radio state");
return RADIO_STATE_UNAVAILABLE;
}
}
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_radio *self = user_data;
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
if (radio_state != RADIO_STATE_UNAVAILABLE) {
struct ril_radio_priv *priv = self->priv;
DBG("%s%s", priv->log_prefix,
ril_radio_state_to_string(radio_state));
GASSERT(!priv->pending_id || !priv->retry_id);
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
DBG("%sswitched off for power cycle", priv->log_prefix);
priv->power_cycle = FALSE;
}
if (priv->pending_id) {
priv->state_changed_while_request_pending++;
}
priv->last_known_state = radio_state;
ril_radio_check_state(self);
}
}
struct ril_radio *ril_radio_new(GRilIoChannel *io)
{
struct ril_radio *self = g_object_new(RIL_RADIO_TYPE, NULL);
struct ril_radio_priv *priv = self->priv;
priv->io = grilio_channel_ref(io);
priv->q = grilio_queue_new(priv->io);
priv->log_prefix =
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
g_strconcat(io->name, " ", NULL) : g_strdup("");
DBG("%s", priv->log_prefix);
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_radio_state_changed,
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
return self;
}
struct ril_radio *ril_radio_ref(struct ril_radio *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_RADIO(self));
return self;
} else {
return NULL;
}
}
void ril_radio_unref(struct ril_radio *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_RADIO(self));
}
}
static void ril_radio_init(struct ril_radio *self)
{
struct ril_radio_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_RADIO_TYPE, struct ril_radio_priv);
self->priv = priv;
priv->req_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, NULL);
}
static void ril_radio_dispose(GObject *object)
{
struct ril_radio *self = RIL_RADIO(object);
struct ril_radio_priv *priv = self->priv;
if (priv->state_event_id) {
grilio_channel_remove_handler(priv->io, priv->state_event_id);
priv->state_event_id = 0;
}
if (priv->pending_id) {
grilio_queue_cancel_request(priv->q, priv->pending_id, FALSE);
priv->pending_id = 0;
}
priv->next_state_valid = FALSE;
ril_radio_cancel_retry(self);
grilio_queue_cancel_all(priv->q, FALSE);
G_OBJECT_CLASS(ril_radio_parent_class)->dispose(object);
}
static void ril_radio_finalize(GObject *object)
{
struct ril_radio *self = RIL_RADIO(object);
struct ril_radio_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
g_free(priv->log_prefix);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
g_hash_table_unref(priv->req_table);
G_OBJECT_CLASS(ril_radio_parent_class)->finalize(object);
}
static void ril_radio_class_init(RilRadioClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_radio_dispose;
object_class->finalize = ril_radio_finalize;
g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
ril_radio_signals[SIGNAL_STATE_CHANGED] =
g_signal_new(SIGNAL_STATE_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,50 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_RADIO_H
#define RIL_RADIO_H
#include "ril_types.h"
struct ril_radio {
GObject object;
struct ril_radio_priv *priv;
enum ril_radio_state state;
};
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
struct ril_radio *ril_radio_new(GRilIoChannel *io);
struct ril_radio *ril_radio_ref(struct ril_radio *radio);
void ril_radio_unref(struct ril_radio *radio);
void ril_radio_power_on(struct ril_radio *radio, gpointer tag);
void ril_radio_power_off(struct ril_radio *radio, gpointer tag);
void ril_radio_confirm_power_on(struct ril_radio *radio);
void ril_radio_power_cycle(struct ril_radio *radio);
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
ril_radio_cb_t cb, void *arg);
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
#endif /* RIL_RADIO */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -18,12 +18,13 @@
#include "ril_log.h"
#include "ril_constants.h"
#include "storage.h"
struct ril_radio_settings {
GRilIoQueue *q;
struct ofono_radio_settings *rs;
enum ofono_radio_access_mode access_mode;
gboolean enable_4g;
int ratmode;
guint timer_id;
guint query_rats_id;
};
struct ril_radio_settings_cbd {
@@ -31,14 +32,12 @@ struct ril_radio_settings_cbd {
union _ofono_radio_settings_cb {
ofono_radio_settings_rat_mode_set_cb_t rat_mode_set;
ofono_radio_settings_rat_mode_query_cb_t rat_mode_query;
ofono_radio_settings_available_rats_query_cb_t available_rats;
gpointer ptr;
} cb;
gpointer data;
};
#define RIL_STORE "rilmodem"
#define LTE_FLAG "4gOn"
#define ril_radio_settings_cbd_free g_free
static inline struct ril_radio_settings *ril_radio_settings_get_data(
@@ -59,6 +58,45 @@ static struct ril_radio_settings_cbd *ril_radio_settings_cbd_new(
return cbd;
}
static enum ofono_radio_access_mode ril_radio_settings_pref_to_mode(int pref)
{
switch (pref) {
case PREF_NET_TYPE_LTE_CDMA_EVDO:
case PREF_NET_TYPE_LTE_GSM_WCDMA:
case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
case PREF_NET_TYPE_LTE_ONLY:
case PREF_NET_TYPE_LTE_WCDMA:
return OFONO_RADIO_ACCESS_MODE_LTE;
case PREF_NET_TYPE_GSM_ONLY:
return OFONO_RADIO_ACCESS_MODE_GSM;
case PREF_NET_TYPE_GSM_WCDMA_AUTO:
case PREF_NET_TYPE_WCDMA:
case PREF_NET_TYPE_GSM_WCDMA:
return OFONO_RADIO_ACCESS_MODE_UMTS;
default:
return OFONO_RADIO_ACCESS_MODE_ANY;
}
}
static int ril_radio_settings_mode_to_pref(struct ril_radio_settings *rsd,
enum ofono_radio_access_mode mode)
{
switch (mode) {
case OFONO_RADIO_ACCESS_MODE_ANY:
case OFONO_RADIO_ACCESS_MODE_LTE:
if (rsd->enable_4g) {
return PREF_NET_TYPE_LTE_WCDMA;
}
/* no break */
case OFONO_RADIO_ACCESS_MODE_UMTS:
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
case OFONO_RADIO_ACCESS_MODE_GSM:
return PREF_NET_TYPE_GSM_ONLY;
default:
return -1;
}
}
static void ril_radio_settings_submit_request(struct ril_radio_settings *rsd,
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
void *cb, void *data)
@@ -78,112 +116,74 @@ static void ril_radio_settings_set_rat_mode_cb(GRilIoChannel *io, int status,
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
ofono_error("rat mode setting failed");
ofono_error("failed to set rat mode");
cb(ril_error_failure(&error), cbd->data);
}
}
static GRilIoRequest *ril_radio_settings_set_pref_req(int pref)
{
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1); /* Number of params */
grilio_request_append_int32(req, pref);
return req;
}
static int ril_radio_settings_parse_pref_resp(const void *data, guint len)
{
GRilIoParser rilp;
int pref = -1;
grilio_parser_init(&rilp, data, len);
grilio_parser_get_int32(&rilp, NULL);
grilio_parser_get_int32(&rilp, &pref);
return pref;
}
static void ril_radio_settings_set_rat_mode(struct ofono_radio_settings *rs,
enum ofono_radio_access_mode mode,
ofono_radio_settings_rat_mode_set_cb_t cb, void *data)
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
GRilIoRequest *req = grilio_request_sized_new(8);
int pref = rsd->ratmode;
int pref = ril_radio_settings_mode_to_pref(rsd, mode);
GRilIoRequest *req;
ofono_info("rat mode set %d", mode);
switch (mode) {
case OFONO_RADIO_ACCESS_MODE_GSM:
pref = PREF_NET_TYPE_GSM_ONLY;
break;
case OFONO_RADIO_ACCESS_MODE_UMTS:
pref = PREF_NET_TYPE_GSM_WCDMA_AUTO; /* per UI design */
break;
case OFONO_RADIO_ACCESS_MODE_LTE:
pref = PREF_NET_TYPE_LTE_ONLY;
default:
break;
}
grilio_request_append_int32(req, 1); /* Number of params */
grilio_request_append_int32(req, pref);
if (pref < 0) pref = rsd->ratmode;
DBG("rat mode set %d (ril %d)", mode, pref);
req = ril_radio_settings_set_pref_req(pref);
ril_radio_settings_submit_request(rsd, req,
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
ril_radio_settings_set_rat_mode_cb, cb, data);
grilio_request_unref(req);
}
static void ril_radio_settings_force_rat(struct ril_radio_settings *rsd,
int pref)
{
if (pref != rsd->ratmode) {
GRilIoRequest *req = grilio_request_sized_new(8);
DBG("pref ril rat mode %d, ril current %d", pref, rsd->ratmode);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, rsd->ratmode);
grilio_queue_send_request(rsd->q, req,
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE);
grilio_request_unref(req);
}
}
static void ril_radio_settings_query_rat_mode_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_radio_settings_cbd *cbd = user_data;
struct ril_radio_settings *rsd = cbd->rsd;
ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb.rat_mode_query;
DBG("");
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
int mode = OFONO_RADIO_ACCESS_MODE_ANY;
int pref = -1;
grilio_parser_init(&rilp, data, len);
grilio_parser_get_int32(&rilp, NULL);
grilio_parser_get_int32(&rilp, &pref);
switch (pref) {
case PREF_NET_TYPE_LTE_ONLY:
mode = OFONO_RADIO_ACCESS_MODE_LTE;
case PREF_NET_TYPE_GSM_ONLY:
mode = OFONO_RADIO_ACCESS_MODE_GSM;
break;
case PREF_NET_TYPE_GSM_WCDMA_AUTO:/* according to UI design */
if (!cb) {
ril_radio_settings_force_rat(cbd->rsd, pref);
}
case PREF_NET_TYPE_WCDMA:
case PREF_NET_TYPE_GSM_WCDMA: /* according to UI design */
mode = OFONO_RADIO_ACCESS_MODE_UMTS;
break;
case PREF_NET_TYPE_LTE_CDMA_EVDO:
case PREF_NET_TYPE_LTE_GSM_WCDMA:
case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
if (!cb) {
ril_radio_settings_force_rat(cbd->rsd, pref);
}
break;
case PREF_NET_TYPE_CDMA_EVDO_AUTO:
case PREF_NET_TYPE_CDMA_ONLY:
case PREF_NET_TYPE_EVDO_ONLY:
case PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO:
default:
break;
}
ofono_info("rat mode %d (ril %d)", mode, pref);
if (cb) {
cb(ril_error_ok(&error), mode, cbd->data);
}
rsd->ratmode = ril_radio_settings_parse_pref_resp(data, len);
DBG("rat mode %d (ril %d)",
ril_radio_settings_pref_to_mode(rsd->ratmode),
rsd->ratmode);
} else {
ofono_error("rat mode query failed");
if (cb) {
cb(ril_error_failure(&error), -1, cbd->data);
}
/*
* With certain versions of RIL, preferred network type
* queries don't work even though setting preferred network
* type does actually work. In this case, assume that our
* cached network type is the right one.
*/
ofono_error("rat mode query failed, assuming %d (ril %d)",
ril_radio_settings_pref_to_mode(rsd->ratmode),
rsd->ratmode);
}
cb(ril_error_ok(&error), ril_radio_settings_pref_to_mode(rsd->ratmode),
cbd->data);
}
static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
@@ -191,61 +191,78 @@ static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
ofono_info("rat mode query");
DBG("rat mode query");
ril_radio_settings_submit_request(rsd, NULL,
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
ril_radio_settings_query_rat_mode_cb, cb, data);
}
static gboolean ril_radio_settings_get_config(struct ril_radio_settings *rsd)
static gboolean ril_radio_settings_query_available_rats_cb(gpointer data)
{
gboolean needsconfig = FALSE;
gboolean value = FALSE;
struct ofono_error error;
struct ril_radio_settings_cbd *cbd = data;
guint rats = OFONO_RADIO_ACCESS_MODE_GSM | OFONO_RADIO_ACCESS_MODE_UMTS;
/* Hmm... One file shared by all modems... Why?? */
GKeyFile *keyfile = storage_open(NULL, RIL_STORE);
char **alreadyset = g_key_file_get_groups(keyfile, NULL);
if (alreadyset[0])
value = g_key_file_get_boolean(
keyfile, alreadyset[0], LTE_FLAG, NULL);
else if (rsd->ratmode == PREF_NET_TYPE_GSM_WCDMA_AUTO)
value = TRUE;
if (!value && rsd->ratmode == PREF_NET_TYPE_LTE_GSM_WCDMA) {
g_key_file_set_boolean(keyfile,
LTE_FLAG, LTE_FLAG, TRUE);
needsconfig = TRUE;
} else if (value && rsd->ratmode == PREF_NET_TYPE_GSM_WCDMA_AUTO) {
g_key_file_set_boolean(keyfile,
LTE_FLAG, LTE_FLAG, FALSE);
needsconfig = TRUE;
if (cbd->rsd->enable_4g) {
rats |= OFONO_RADIO_ACCESS_MODE_LTE;
}
g_strfreev(alreadyset);
storage_close(NULL, RIL_STORE, keyfile, TRUE);
DBG("needsconfig %d, rat mode %d", needsconfig, rsd->ratmode);
return needsconfig;
GASSERT(cbd->rsd->query_rats_id);
cbd->rsd->query_rats_id = 0;
cbd->cb.available_rats(ril_error_ok(&error), rats, cbd->data);
return FALSE;
}
static gboolean ril_radio_settings_register(gpointer user_data)
static void ril_radio_settings_query_available_rats(
struct ofono_radio_settings *rs,
ofono_radio_settings_available_rats_query_cb_t cb, void *data)
{
struct ofono_radio_settings *rs = user_data;
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
rsd->timer_id = 0;
ofono_radio_settings_register(rs);
DBG("");
GASSERT(!rsd->query_rats_id);
rsd->query_rats_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_radio_settings_query_available_rats_cb,
ril_radio_settings_cbd_new(rsd, cb, data),
ril_radio_settings_cbd_free);
}
if (ril_radio_settings_get_config(rsd)) {
ril_radio_settings_submit_request(rsd, NULL,
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
ril_radio_settings_query_rat_mode_cb, NULL, NULL);
static void ril_radio_settings_init_query_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
int pref;
struct ril_radio_settings *rsd = user_data;
enum ofono_radio_access_mode mode;
if (status == RIL_E_SUCCESS) {
pref = ril_radio_settings_parse_pref_resp(data, len);
DBG("rat mode %d", pref);
} else {
ofono_error("initial rat mode query failed");
pref = ril_radio_settings_mode_to_pref(rsd,
OFONO_RADIO_ACCESS_MODE_ANY);
}
/* Single shot */
return FALSE;
mode = ril_radio_settings_pref_to_mode(pref);
if (!rsd->enable_4g && mode == OFONO_RADIO_ACCESS_MODE_LTE) {
rsd->ratmode = ril_radio_settings_mode_to_pref(rsd,
OFONO_RADIO_ACCESS_MODE_UMTS);
} else {
rsd->ratmode = pref;
}
if (rsd->ratmode != pref || status != RIL_E_SUCCESS) {
GRilIoRequest *req;
DBG("forcing rat mode %d", rsd->ratmode);
req = ril_radio_settings_set_pref_req(rsd->ratmode);
grilio_queue_send_request(rsd->q, req,
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE);
grilio_request_unref(req);
}
ofono_radio_settings_register(rsd->rs);
}
static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
@@ -255,37 +272,39 @@ static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
struct ril_radio_settings *rsd = g_new0(struct ril_radio_settings, 1);
DBG("");
rsd->rs = rs;
rsd->q = grilio_queue_new(ril_modem_io(modem));
rsd->ratmode = ril_modem_4g_enabled(modem) ?
PREF_NET_TYPE_LTE_GSM_WCDMA :
PREF_NET_TYPE_GSM_WCDMA_AUTO;
rsd->enable_4g = ril_modem_4g_enabled(modem);
grilio_queue_send_request_full(rsd->q, NULL,
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
ril_radio_settings_init_query_cb, NULL, rsd);
rsd->timer_id = g_idle_add(ril_radio_settings_register, rs);
ofono_radio_settings_set_data(rs, rsd);
return 0;
}
static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
{
struct ril_radio_settings *rd = ril_radio_settings_get_data(rs);
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
DBG("");
ofono_radio_settings_set_data(rs, NULL);
if (rd->timer_id > 0) {
g_source_remove(rd->timer_id);
if (rsd->query_rats_id > 0) {
g_source_remove(rsd->query_rats_id);
}
grilio_queue_cancel_all(rd->q, FALSE);
grilio_queue_unref(rd->q);
g_free(rd);
grilio_queue_cancel_all(rsd->q, FALSE);
grilio_queue_unref(rsd->q);
g_free(rsd);
}
const struct ofono_radio_settings_driver ril_radio_settings_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_radio_settings_probe,
.remove = ril_radio_settings_remove,
.query_rat_mode = ril_radio_settings_query_rat_mode,
.set_rat_mode = ril_radio_settings_set_rat_mode,
.name = RILMODEM_DRIVER,
.probe = ril_radio_settings_probe,
.remove = ril_radio_settings_remove,
.query_rat_mode = ril_radio_settings_query_rat_mode,
.set_rat_mode = ril_radio_settings_set_rat_mode,
.query_available_rats = ril_radio_settings_query_available_rats
};
/*

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,532 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_sim_card.h"
#include "ril_radio.h"
#include "ril_util.h"
#include "ril_log.h"
#include <grilio_queue.h>
#include <grilio_request.h>
#include <grilio_parser.h>
typedef GObjectClass RilSimCardClass;
typedef struct ril_sim_card RilSimCard;
enum ril_sim_card_event {
EVENT_SIM_STATUS_CHANGED,
EVENT_UICC_SUBSCRIPTION_STATUS_CHANGED,
EVENT_COUNT
};
struct ril_sim_card_priv {
GRilIoChannel *io;
GRilIoQueue *q;
int flags;
guint status_req_id;
gulong event_id[EVENT_COUNT];
};
enum ril_sim_card_signal {
SIGNAL_STATUS_RECEIVED,
SIGNAL_STATUS_CHANGED,
SIGNAL_STATE_CHANGED,
SIGNAL_APP_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
static guint ril_sim_card_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilSimCard, ril_sim_card, G_TYPE_OBJECT)
#define RIL_SIMCARD_TYPE (ril_sim_card_get_type())
#define RIL_SIMCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_SIMCARD_TYPE, RilSimCard))
#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)
{
if (a1 == a2) {
return TRUE;
} else if (!a1 || !a2) {
return FALSE;
} else {
return a1->app_type == a2->app_type &&
a1->app_state == a2->app_state &&
a1->perso_substate == a2->perso_substate &&
a1->pin_replaced == a2->pin_replaced &&
a1->pin1_state == a2->pin1_state &&
a1->pin2_state == a2->pin2_state &&
!g_strcmp0(a1->aid, a2->aid) &&
!g_strcmp0(a1->label, a2->label);
}
}
static int ril_sim_card_status_compare(const struct ril_sim_card_status *s1,
const struct ril_sim_card_status *s2)
{
if (s1 == s2) {
return 0;
} else if (!s1 || !s2) {
return RIL_SIMCARD_STATE_CHANGED | RIL_SIMCARD_STATUS_CHANGED;
} else {
int diff = 0;
if (s1->card_state != s2->card_state) {
diff |= RIL_SIMCARD_STATE_CHANGED;
}
if (s1->pin_state != s2->pin_state ||
s1->gsm_umts_index != s2->gsm_umts_index ||
s1->cdma_index != s2->cdma_index ||
s1->ims_index != s2->ims_index ||
s1->num_apps != s2->num_apps) {
diff |= RIL_SIMCARD_STATUS_CHANGED;
} else {
int i;
for (i = 0; i < s1->num_apps; i++) {
if (!ril_sim_card_app_equal(s1->apps + i,
s2->apps + i)) {
diff |= RIL_SIMCARD_STATUS_CHANGED;
break;
}
}
}
return diff;
}
}
static void ril_sim_card_status_free(struct ril_sim_card_status *status)
{
if (status) {
if (status->apps) {
int i;
for (i = 0; i < status->num_apps; i++) {
g_free(status->apps[i].aid);
g_free(status->apps[i].label);
}
g_free(status->apps);
}
g_free(status);
}
}
static void ril_sim_card_subscribe(struct ril_sim_card *self,
int app_index, int sub_status)
{
struct ril_sim_card_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(16);
const guint sub_id = self->slot;
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_status);
grilio_request_append_int32(req, self->slot);
grilio_request_append_int32(req, app_index);
grilio_request_append_int32(req, sub_id);
grilio_request_append_int32(req, sub_status);
grilio_queue_send_request(priv->q, req, (priv->io->ril_version <= 9 &&
(priv->flags & RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND)) ?
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
RIL_REQUEST_SET_UICC_SUBSCRIPTION);
grilio_request_unref(req);
}
static int ril_sim_card_select_app(const struct ril_sim_card_status *status)
{
int selected_app = -1;
guint i;
for (i = 0; i < status->num_apps; i++) {
const int type = status->apps[i].app_type;
if (type == RIL_APPTYPE_USIM || type == RIL_APPTYPE_RUIM) {
selected_app = i;
break;
} else if (type != RIL_APPTYPE_UNKNOWN && selected_app == -1) {
selected_app = i;
}
}
DBG("%d", selected_app);
return selected_app;
}
static void ril_sim_card_update_app(struct ril_sim_card *self)
{
const struct ril_sim_card_app *old_app = self->app;
const struct ril_sim_card_status *status = self->status;
int app_index;
if (status->card_state == RIL_CARDSTATE_PRESENT) {
if (status->gsm_umts_index >= 0 &&
status->gsm_umts_index < status->num_apps) {
app_index = status->gsm_umts_index;
} else {
app_index = ril_sim_card_select_app(status);
if (app_index >= 0) {
ril_sim_card_subscribe(self, app_index, 1);
}
}
} else {
app_index = -1;
}
if (app_index >= 0 &&
status->apps[app_index].app_type != RIL_APPTYPE_UNKNOWN) {
self->app = status->apps + app_index;
} else {
self->app = NULL;
}
if (!ril_sim_card_app_equal(old_app, self->app)) {
g_signal_emit(self,
ril_sim_card_signals[SIGNAL_APP_CHANGED], 0);
}
}
static void ril_sim_card_update_status(struct ril_sim_card *self,
struct ril_sim_card_status *status)
{
const int diff = ril_sim_card_status_compare(self->status, status);
if (diff) {
struct ril_sim_card_status *old_status = self->status;
self->status = status;
ril_sim_card_update_app(self);
g_signal_emit(self, ril_sim_card_signals[
SIGNAL_STATUS_RECEIVED], 0);
if (diff & RIL_SIMCARD_STATUS_CHANGED) {
DBG("status changed");
g_signal_emit(self, ril_sim_card_signals[
SIGNAL_STATUS_CHANGED], 0);
}
if (diff & RIL_SIMCARD_STATE_CHANGED) {
DBG("state changed");
g_signal_emit(self, ril_sim_card_signals[
SIGNAL_STATE_CHANGED], 0);
}
ril_sim_card_status_free(old_status);
} else {
ril_sim_card_status_free(status);
g_signal_emit(self, ril_sim_card_signals[
SIGNAL_STATUS_RECEIVED], 0);
}
}
static gboolean ril_sim_card_app_parse(GRilIoParser *rilp,
struct ril_sim_card_app *app)
{
gint32 app_type, app_state, perso_substate;
gint32 pin_replaced, pin1_state, pin2_state;
grilio_parser_get_int32(rilp, &app_type);
grilio_parser_get_int32(rilp, &app_state);
/*
* Consider RIL_APPSTATE_ILLEGAL also READY. Even if app state is
* RIL_APPSTATE_ILLEGAL (-1), ICC operations must be permitted.
* Network access requests will anyway be rejected and ME will be
* in limited service.
*/
if (app_state == RIL_APPSTATE_ILLEGAL) {
DBG("RIL_APPSTATE_ILLEGAL => RIL_APPSTATE_READY");
app_state = RIL_APPSTATE_READY;
}
grilio_parser_get_int32(rilp, &perso_substate);
app->aid = grilio_parser_get_utf8(rilp);
app->label = grilio_parser_get_utf8(rilp);
if (grilio_parser_get_int32(rilp, &pin_replaced) &&
grilio_parser_get_int32(rilp, &pin1_state) &&
grilio_parser_get_int32(rilp, &pin2_state)) {
app->app_type = app_type;
app->app_state = app_state;
app->perso_substate = perso_substate;
app->pin_replaced = pin_replaced;
app->pin1_state = pin1_state;
app->pin2_state = pin2_state;
return TRUE;
}
return FALSE;
}
static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
guint len)
{
GRilIoParser rilp;
gint32 card_state, pin_state, gsm_umts_index, cdma_index;
gint32 ims_index, num_apps;
grilio_parser_init(&rilp, data, len);
if (!grilio_parser_get_int32(&rilp, &card_state) ||
!grilio_parser_get_int32(&rilp, &pin_state) ||
!grilio_parser_get_int32(&rilp, &gsm_umts_index) ||
!grilio_parser_get_int32(&rilp, &cdma_index) ||
!grilio_parser_get_int32(&rilp, &ims_index) ||
!grilio_parser_get_int32(&rilp, &num_apps)) {
ofono_error("Failed to parse SIM card status request");
return NULL;
} else if (num_apps < 0 || num_apps > RIL_CARD_MAX_APPS) {
ofono_error("Invalid SIM app count %d", num_apps);
return NULL;
} else {
int i;
struct ril_sim_card_status *status =
g_new0(struct ril_sim_card_status, 1);
DBG("card_state=%d, universal_pin_state=%d, gsm_umts_index=%d, "
"cdma_index=%d, ims_index=%d, num_apps=%d",
card_state, pin_state, gsm_umts_index, cdma_index,
ims_index, num_apps);
status->card_state = card_state;
status->pin_state = pin_state;
status->gsm_umts_index = gsm_umts_index;
status->cdma_index = cdma_index;
status->ims_index = ims_index;
status->num_apps = num_apps;
if (num_apps > 0) {
status->apps = g_new0(struct ril_sim_card_app, num_apps);
}
for (i = 0; i < num_apps; i++) {
struct ril_sim_card_app *app = status->apps + i;
if (ril_sim_card_app_parse(&rilp, app)) {
DBG("app[%d]: type=%d, state=%d, "
"perso_substate=%d, aid_ptr=%s, "
"label=%s, pin1_replaced=%d, pin1=%d, "
"pin2=%d", i, app->app_type,
app->app_state, app->perso_substate,
app->aid, app->label,
app->pin_replaced, app->pin1_state,
app->pin2_state);
} else {
break;
}
}
if (i == num_apps) {
return status;
} else {
ril_sim_card_status_free(status);
return NULL;
}
}
}
static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_sim_card *self = user_data;
struct ril_sim_card_priv *priv = self->priv;
GASSERT(priv->status_req_id);
priv->status_req_id = 0;
if (ril_status == RIL_E_SUCCESS) {
struct ril_sim_card_status *status =
ril_sim_card_status_parse(data, len);
if (status) {
ril_sim_card_update_status(self, status);
}
}
}
static void ril_sim_card_request_status(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
if (priv->status_req_id) {
/* Retry right away, don't wait for retry timeout to expire */
grilio_channel_retry_request(priv->io, priv->status_req_id);
} else {
GRilIoRequest* req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
priv->status_req_id = grilio_queue_send_request_full(priv->q,
req, RIL_REQUEST_GET_SIM_STATUS,
ril_sim_card_status_cb, NULL, self);
grilio_request_unref(req);
}
}
static void ril_sim_card_status_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_sim_card *self = user_data;
ril_sim_card_request_status(self);
}
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags)
{
struct ril_sim_card *self = g_object_new(RIL_SIMCARD_TYPE, NULL);
struct ril_sim_card_priv *priv = self->priv;
/*
* We need to know the RIL version (for UICC subscription hack),
* so we must be connected. The caller is supposed to make sure
* that we get connected first.
*/
DBG("%u", slot);
GASSERT(io->connected);
self->slot = slot;
priv->io = grilio_channel_ref(io);
priv->q = grilio_queue_new(io);
priv->flags = flags;
priv->event_id[EVENT_SIM_STATUS_CHANGED] =
grilio_channel_add_unsol_event_handler(priv->io,
ril_sim_card_status_changed,
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, self);
priv->event_id[EVENT_UICC_SUBSCRIPTION_STATUS_CHANGED] =
grilio_channel_add_unsol_event_handler(priv->io,
ril_sim_card_status_changed,
RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, self);
ril_sim_card_request_status(self);
return self;
}
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_SIMCARD(self));
return self;
} else {
return NULL;
}
}
void ril_sim_card_unref(struct ril_sim_card *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_SIMCARD(self));
}
}
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *self,
ril_sim_card_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_STATUS_RECEIVED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_sim_card_add_status_changed_handler(struct ril_sim_card *self,
ril_sim_card_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_STATUS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *self,
ril_sim_card_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *self,
ril_sim_card_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_APP_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
static void ril_sim_card_init(struct ril_sim_card *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIMCARD_TYPE,
struct ril_sim_card_priv);
}
static void ril_sim_card_dispose(GObject *object)
{
struct ril_sim_card *self = RIL_SIMCARD(object);
struct ril_sim_card_priv *priv = self->priv;
grilio_channel_remove_handlers(priv->io, priv->event_id, EVENT_COUNT);
grilio_queue_cancel_all(priv->q, TRUE);
G_OBJECT_CLASS(ril_sim_card_parent_class)->dispose(object);
}
static void ril_sim_card_finalize(GObject *object)
{
struct ril_sim_card *self = RIL_SIMCARD(object);
struct ril_sim_card_priv *priv = self->priv;
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
ril_sim_card_status_free(self->status);
G_OBJECT_CLASS(ril_sim_card_parent_class)->finalize(object);
}
static void ril_sim_card_class_init(RilSimCardClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_sim_card_dispose;
object_class->finalize = ril_sim_card_finalize;
g_type_class_add_private(klass, sizeof(struct ril_sim_card_priv));
ril_sim_card_signals[SIGNAL_STATUS_RECEIVED] =
g_signal_new(SIGNAL_STATUS_RECEIVED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
ril_sim_card_signals[SIGNAL_STATUS_CHANGED] =
g_signal_new(SIGNAL_STATUS_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
ril_sim_card_signals[SIGNAL_STATE_CHANGED] =
g_signal_new(SIGNAL_STATE_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
ril_sim_card_signals[SIGNAL_APP_CHANGED] =
g_signal_new(SIGNAL_APP_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,81 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_SIM_CARD_H
#define RIL_SIM_CARD_H
#include "ril_types.h"
struct ril_sim_card_app {
enum ril_app_type app_type;
enum ril_app_state app_state;
enum ril_perso_substate perso_substate;
char *aid;
char *label;
guint pin_replaced;
enum ril_pin_state pin1_state;
enum ril_pin_state pin2_state;
};
struct ril_sim_card_status {
enum ril_card_state card_state;
enum ril_pin_state pin_state;
int gsm_umts_index;
int cdma_index;
int ims_index;
int num_apps;
struct ril_sim_card_app *apps;
};
struct ril_sim_card {
GObject object;
struct ril_sim_card_priv *priv;
struct ril_sim_card_status *status;
const struct ril_sim_card_app *app;
guint slot;
};
typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
/* Flags for ril_sim_card_new */
#define RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND (0x01)
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);
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
gulong ril_sim_card_add_status_changed_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
/* Inline wrappers */
G_INLINE_FUNC enum ril_app_type
ril_sim_card_app_type(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
#endif /* RIL_SIM_CARD_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_log.h"
#include <ofono/log.h>
#include <ofono/dbus.h>
#include <gdbus.h>
@@ -174,7 +173,7 @@ struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *md)
if (imsi) {
GError *error = NULL;
const struct ril_modem_config *config= ril_modem_config(md);
const struct ril_slot_config *config = &md->config;
struct ril_sim_dbus *dbus = g_new0(struct ril_sim_dbus, 1);
DBG("%s", ril_modem_get_path(md));
@@ -204,7 +203,7 @@ struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *md)
if (g_dbus_register_interface(dbus->conn, dbus->path,
RIL_SIM_DBUS_INTERFACE, ril_sim_dbus_methods,
ril_sim_dbus_signals, NULL, dbus, NULL)) {
ofono_modem_add_interface(ril_modem_ofono_modem(md),
ofono_modem_add_interface(md->ofono,
RIL_SIM_DBUS_INTERFACE);
return dbus;
} else {
@@ -222,7 +221,7 @@ void ril_sim_dbus_free(struct ril_sim_dbus *dbus)
DBG("%s", dbus->path);
g_dbus_unregister_interface(dbus->conn, dbus->path,
RIL_SIM_DBUS_INTERFACE);
ofono_modem_remove_interface(ril_modem_ofono_modem(dbus->md),
ofono_modem_remove_interface(dbus->md->ofono,
RIL_SIM_DBUS_INTERFACE);
dbus_connection_unref(dbus->conn);
g_key_file_free(dbus->storage);

View File

@@ -0,0 +1,55 @@
# This is a sample configuration file for the ril driver
#
# This file is expected to be installed in /etc/ofono
#
# Configuration for each modem is defined in its own [ril_x] section.
# Only the sections that start with the "ril_" prefix define the modems,
# other sections are currently ignored.
#
[ril_0]
# Required entry, defines the RIL socket path
socket=/dev/socket/rild
# Subscription string. Some (mostly, older) RILs require that 4 bytes
# (usually SUB1 or SUB2) are written to the socket before rild starts
# talking to us.
#
# Not sent by default.
#
#sub=SUB1
# RIL logging prefix, to tell one socket from another in the log.
# Makes sense if you have more than one modem configured.
#
# No prefix by default.
#
#name=RIL1
# Slot id for SET_UICC_SUBSCRIPTION request.
#
# By default the first modem becomes slot 0, the next one slot 1 and so on.
#
#slot=0
# RIL request timeout, in milliseconds.
#
# The default is zero (no timeout)
#
#timeout=0
# Setting this one to false would disable 4G technology selection.
#
# By default 4G is enabled
#
#enable4G=true
# RIL_REQUEST_SET_UICC_SUBSCRIPTION is 115 in RIL version 9 (or earlier)
# and 122 in RIL version 10 and later. Since ofono doesn't know in advance
# which RIL version it's dealing with, it makes the decision at runtime.
# Settings it to false disables the workaround and always sends 122.
#
# Default is true (select SET_UICC_SUBSCRIPTION based on the RIL version)
#
#uiccWorkaround=true

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,14 +22,29 @@
#include <grilio_types.h>
#include <gutil_macros.h>
#include <ofono/types.h>
struct ofono_modem;
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ril_constants.h"
#define RIL_RETRY_SECS (2)
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
struct ril_data;
struct ril_modem;
struct ril_radio;
struct ril_network;
struct ril_sim_card;
struct ril_plugin_dbus;
#endif /* RIL_TYPES_H */
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,15 +15,14 @@
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include <grilio_channel.h>
#include <grilio_parser.h>
#include <sys/socket.h>
#include <ctype.h>
#include "common.h"
#include "util.h"
#include "netreg.h"
const char *ril_error_to_string(int error)
{
@@ -300,86 +299,6 @@ int ril_address_family(const char *addr)
}
}
gboolean ril_util_parse_reg(const void *data, guint len,
struct ril_reg_data *reg)
{
GRilIoParser rilp;
int nparams;
gchar *sstatus = NULL, *slac = NULL, *sci = NULL;
gchar *stech = NULL, *sreason = NULL, *smax = NULL;
memset(reg, 0, sizeof(*reg));
/* Size of response string array
*
* Should be:
* >= 4 for VOICE_REG reply
* >= 5 for DATA_REG reply
*/
grilio_parser_init(&rilp, data, len);
if (!grilio_parser_get_int32(&rilp, &nparams) || nparams < 4) {
DBG("broken response");
return FALSE;
}
sstatus = grilio_parser_get_utf8(&rilp);
if (!sstatus) {
DBG("No sstatus value returned!");
return FALSE;
}
slac = grilio_parser_get_utf8(&rilp);
sci = grilio_parser_get_utf8(&rilp);
stech = grilio_parser_get_utf8(&rilp);
nparams -= 4;
reg->ril_status = atoi(sstatus);
if (reg->ril_status > 10) {
reg->status = reg->ril_status - 10;
} else {
reg->status = reg->ril_status;
}
/* FIXME: need to review VOICE_REGISTRATION response
* as it returns ~15 parameters ( vs. 6 for DATA ).
*
* The first four parameters are the same for both
* responses ( although status includes values for
* emergency calls for VOICE response ).
*
* Parameters 5 & 6 have different meanings for
* voice & data response.
*/
if (nparams--) {
/* TODO: different use for CDMA */
sreason = grilio_parser_get_utf8(&rilp);
if (nparams--) {
/* TODO: different use for CDMA */
smax = grilio_parser_get_utf8(&rilp);
if (smax) {
reg->max_calls = atoi(smax);
}
}
}
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
reg->access_tech = ril_parse_tech(stech, &reg->ril_tech);
DBG("%s,%s,%s,%d,%s,%s,%s", registration_status_to_string(reg->status),
slac, sci, reg->ril_tech,
registration_tech_to_string(reg->access_tech),
sreason, smax);
g_free(sstatus);
g_free(slac);
g_free(sci);
g_free(stech);
g_free(sreason);
g_free(smax);
return TRUE;
}
/* Returns enum access_technology or -1 on failure. */
int ril_parse_tech(const char *stech, int *ril_tech)
{
@@ -406,7 +325,6 @@ int ril_parse_tech(const char *stech, int *ril_tech)
break;
case RADIO_TECH_HSPA:
case RADIO_TECH_HSPAP:
case RADIO_TECH_DC_HSDPA:
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
break;
case RADIO_TECH_LTE:
@@ -415,6 +333,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
default:
DBG("Unknown RIL tech %s", stech);
/* no break */
case RADIO_TECH_IWLAN:
case RADIO_TECH_UNKNOWN:
tech = -1;
break;
@@ -427,6 +346,50 @@ int ril_parse_tech(const char *stech, int *ril_tech)
return access_tech;
}
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
{
if (str) {
int i;
const char *ptr = str;
/* Three digit country code */
for (i = 0;
i < OFONO_MAX_MCC_LENGTH && *ptr && isdigit(*ptr);
i++) {
op->mcc[i] = *ptr++;
}
op->mcc[i] = 0;
if (i == OFONO_MAX_MCC_LENGTH) {
/* Usually 2 but sometimes 3 digit network code */
for (i=0;
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
i++) {
op->mnc[i] = *ptr++;
}
op->mnc[i] = 0;
if (i > 0) {
/*
* Sometimes MCC/MNC are followed by + and
* what looks like the technology code. This
* is of course completely undocumented.
*/
if (*ptr == '+') {
int tech = ril_parse_tech(ptr+1, NULL);
if (tech >= 0) {
op->tech = tech;
}
}
return TRUE;
}
}
}
return FALSE;
}
/*
* Local Variables:
* mode: C

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,17 +18,7 @@
#include "ril_types.h"
#include <ofono/log.h>
struct ril_reg_data {
int ril_status;
int ril_tech;
int status; /* enum network_registration_status or -1 if none */
int access_tech; /* enum access_technology or -1 if none */
int lac;
int ci;
int max_calls;
};
struct ofono_network_operator;
const char *ril_error_to_string(int error);
const char *ril_request_to_string(guint request);
@@ -36,8 +26,7 @@ const char *ril_unsol_event_to_string(guint event);
const char *ril_radio_state_to_string(int radio_state);
int ril_parse_tech(const char *stech, int *ril_tech);
int ril_address_family(const char *addr);
gboolean ril_util_parse_reg(const void *data, guint len,
struct ril_reg_data *parsed);
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
#define ril_error_init_ok(err) \
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -175,6 +175,24 @@ static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
return l;
}
/* Valid call statuses have value >= 0 */
static int call_status_with_id(struct ofono_voicecall *vc, int id)
{
GSList *l;
struct voicecall *v;
GASSERT(vc);
for (l = vc->call_list; l; l = l->next) {
v = l->data;
if (v->call->id == id) {
return v->call->status;
}
}
return -1;
}
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
@@ -182,6 +200,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
struct ofono_voicecall *vc = reqdata->vc;
int tmp;
int id = reqdata->id;
int call_status;
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
@@ -197,32 +216,54 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
* protocols", Annex H, are properly reflected in the RIL API.
* For example, cause #21 "call rejected" is mapped to
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
* from a network failure. We signal disconnect reason "remote"
* for cause values
* - #16 "normal call clearing"
* - #17 "user busy"
* - UNSPECIFIED for MO calls that are not yet connected
* , and disconnect reason "network" otherwise.
* from a network failure.
*/
ofono_info("Call %d ended with RIL cause %d", id, last_cause);
if (last_cause == CALL_FAIL_NORMAL || last_cause == CALL_FAIL_BUSY) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
switch (last_cause) {
case CALL_FAIL_UNOBTAINABLE_NUMBER:
case CALL_FAIL_NORMAL:
case CALL_FAIL_BUSY:
case CALL_FAIL_NO_ROUTE_TO_DESTINATION:
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_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_FACILITY_REJECTED:
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
break;
case CALL_FAIL_NORMAL_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
if (call_status == CALL_STATUS_ACTIVE ||
call_status == CALL_STATUS_HELD ||
call_status == CALL_STATUS_DIALING ||
call_status == CALL_STATUS_ALERTING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
} else if (call_status == CALL_STATUS_INCOMING) {
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
}
break;
case CALL_FAIL_ERROR_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
if (call_status == CALL_STATUS_DIALING ||
call_status == CALL_STATUS_ALERTING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
}
break;
default:
reason = OFONO_DISCONNECT_REASON_ERROR;
break;
}
if (last_cause == CALL_FAIL_ERROR_UNSPECIFIED) {
GSList *l;
struct voicecall *v;
for (l = vc->call_list; l; l = l->next) {
v = l->data;
if (v->call->id == id) {
if (v->call->status == CALL_STATUS_DIALING ||
v->call->status == CALL_STATUS_ALERTING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
}
break;
}
}
}
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
id, last_cause, reason);
ofono_voicecall_disconnected(vc, id, reason, NULL);
}

View File

@@ -128,9 +128,8 @@ static void bt_connect(struct dundee_device *device,
if (status == 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
g_free(cbd);
}
struct dundee_device_driver bluetooth_driver = {

View File

@@ -583,7 +583,7 @@ static void have_line(struct at_chat *p, char *str)
return;
/* Check for echo, this should not happen, but lets be paranoid */
if (!strncmp(str, "AT", 2) == TRUE)
if (!strncmp(str, "AT", 2))
goto done;
cmd = g_queue_peek_head(p->command_queue);
@@ -1135,6 +1135,29 @@ static gboolean at_chat_cancel_group(struct at_chat *chat, guint group)
return TRUE;
}
static gpointer at_chat_get_userdata(struct at_chat *chat,
guint group, guint id)
{
GList *l;
struct at_command *c;
if (chat->command_queue == NULL)
return NULL;
l = g_queue_find_custom(chat->command_queue, GUINT_TO_POINTER(id),
at_command_compare_by_id);
if (l == NULL)
return NULL;
c = l->data;
if (c->gid != group)
return NULL;
return c->user_data;
}
static guint at_chat_register(struct at_chat *chat, guint group,
const char *prefix, GAtNotifyFunc func,
gboolean expect_pdu, gpointer user_data,
@@ -1540,6 +1563,14 @@ gboolean g_at_chat_cancel_all(GAtChat *chat)
return at_chat_cancel_group(chat->parent, chat->group);
}
gpointer g_at_chat_get_userdata(GAtChat *chat, guint id)
{
if (chat == NULL)
return NULL;
return at_chat_get_userdata(chat->parent, chat->group, id);
}
guint g_at_chat_register(GAtChat *chat, const char *prefix,
GAtNotifyFunc func, gboolean expect_pdu,
gpointer user_data,

View File

@@ -150,6 +150,8 @@ guint g_at_chat_send_and_expect_short_prompt(GAtChat *chat, const char *cmd,
gboolean g_at_chat_cancel(GAtChat *chat, guint id);
gboolean g_at_chat_cancel_all(GAtChat *chat);
gpointer g_at_chat_get_userdata(GAtChat *chat, guint id);
guint g_at_chat_register(GAtChat *chat, const char *prefix,
GAtNotifyFunc func, gboolean expect_pdu,
gpointer user_data, GDestroyNotify notify);

View File

@@ -64,10 +64,10 @@ gboolean ppp_net_set_mtu(struct ppp_net *net, guint16 mtu)
return FALSE;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, net->if_name, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name, net->if_name, IFNAMSIZ - 1);
ifr.ifr_mtu = mtu;
err = ioctl(sk, SIOCSIFMTU, (caddr_t) &ifr);
err = ioctl(sk, SIOCSIFMTU, (void *) &ifr);
close(sk);

View File

@@ -42,6 +42,7 @@ struct GDBusClient {
DBusConnection *dbus_conn;
char *service_name;
char *base_path;
char *root_path;
guint watch;
guint added_watch;
guint removed_watch;
@@ -1107,7 +1108,11 @@ static void get_managed_objects(GDBusClient *client)
{
DBusMessage *msg;
if (!client->proxy_added && !client->proxy_removed) {
if (!client->connected)
return;
if ((!client->proxy_added && !client->proxy_removed) ||
!client->root_path) {
refresh_properties(client);
return;
}
@@ -1115,9 +1120,10 @@ static void get_managed_objects(GDBusClient *client)
if (client->get_objects_call != NULL)
return;
msg = dbus_message_new_method_call(client->service_name, "/",
DBUS_INTERFACE_DBUS ".ObjectManager",
"GetManagedObjects");
msg = dbus_message_new_method_call(client->service_name,
client->root_path,
DBUS_INTERFACE_OBJECT_MANAGER,
"GetManagedObjects");
if (msg == NULL)
return;
@@ -1142,13 +1148,13 @@ static void service_connect(DBusConnection *conn, void *user_data)
g_dbus_client_ref(client);
client->connected = TRUE;
if (client->connect_func)
client->connect_func(conn, client->connect_data);
get_managed_objects(client);
client->connected = TRUE;
g_dbus_client_unref(client);
}
@@ -1156,13 +1162,13 @@ static void service_disconnect(DBusConnection *conn, void *user_data)
{
GDBusClient *client = user_data;
client->connected = FALSE;
g_list_free_full(client->proxy_list, proxy_free);
client->proxy_list = NULL;
if (client->disconn_func) {
if (client->disconn_func)
client->disconn_func(conn, client->disconn_data);
client->connected = FALSE;
}
}
static DBusHandlerResult message_filter(DBusConnection *connection,
@@ -1195,11 +1201,19 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
GDBusClient *g_dbus_client_new(DBusConnection *connection,
const char *service, const char *path)
{
return g_dbus_client_new_full(connection, service, path, "/");
}
GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
const char *service,
const char *path,
const char *root_path)
{
GDBusClient *client;
unsigned int i;
if (connection == NULL)
if (!connection || !service)
return NULL;
client = g_try_new0(GDBusClient, 1);
@@ -1215,6 +1229,7 @@ GDBusClient *g_dbus_client_new(DBusConnection *connection,
client->dbus_conn = dbus_connection_ref(connection);
client->service_name = g_strdup(service);
client->base_path = g_strdup(path);
client->root_path = g_strdup(root_path);
client->connected = FALSE;
client->match_rules = g_ptr_array_sized_new(1);
@@ -1224,14 +1239,18 @@ GDBusClient *g_dbus_client_new(DBusConnection *connection,
service_connect,
service_disconnect,
client, NULL);
if (!root_path)
return g_dbus_client_ref(client);
client->added_watch = g_dbus_add_signal_watch(connection, service,
"/",
client->root_path,
DBUS_INTERFACE_OBJECT_MANAGER,
"InterfacesAdded",
interfaces_added,
client, NULL);
client->removed_watch = g_dbus_add_signal_watch(connection, service,
"/",
client->root_path,
DBUS_INTERFACE_OBJECT_MANAGER,
"InterfacesRemoved",
interfaces_removed,
@@ -1305,6 +1324,7 @@ void g_dbus_client_unref(GDBusClient *client)
g_free(client->service_name);
g_free(client->base_path);
g_free(client->root_path);
g_free(client);
}
@@ -1371,7 +1391,8 @@ gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
client->property_changed = property_changed;
client->user_data = user_data;
get_managed_objects(client);
if (proxy_added || proxy_removed || property_changed)
get_managed_objects(client);
return TRUE;
}

View File

@@ -216,6 +216,7 @@ struct GDBusSecurityTable {
.flags = G_DBUS_SIGNAL_FLAG_EXPERIMENTAL
void g_dbus_set_flags(int flags);
int g_dbus_get_flags(void);
gboolean g_dbus_register_interface(DBusConnection *connection,
const char *path, const char *name,
@@ -355,6 +356,10 @@ gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
GDBusClient *g_dbus_client_new(DBusConnection *connection,
const char *service, const char *path);
GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
const char *service,
const char *path,
const char *root_path);
GDBusClient *g_dbus_client_ref(GDBusClient *client);
void g_dbus_client_unref(GDBusClient *client);

View File

@@ -322,6 +322,7 @@ DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
return NULL;
if (setup_bus(conn, name, error) == FALSE) {
dbus_connection_close(conn);
dbus_connection_unref(conn);
return NULL;
}

View File

@@ -1412,7 +1412,10 @@ DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
{
char str[1024];
vsnprintf(str, sizeof(str), format, args);
if (format)
vsnprintf(str, sizeof(str), format, args);
else
str[0] = '\0';
return dbus_message_new_error(message, name, str);
}
@@ -1530,11 +1533,8 @@ gboolean g_dbus_send_error_valist(DBusConnection *connection,
const char *format, va_list args)
{
DBusMessage *error;
char str[1024];
vsnprintf(str, sizeof(str), format, args);
error = dbus_message_new_error(message, name, str);
error = g_dbus_create_error_valist(message, name, format, args);
if (error == NULL)
return FALSE;
@@ -1816,3 +1816,8 @@ void g_dbus_set_flags(int flags)
{
global_flags = flags;
}
int g_dbus_get_flags(void)
{
return global_flags;
}

View File

@@ -523,7 +523,7 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
member = dbus_message_get_member(message);
dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
/* Sender is always the owner */
/* If sender != NULL it is always the owner */
for (current = listeners; current != NULL; current = current->next) {
data = current->data;
@@ -531,19 +531,24 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
if (connection != data->connection)
continue;
if (data->owner && g_strcmp0(sender, data->owner) != 0)
if (!sender && data->owner)
continue;
if (data->path && g_strcmp0(path, data->path) != 0)
if (data->owner && g_str_equal(sender, data->owner) == FALSE)
continue;
if (data->interface && g_strcmp0(iface, data->interface) != 0)
if (data->path && g_str_equal(path, data->path) == FALSE)
continue;
if (data->member && g_strcmp0(member, data->member) != 0)
if (data->interface && g_str_equal(iface,
data->interface) == FALSE)
continue;
if (data->argument && g_strcmp0(arg, data->argument) != 0)
if (data->member && g_str_equal(member, data->member) == FALSE)
continue;
if (data->argument && g_str_equal(arg,
data->argument) == FALSE)
continue;
if (data->handle_func) {

View File

@@ -101,6 +101,8 @@ struct ofono_modem *ofono_gprs_context_get_modem(struct ofono_gprs_context *gc);
void ofono_gprs_context_set_type(struct ofono_gprs_context *gc,
enum ofono_gprs_context_type type);
enum ofono_gprs_context_type ofono_gprs_context_get_type(
struct ofono_gprs_context *gc);
void ofono_gprs_context_set_interface(struct ofono_gprs_context *gc,
const char *interface);

View File

@@ -61,6 +61,8 @@ void ofono_gprs_suspend_notify(struct ofono_gprs *gprs, int cause);
void ofono_gprs_resume_notify(struct ofono_gprs *gprs);
void ofono_gprs_bearer_notify(struct ofono_gprs *gprs, int bearer);
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs);
int ofono_gprs_driver_register(const struct ofono_gprs_driver *d);
void ofono_gprs_driver_unregister(const struct ofono_gprs_driver *d);
@@ -78,7 +80,6 @@ void ofono_gprs_set_cid_range(struct ofono_gprs *gprs,
void ofono_gprs_add_context(struct ofono_gprs *gprs,
struct ofono_gprs_context *gc);
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs);
ofono_bool_t ofono_gprs_get_roaming_allowed(struct ofono_gprs *gprs);
#ifdef __cplusplus

View File

@@ -41,6 +41,7 @@ struct ofono_handsfree_card_driver {
void (*connect)(struct ofono_handsfree_card *card,
ofono_handsfree_card_connect_cb_t cb,
void *data);
void (*sco_connected_hint)(struct ofono_handsfree_card *card);
};
struct ofono_handsfree_card *ofono_handsfree_card_create(unsigned int vendor,

View File

@@ -133,6 +133,9 @@ void ofono_radio_settings_remove(struct ofono_radio_settings *rs);
void ofono_radio_settings_set_data(struct ofono_radio_settings *rs, void *data);
void *ofono_radio_settings_get_data(struct ofono_radio_settings *rs);
struct ofono_modem *ofono_radio_settings_get_modem(
struct ofono_radio_settings *rs);
#ifdef __cplusplus
}
#endif

View File

@@ -83,6 +83,12 @@ struct ofono_error {
#define OFONO_MAX_PHONE_NUMBER_LENGTH 80
#define OFONO_MAX_CALLER_NAME_LENGTH 80
/* Number types, 3GPP TS 24.008 subclause 10.5.4.7, octect 3 */
/* Unknown, ISDN numbering plan */
#define OFONO_NUMBER_TYPE_UNKNOWN 129
/* International, ISDN numbering plan */
#define OFONO_NUMBER_TYPE_INTERNATIONAL 145
struct ofono_phone_number {
char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 1];
int type;

View File

@@ -52,23 +52,25 @@
#include <ofono/gprs.h>
#include <ofono/gprs-context.h>
static int tc65_probe(struct ofono_modem *modem)
#include <drivers/atmodem/vendor.h>
static int cinterion_probe(struct ofono_modem *modem)
{
return 0;
}
static void tc65_remove(struct ofono_modem *modem)
static void cinterion_remove(struct ofono_modem *modem)
{
}
static void tc65_debug(const char *str, void *user_data)
static void cinterion_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
ofono_info("%s%s", prefix, str);
}
static int tc65_enable(struct ofono_modem *modem)
static int cinterion_enable(struct ofono_modem *modem)
{
GAtChat *chat;
GIOChannel *channel;
@@ -102,7 +104,10 @@ static int tc65_enable(struct ofono_modem *modem)
return -EIO;
/*
* TC65 works almost as the 27.007 says. But for example after
* (Cinterion plugin is based on tc65 plugin. Comment left in but may
* not be applicable in the general case)
*
* TC65 works almost as the 27.007 says. But for example after
* AT+CRSM the modem replies with the data in the queried EF and
* writes three pairs of <CR><LF> after the data and before OK.
*/
@@ -116,14 +121,14 @@ static int tc65_enable(struct ofono_modem *modem)
return -ENOMEM;
if (getenv("OFONO_AT_DEBUG"))
g_at_chat_set_debug(chat, tc65_debug, "");
g_at_chat_set_debug(chat, cinterion_debug, "");
ofono_modem_set_data(modem, chat);
return 0;
}
static int tc65_disable(struct ofono_modem *modem)
static int cinterion_disable(struct ofono_modem *modem)
{
GAtChat *chat = ofono_modem_get_data(modem);
@@ -149,7 +154,7 @@ static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
cb(&error, cbd->data);
}
static void tc65_set_online(struct ofono_modem *modem, ofono_bool_t online,
static void cinterion_set_online(struct ofono_modem *modem, ofono_bool_t online,
ofono_modem_online_cb_t cb, void *user_data)
{
GAtChat *chat = ofono_modem_get_data(modem);
@@ -161,12 +166,12 @@ static void tc65_set_online(struct ofono_modem *modem, ofono_bool_t online,
if (g_at_chat_send(chat, command, NULL, set_online_cb, cbd, g_free))
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, cbd->data);
g_free(cbd);
}
static void tc65_pre_sim(struct ofono_modem *modem)
static void cinterion_pre_sim(struct ofono_modem *modem)
{
GAtChat *chat = ofono_modem_get_data(modem);
struct ofono_sim *sim;
@@ -181,7 +186,7 @@ static void tc65_pre_sim(struct ofono_modem *modem)
ofono_sim_inserted_notify(sim, TRUE);
}
static void tc65_post_sim(struct ofono_modem *modem)
static void cinterion_post_sim(struct ofono_modem *modem)
{
GAtChat *chat = ofono_modem_get_data(modem);
@@ -192,7 +197,7 @@ static void tc65_post_sim(struct ofono_modem *modem)
ofono_sms_create(modem, 0, "atmodem", chat);
}
static void tc65_post_online(struct ofono_modem *modem)
static void cinterion_post_online(struct ofono_modem *modem)
{
GAtChat *chat = ofono_modem_get_data(modem);
struct ofono_message_waiting *mw;
@@ -204,7 +209,7 @@ static void tc65_post_online(struct ofono_modem *modem)
ofono_ussd_create(modem, 0, "atmodem", chat);
ofono_call_forwarding_create(modem, 0, "atmodem", chat);
ofono_call_settings_create(modem, 0, "atmodem", chat);
ofono_netreg_create(modem, 0, "atmodem", chat);
ofono_netreg_create(modem, OFONO_VENDOR_CINTERION, "atmodem", chat);
ofono_call_meter_create(modem, 0, "atmodem", chat);
ofono_call_barring_create(modem, 0, "atmodem", chat);
@@ -219,27 +224,27 @@ static void tc65_post_online(struct ofono_modem *modem)
ofono_message_waiting_register(mw);
}
static struct ofono_modem_driver tc65_driver = {
.name = "tc65",
.probe = tc65_probe,
.remove = tc65_remove,
.enable = tc65_enable,
.disable = tc65_disable,
.set_online = tc65_set_online,
.pre_sim = tc65_pre_sim,
.post_sim = tc65_post_sim,
.post_online = tc65_post_online,
static struct ofono_modem_driver cinterion_driver = {
.name = "cinterion",
.probe = cinterion_probe,
.remove = cinterion_remove,
.enable = cinterion_enable,
.disable = cinterion_disable,
.set_online = cinterion_set_online,
.pre_sim = cinterion_pre_sim,
.post_sim = cinterion_post_sim,
.post_online = cinterion_post_online,
};
static int tc65_init(void)
static int cinterion_init(void)
{
return ofono_modem_driver_register(&tc65_driver);
return ofono_modem_driver_register(&cinterion_driver);
}
static void tc65_exit(void)
static void cinterion_exit(void)
{
ofono_modem_driver_unregister(&tc65_driver);
ofono_modem_driver_unregister(&cinterion_driver);
}
OFONO_PLUGIN_DEFINE(tc65, "Cinterion TC65 driver plugin", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT, tc65_init, tc65_exit)
OFONO_PLUGIN_DEFINE(cinterion, "Cinterion driver plugin", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT, cinterion_init, cinterion_exit)

View File

@@ -70,6 +70,7 @@ struct hfp {
struct hfp_slc_info info;
DBusMessage *msg;
struct ofono_handsfree_card *card;
unsigned int bcc_id;
};
static const char *none_prefix[] = { NULL };
@@ -373,8 +374,12 @@ static void bcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_handsfree_card_connect_cb_t cb = cbd->cb;
struct ofono_handsfree_card *card = cbd->user;
struct hfp *hfp = ofono_handsfree_card_get_data(card);
struct ofono_error error;
hfp->bcc_id = 0;
decode_at_error(&error, g_at_result_final_response(result));
cb(&error, cbd->data);
@@ -391,7 +396,10 @@ static void hfp16_card_connect(struct ofono_handsfree_card *card,
info->ag_features & HFP_AG_FEATURE_CODEC_NEGOTIATION) {
struct cb_data *cbd = cb_data_new(cb, data);
g_at_chat_send(info->chat, "AT+BCC", NULL, bcc_cb, cbd, g_free);
cbd->user = card;
hfp->bcc_id = g_at_chat_send(info->chat, "AT+BCC",
none_prefix, bcc_cb,
cbd, g_free);
return;
}
@@ -404,11 +412,40 @@ static void hfp16_card_connect(struct ofono_handsfree_card *card,
ofono_handsfree_card_connect_sco(card);
}
static void hfp16_sco_connected_hint(struct ofono_handsfree_card *card)
{
struct hfp *hfp = ofono_handsfree_card_get_data(card);
struct hfp_slc_info *info = &hfp->info;
struct cb_data *cbd;
ofono_handsfree_card_connect_cb_t cb;
/*
* SCO has just been connected, probably initiated by the AG.
* If we have any outstanding BCC requests, then lets cancel these
* as they're no longer needed
*/
if (hfp->bcc_id == 0)
return;
cbd = g_at_chat_get_userdata(info->chat, hfp->bcc_id);
if (cbd == NULL)
return;
cb = cbd->cb;
CALLBACK_WITH_SUCCESS(cb, cbd->data);
/* cbd will be freed once cancel is processed */
g_at_chat_cancel(info->chat, hfp->bcc_id);
hfp->bcc_id = 0;
}
static struct ofono_handsfree_card_driver hfp16_hf_driver = {
.name = HFP16_HF_DRIVER,
.probe = hfp16_card_probe,
.remove = hfp16_card_remove,
.connect = hfp16_card_connect,
.name = HFP16_HF_DRIVER,
.probe = hfp16_card_probe,
.remove = hfp16_card_remove,
.connect = hfp16_card_connect,
.sco_connected_hint = hfp16_sco_connected_hint,
};
static ofono_bool_t device_path_compare(struct ofono_modem *modem,
@@ -702,8 +739,17 @@ static void modem_register_from_proxy(GDBusProxy *proxy, const char *path)
return;
dbus_message_iter_get_basic(&iter, &paired);
if (paired == FALSE)
if (paired == FALSE) {
modem = ofono_modem_find(device_path_compare, (void *) path);
if (modem != NULL) {
ofono_modem_remove(modem);
g_dbus_proxy_set_removed_watch(proxy, NULL, NULL);
g_dbus_proxy_set_property_watch(proxy, NULL, NULL);
}
return;
}
if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
return;

View File

@@ -204,7 +204,7 @@ static void reachable_cb(const GIsiMessage *msg, void *data)
struct ofono_modem *om = data;
struct isi_data *isi = ofono_modem_get_data(om);
if (!g_isi_msg_error(msg) < 0)
if (g_isi_msg_error(msg) < 0)
return;
ISI_RESOURCE_DBG(msg);

View File

@@ -238,7 +238,7 @@ static void mtc_reachable_cb(const GIsiMessage *msg, void *data)
struct ofono_modem *modem = data;
struct isi_data *isi = ofono_modem_get_data(modem);
if (!g_isi_msg_error(msg) < 0)
if (g_isi_msg_error(msg) < 0)
return;
ISI_RESOURCE_DBG(msg);

View File

@@ -41,7 +41,7 @@
#define PUSH_NOTIFICATION_INTERFACE "org.ofono.PushNotification"
#define AGENT_INTERFACE "org.ofono.PushNotificationAgent"
#define WAP_PUSH_SRC_PORT 9200
#define WAP_PUSH_SRC_PORT -1
#define WAP_PUSH_DST_PORT 2948
static unsigned int modemwatch_id;
@@ -50,21 +50,16 @@ struct push_notification {
struct ofono_modem *modem;
struct ofono_sms *sms;
struct sms_agent *agent;
unsigned int push_watch[2];
unsigned int push_watch;
};
static void agent_exited(void *userdata)
{
struct push_notification *pn = userdata;
if (pn->push_watch[0] > 0) {
__ofono_sms_datagram_watch_remove(pn->sms, pn->push_watch[0]);
pn->push_watch[0] = 0;
}
if (pn->push_watch[1] > 0) {
__ofono_sms_datagram_watch_remove(pn->sms, pn->push_watch[1]);
pn->push_watch[1] = 0;
if (pn->push_watch > 0) {
__ofono_sms_datagram_watch_remove(pn->sms, pn->push_watch);
pn->push_watch = 0;
}
pn->agent = NULL;
@@ -113,17 +108,12 @@ static DBusMessage *push_notification_register_agent(DBusConnection *conn,
sms_agent_set_removed_notify(pn->agent, agent_exited, pn);
pn->push_watch[0] = __ofono_sms_datagram_watch_add(pn->sms,
pn->push_watch = __ofono_sms_datagram_watch_add(pn->sms,
push_received,
WAP_PUSH_DST_PORT,
WAP_PUSH_SRC_PORT,
pn, NULL);
pn->push_watch[1] = __ofono_sms_datagram_watch_add(pn->sms,
push_received,
WAP_PUSH_DST_PORT,
0, pn, NULL);
return dbus_message_new_method_return(msg);
}
@@ -166,8 +156,7 @@ static void push_notification_cleanup(gpointer user)
DBG("%p", pn);
/* The push watch was already cleaned up */
pn->push_watch[0] = 0;
pn->push_watch[1] = 0;
pn->push_watch = 0;
pn->sms = NULL;
sms_agent_free(pn->agent);

View File

@@ -48,6 +48,8 @@ static const char *none_prefix[] = { NULL };
struct sierra_data {
GAtChat *modem;
gboolean have_sim;
struct at_util_sim_state_query *sim_state_query;
};
static void sierra_debug(const char *str, void *user_data)
@@ -80,6 +82,9 @@ static void sierra_remove(struct ofono_modem *modem)
ofono_modem_set_data(modem, NULL);
/* Cleanup potential SIM state polling */
at_util_sim_state_query_free(data->sim_state_query);
/* Cleanup after hot-unplug */
g_at_chat_unref(data->modem);
@@ -119,6 +124,21 @@ static GAtChat *open_device(struct ofono_modem *modem,
return chat;
}
static void sim_state_cb(gboolean present, gpointer user_data)
{
struct ofono_modem *modem = user_data;
struct sierra_data *data = ofono_modem_get_data(modem);
DBG("%p", modem);
at_util_sim_state_query_free(data->sim_state_query);
data->sim_state_query = NULL;
data->have_sim = present;
ofono_modem_set_powered(modem, TRUE);
}
static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
@@ -131,7 +151,9 @@ static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
data->modem = NULL;
}
ofono_modem_set_powered(modem, ok);
data->sim_state_query = at_util_sim_state_query_new(data->modem,
2, 20, sim_state_cb, modem,
NULL);
}
static int sierra_enable(struct ofono_modem *modem)
@@ -222,7 +244,7 @@ static void sierra_pre_sim(struct ofono_modem *modem)
sim = ofono_sim_create(modem, OFONO_VENDOR_SIERRA,
"atmodem", data->modem);
if (sim)
if (sim && data->have_sim == TRUE)
ofono_sim_inserted_notify(sim, TRUE);
}

View File

@@ -423,9 +423,8 @@ static void ste_set_online(struct ofono_modem *modem, ofono_bool_t online,
if (g_at_chat_send(chat, command, NULL, set_online_cb, cbd, g_free))
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, cbd->data);
g_free(cbd);
}
static void ste_pre_sim(struct ofono_modem *modem)

View File

@@ -232,7 +232,7 @@ static void reachable_cb(const GIsiMessage *msg, void *data)
struct ofono_modem *om = data;
struct isi_data *isi = ofono_modem_get_data(om);
if (!g_isi_msg_error(msg) < 0)
if (g_isi_msg_error(msg) < 0)
return;
ISI_RESOURCE_DBG(msg);

View File

@@ -192,7 +192,7 @@ static void add_wavecom(struct ofono_modem *modem,
ofono_modem_register(modem);
}
static void add_tc65(struct ofono_modem *modem,
static void add_cinterion(struct ofono_modem *modem,
struct udev_device *udev_device)
{
const char *devnode;
@@ -243,6 +243,11 @@ static void add_modem(struct udev_device *udev_device)
if (devpath == NULL)
return;
if(g_strcmp0(driver, "tc65") == 0)
driver = "cinterion";
if(g_strcmp0(driver, "ehs6") == 0)
driver = "cinterion";
modem = ofono_modem_create(NULL, driver);
if (modem == NULL)
return;
@@ -305,8 +310,8 @@ done:
add_isi(modem, udev_device);
else if (g_strcmp0(driver, "calypso") == 0)
add_calypso(modem, udev_device);
else if (g_strcmp0(driver, "tc65") == 0)
add_tc65(modem, udev_device);
else if (g_strcmp0(driver, "cinterion") == 0)
add_cinterion(modem, udev_device);
else if (g_strcmp0(driver, "nokiacdma") == 0)
add_nokiacdma(modem, udev_device);
else if (g_strcmp0(driver, "sim900") == 0)

View File

@@ -117,6 +117,8 @@ static gboolean setup_mbm(struct modem_info *modem)
gps = info->devnode;
} else if (g_str_has_suffix(info->sysattr,
"Network Adapter") == TRUE ||
g_str_has_suffix(info->sysattr,
"gw") == TRUE ||
g_str_has_suffix(info->sysattr,
"NetworkAdapter") == TRUE) {
network = info->devnode;
@@ -1078,14 +1080,19 @@ static struct {
{ "icera", "cdc_ether", "0421", "0633" },
{ "mbm", "cdc_acm", "0bdb" },
{ "mbm", "cdc_ether", "0bdb" },
{ "mbm", "cdc_ncm", "0bdb" },
{ "mbm", "cdc_acm", "0fce" },
{ "mbm", "cdc_ether", "0fce" },
{ "mbm", "cdc_ncm", "0fce" },
{ "mbm", "cdc_acm", "413c" },
{ "mbm", "cdc_ether", "413c" },
{ "mbm", "cdc_ncm", "413c" },
{ "mbm", "cdc_acm", "03f0" },
{ "mbm", "cdc_ether", "03f0" },
{ "mbm", "cdc_ncm", "03f0" },
{ "mbm", "cdc_acm", "0930" },
{ "mbm", "cdc_ether", "0930" },
{ "mbm", "cdc_ncm", "0930" },
{ "hso", "hso" },
{ "gobi", "qmi_wwan" },
{ "gobi", "qcserial" },

View File

@@ -1029,11 +1029,14 @@ out:
/*
* In order to minimize signal transmissions we wait about X seconds
* before reseting the base station id. The hope is that we receive
* before resetting the base station id. The hope is that we receive
* another cell broadcast with the new base station name within
* that time
*/
if (lac_changed || ci_changed) {
if(cbs->reset_source)
g_source_remove(cbs->reset_source);
cbs->reset_source =
g_timeout_add_seconds(3, reset_base_station_name, cbs);
}

View File

@@ -89,7 +89,7 @@ static void cdma_connman_ifupdown(const char *interface, ofono_bool_t active)
return;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, interface, IFNAMSIZ);
strncpy(ifr.ifr_name, interface, IFNAMSIZ - 1);
if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0)
goto done;

View File

@@ -41,6 +41,14 @@ enum network_registration_status {
NETWORK_REGISTRATION_STATUS_ROAMING = 5,
};
/* 27.007 Section 7.3 <stat> */
enum operator_status {
OPERATOR_STATUS_UNKNOWN = 0,
OPERATOR_STATUS_AVAILABLE = 1,
OPERATOR_STATUS_CURRENT = 2,
OPERATOR_STATUS_FORBIDDEN = 3,
};
/* 27.007 Section 7.6 */
enum clip_validity {
CLIP_VALIDITY_VALID = 0,
@@ -48,6 +56,18 @@ enum clip_validity {
CLIP_VALIDITY_NOT_AVAILABLE = 2,
};
/* 27.007 Section 7.29 */
enum packet_bearer {
PACKET_BEARER_NONE = 0,
PACKET_BEARER_GPRS = 1,
PACKET_BEARER_EGPRS = 2,
PACKET_BEARER_UMTS = 3,
PACKET_BEARER_HSUPA = 4,
PACKET_BEARER_HSDPA = 5,
PACKET_BEARER_HSUPA_HSDPA = 6,
PACKET_BEARER_EPS = 7,
};
/* 27.007 Section 7.30 */
enum cnap_validity {
CNAP_VALIDITY_VALID = 0,

View File

@@ -60,18 +60,6 @@
#define MAX_MMS_MTU 1280
#define MAX_GPRS_MTU 1280
/* 27.007 Section 7.29 */
enum packet_bearer {
PACKET_BEARER_NONE = 0,
PACKET_BEARER_GPRS = 1,
PACKET_BEARER_EGPRS = 2,
PACKET_BEARER_UMTS = 3,
PACKET_BEARER_HSUPA = 4,
PACKET_BEARER_HSDPA = 5,
PACKET_BEARER_HSUPA_HSDPA = 6,
PACKET_BEARER_EPS = 7,
};
struct ofono_gprs {
GSList *contexts;
ofono_bool_t attached;
@@ -1889,6 +1877,8 @@ static void gprs_netreg_update(struct ofono_gprs *gprs)
attach = attach && gprs->powered;
DBG("attach: %u, driver_attached: %u", attach, gprs->driver_attached);
if (gprs->driver_attached == attach)
return;
@@ -1899,8 +1889,8 @@ static void gprs_netreg_update(struct ofono_gprs *gprs)
gprs->flags |= GPRS_FLAG_ATTACHING;
gprs->driver->set_attached(gprs, attach, gprs_attach_callback, gprs);
gprs->driver_attached = attach;
gprs->driver->set_attached(gprs, attach, gprs_attach_callback, gprs);
}
static void netreg_status_changed(int status, int lac, int ci, int tech,
@@ -1911,9 +1901,6 @@ static void netreg_status_changed(int status, int lac, int ci, int tech,
DBG("%d", status);
if (gprs->netreg_status == status)
return;
gprs->netreg_status = status;
gprs_netreg_update(gprs);
@@ -2123,6 +2110,36 @@ static struct pri_context *add_context(struct ofono_gprs *gprs,
return context;
}
static void send_context_added_signal(struct ofono_gprs *gprs,
struct pri_context *context,
DBusConnection *conn)
{
const char *path;
DBusMessage *signal;
DBusMessageIter iter;
DBusMessageIter dict;
path = __ofono_atom_get_path(gprs->atom);
signal = dbus_message_new_signal(path,
OFONO_CONNECTION_MANAGER_INTERFACE,
"ContextAdded");
if (!signal)
return;
dbus_message_iter_init_append(signal, &iter);
path = context->path;
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
OFONO_PROPERTIES_ARRAY_SIGNATURE,
&dict);
append_context_properties(context, &dict);
dbus_message_iter_close_container(&iter, &dict);
g_dbus_send_message(conn, signal);
}
static DBusMessage *gprs_add_context(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -2132,7 +2149,6 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
const char *name;
const char *path;
enum ofono_gprs_context_type type;
DBusMessage *signal;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &typestr,
DBUS_TYPE_INVALID))
@@ -2154,29 +2170,7 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
g_dbus_send_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
path = __ofono_atom_get_path(gprs->atom);
signal = dbus_message_new_signal(path,
OFONO_CONNECTION_MANAGER_INTERFACE,
"ContextAdded");
if (signal) {
DBusMessageIter iter;
DBusMessageIter dict;
dbus_message_iter_init_append(signal, &iter);
path = context->path;
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
&path);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
OFONO_PROPERTIES_ARRAY_SIGNATURE,
&dict);
append_context_properties(context, &dict);
dbus_message_iter_close_container(&iter, &dict);
g_dbus_send_message(conn, signal);
}
send_context_added_signal(gprs, context, conn);
return NULL;
}
@@ -2411,6 +2405,196 @@ static DBusMessage *gprs_get_contexts(DBusConnection *conn,
return reply;
}
static void provision_context(const struct ofono_gprs_provision_data *ap,
struct ofono_gprs *gprs)
{
unsigned int id;
struct pri_context *context = NULL;
/* Sanity check */
if (ap == NULL)
return;
if (ap->name && strlen(ap->name) > MAX_CONTEXT_NAME_LENGTH)
return;
if (ap->apn == NULL || strlen(ap->apn) > OFONO_GPRS_MAX_APN_LENGTH)
return;
if (is_valid_apn(ap->apn) == FALSE)
return;
if (ap->username &&
strlen(ap->username) > OFONO_GPRS_MAX_USERNAME_LENGTH)
return;
if (ap->password &&
strlen(ap->password) > OFONO_GPRS_MAX_PASSWORD_LENGTH)
return;
if (ap->message_proxy &&
strlen(ap->message_proxy) > MAX_MESSAGE_PROXY_LENGTH)
return;
if (ap->message_center &&
strlen(ap->message_center) > MAX_MESSAGE_CENTER_LENGTH)
return;
if (gprs->last_context_id)
id = idmap_alloc_next(gprs->pid_map, gprs->last_context_id);
else
id = idmap_alloc(gprs->pid_map);
if (id > idmap_get_max(gprs->pid_map))
return;
context = pri_context_create(gprs, ap->name, ap->type);
if (context == NULL) {
idmap_put(gprs->pid_map, id);
return;
}
context->id = id;
if (ap->username != NULL)
strcpy(context->context.username, ap->username);
if (ap->password != NULL)
strcpy(context->context.password, ap->password);
context->context.auth_method = ap->auth_method;
strcpy(context->context.apn, ap->apn);
context->context.proto = ap->proto;
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
if (ap->message_proxy != NULL)
strcpy(context->message_proxy, ap->message_proxy);
if (ap->message_center != NULL)
strcpy(context->message_center, ap->message_center);
}
if (context_dbus_register(context) == FALSE)
return;
gprs->last_context_id = id;
if (gprs->settings) {
write_context_settings(gprs, context);
storage_sync(gprs->imsi, SETTINGS_STORE, gprs->settings);
}
gprs->contexts = g_slist_append(gprs->contexts, context);
}
static void provision_contexts(struct ofono_gprs *gprs, const char *mcc,
const char *mnc, const char *spn)
{
struct ofono_gprs_provision_data *settings;
int count;
int i;
if (__ofono_gprs_provision_get_settings(mcc, mnc, spn,
&settings, &count) == FALSE) {
ofono_warn("Provisioning failed");
return;
}
for (i = 0; i < count; i++)
provision_context(&settings[i], gprs);
__ofono_gprs_provision_free_settings(settings, count);
}
static void remove_non_active_context(struct ofono_gprs *gprs,
struct pri_context *ctx, DBusConnection *conn)
{
char *path;
const char *atompath;
if (gprs->settings) {
g_key_file_remove_group(gprs->settings, ctx->key, NULL);
storage_sync(gprs->imsi, SETTINGS_STORE, gprs->settings);
}
/* Make a backup copy of path for signal emission below */
path = g_strdup(ctx->path);
context_dbus_unregister(ctx);
gprs->contexts = g_slist_remove(gprs->contexts, ctx);
atompath = __ofono_atom_get_path(gprs->atom);
g_dbus_emit_signal(conn, atompath, OFONO_CONNECTION_MANAGER_INTERFACE,
"ContextRemoved", DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
g_free(path);
}
static DBusMessage *gprs_reset_contexts(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ofono_gprs *gprs = data;
struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom);
struct ofono_sim *sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
DBusMessage *reply;
GSList *l;
if (gprs->pending)
return __ofono_error_busy(msg);
/*
* We want __ofono_error_busy to take precedence over
* __ofono_error_not_allowed errors, so we check it first.
*/
for (l = gprs->contexts; l; l = l->next) {
struct pri_context *ctx = l->data;
if (ctx->pending)
return __ofono_error_busy(msg);
}
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID))
return __ofono_error_invalid_args(msg);
if (gprs->powered)
return __ofono_error_not_allowed(msg);
for (l = gprs->contexts; l; l = l->next) {
struct pri_context *ctx = l->data;
if (ctx->active)
return __ofono_error_not_allowed(msg);
}
reply = dbus_message_new_method_return(msg);
if (reply == NULL)
return NULL;
/* Remove first the current contexts, re-provision after */
while (gprs->contexts != NULL) {
struct pri_context *ctx = gprs->contexts->data;
remove_non_active_context(gprs, ctx, conn);
}
gprs->last_context_id = 0;
provision_contexts(gprs, ofono_sim_get_mcc(sim),
ofono_sim_get_mnc(sim), ofono_sim_get_spn(sim));
if (gprs->contexts == NULL) /* Automatic provisioning failed */
add_context(gprs, NULL, OFONO_GPRS_CONTEXT_TYPE_INTERNET);
for (l = gprs->contexts; l; l = l->next) {
struct pri_context *ctx = l->data;
send_context_added_signal(gprs, ctx, conn);
}
return reply;
}
static const GDBusMethodTable manager_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
@@ -2430,6 +2614,8 @@ static const GDBusMethodTable manager_methods[] = {
{ GDBUS_METHOD("GetContexts", NULL,
GDBUS_ARGS({ "contexts_with_properties", "a(oa{sv})" }),
gprs_get_contexts) },
{ GDBUS_ASYNC_METHOD("ResetContexts", NULL, NULL,
gprs_reset_contexts) },
{ }
};
@@ -2437,7 +2623,7 @@ static const GDBusSignalTable manager_signals[] = {
{ GDBUS_SIGNAL("PropertyChanged",
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
{ GDBUS_SIGNAL("ContextAdded",
GDBUS_ARGS({ "path", "o" }, { "properties", "v" })) },
GDBUS_ARGS({ "path", "o" }, { "properties", "a{sv}" })) },
{ GDBUS_SIGNAL("ContextRemoved", GDBUS_ARGS({ "path", "o" })) },
{ }
};
@@ -2725,6 +2911,12 @@ void ofono_gprs_context_set_type(struct ofono_gprs_context *gc,
gc->type = type;
}
enum ofono_gprs_context_type ofono_gprs_context_get_type(
struct ofono_gprs_context *gc)
{
return gc->type;
}
void ofono_gprs_context_set_interface(struct ofono_gprs_context *gc,
const char *interface)
{
@@ -3234,108 +3426,6 @@ remove:
storage_sync(imsi, SETTINGS_STORE, gprs->settings);
}
static void provision_context(const struct ofono_gprs_provision_data *ap,
struct ofono_gprs *gprs)
{
unsigned int id;
struct pri_context *context = NULL;
/* Sanity check */
if (ap == NULL)
return;
if (ap->name && strlen(ap->name) > MAX_CONTEXT_NAME_LENGTH)
return;
if (ap->apn == NULL || strlen(ap->apn) > OFONO_GPRS_MAX_APN_LENGTH)
return;
if (is_valid_apn(ap->apn) == FALSE)
return;
if (ap->username &&
strlen(ap->username) > OFONO_GPRS_MAX_USERNAME_LENGTH)
return;
if (ap->password &&
strlen(ap->password) > OFONO_GPRS_MAX_PASSWORD_LENGTH)
return;
if (ap->message_proxy &&
strlen(ap->message_proxy) > MAX_MESSAGE_PROXY_LENGTH)
return;
if (ap->message_center &&
strlen(ap->message_center) > MAX_MESSAGE_CENTER_LENGTH)
return;
if (gprs->last_context_id)
id = idmap_alloc_next(gprs->pid_map, gprs->last_context_id);
else
id = idmap_alloc(gprs->pid_map);
if (id > idmap_get_max(gprs->pid_map))
return;
context = pri_context_create(gprs, ap->name, ap->type);
if (context == NULL) {
idmap_put(gprs->pid_map, id);
return;
}
context->id = id;
if (ap->username != NULL)
strcpy(context->context.username, ap->username);
if (ap->password != NULL)
strcpy(context->context.password, ap->password);
context->context.auth_method = ap->auth_method;
strcpy(context->context.apn, ap->apn);
context->context.proto = ap->proto;
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
if (ap->message_proxy != NULL)
strcpy(context->message_proxy, ap->message_proxy);
if (ap->message_center != NULL)
strcpy(context->message_center, ap->message_center);
}
if (context_dbus_register(context) == FALSE)
return;
gprs->last_context_id = id;
if (gprs->settings) {
write_context_settings(gprs, context);
storage_sync(gprs->imsi, SETTINGS_STORE, gprs->settings);
}
gprs->contexts = g_slist_append(gprs->contexts, context);
}
static void provision_contexts(struct ofono_gprs *gprs, const char *mcc,
const char *mnc, const char *spn)
{
struct ofono_gprs_provision_data *settings;
int count;
int i;
if (__ofono_gprs_provision_get_settings(mcc, mnc, spn,
&settings, &count) == FALSE) {
ofono_warn("Provisioning failed");
return;
}
for (i = 0; i < count; i++)
provision_context(&settings[i], gprs);
__ofono_gprs_provision_free_settings(settings, count);
}
static void ofono_gprs_finish_register(struct ofono_gprs *gprs)
{
DBusConnection *conn = ofono_dbus_get_connection();
@@ -3422,6 +3512,11 @@ static void spn_read_cb(const char *spn, const char *dc, void *data)
ofono_gprs_finish_register(gprs);
}
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs)
{
return __ofono_atom_get_modem(gprs->atom);
}
void ofono_gprs_register(struct ofono_gprs *gprs)
{
struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom);
@@ -3457,11 +3552,6 @@ void *ofono_gprs_get_data(struct ofono_gprs *gprs)
return gprs->driver_data;
}
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs)
{
return __ofono_atom_get_modem(gprs->atom);
}
ofono_bool_t ofono_gprs_get_roaming_allowed(struct ofono_gprs *gprs)
{
return gprs->roaming_allowed;

View File

@@ -101,6 +101,8 @@ static void send_new_connection(const char *card, int fd, uint8_t codec)
DBusMessage *msg;
DBusMessageIter iter;
DBG("%p, fd: %d, codec: %hu", card, fd, codec);
msg = dbus_message_new_method_call(agent->owner, agent->path,
HFP_AUDIO_AGENT_INTERFACE, "NewConnection");
if (msg == NULL)
@@ -183,9 +185,15 @@ static gboolean sco_accept(GIOChannel *io, GIOCondition cond,
return TRUE;
}
DBG("SCO connection setup between local: %s and remote: %s",
local, remote);
send_new_connection(card->path, nsk, card->selected_codec);
close(nsk);
if (card->driver->sco_connected_hint)
card->driver->sco_connected_hint(card);
return TRUE;
}
@@ -845,6 +853,8 @@ void ofono_handsfree_audio_ref(void)
if (ref_count != 1)
return;
__ofono_handsfree_audio_manager_init();
if (!g_dbus_register_interface(ofono_dbus_get_connection(),
OFONO_MANAGER_PATH,
HFP_AUDIO_MANAGER_INTERFACE,
@@ -873,6 +883,8 @@ void ofono_handsfree_audio_unref(void)
agent_release(agent);
agent_free(agent);
}
__ofono_handsfree_audio_manager_cleanup();
}
int __ofono_handsfree_audio_manager_init(void)
@@ -882,15 +894,11 @@ int __ofono_handsfree_audio_manager_init(void)
void __ofono_handsfree_audio_manager_cleanup(void)
{
if (ref_count == 0)
if (ref_count != 0)
return;
ofono_error("Handsfree Audio manager not cleaned up properly,"
"fixing...");
ref_count = 1;
ofono_handsfree_audio_unref();
if (sco_watch > 0)
if (sco_watch > 0) {
g_source_remove(sco_watch);
sco_watch = 0;
}
}

View File

@@ -72,7 +72,11 @@ struct ofono_handsfree {
static const char **ag_features_list(unsigned int features,
unsigned int chld_features)
{
static const char *list[10];
/*
* BRSF response is a 32-bit unsigned int. Only 32 entries are posible,
* and we do not ever report the presence of bit 8.
*/
static const char *list[32];
unsigned int i = 0;
if (features & HFP_AG_FEATURE_3WAY)
@@ -602,7 +606,7 @@ static DBusMessage *handsfree_request_phone_number(DBusConnection *conn,
}
static const GDBusMethodTable handsfree_methods[] = {
{ GDBUS_METHOD("GetProperties",
{ GDBUS_ASYNC_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
handsfree_get_properties) },
{ GDBUS_ASYNC_METHOD("SetProperty",

View File

@@ -30,7 +30,9 @@
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#ifdef __GLIBC__
#include <execinfo.h>
#endif
#include <dlfcn.h>
#include "ofono.h"
@@ -113,6 +115,7 @@ void ofono_debug(const char *format, ...)
va_end(ap);
}
#ifdef __GLIBC__
static void print_backtrace(unsigned int offset)
{
void *frames[99];
@@ -240,6 +243,7 @@ static void signal_setup(sighandler_t handler)
sigaction(SIGABRT, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
}
#endif
extern struct ofono_debug_desc __start___debug[];
extern struct ofono_debug_desc __stop___debug[];
@@ -311,8 +315,10 @@ int __ofono_log_init(const char *program, const char *debug,
if (detach == FALSE)
option |= LOG_PERROR;
#ifdef __GLIBC__
if (backtrace == TRUE)
signal_setup(signal_handler);
#endif
openlog(basename(program), option, LOG_DAEMON);
@@ -327,8 +333,10 @@ void __ofono_log_cleanup(ofono_bool_t backtrace)
closelog();
#ifdef __GLIBC__
if (backtrace == TRUE)
signal_setup(SIG_DFL);
#endif
g_strfreev(enabled);
}

View File

@@ -244,12 +244,6 @@ int main(int argc, char **argv)
__ofono_manager_init();
/*
* BT HFP SCO socket creation moved to Bluez5 plugin.
* Bluez4 handles the SCO socket, it will conflict with oFono.
*/
//__ofono_handsfree_audio_manager_init();
__ofono_plugin_init(option_plugin, option_noplugin);
g_free(option_plugin);
@@ -259,8 +253,6 @@ int main(int argc, char **argv)
__ofono_plugin_cleanup();
//__ofono_handsfree_audio_manager_cleanup(); See comment above
__ofono_manager_cleanup();
__ofono_modemwatch_cleanup();

View File

@@ -481,7 +481,7 @@ static void mw_mwis_read_cb(int ok, int total_length, int record,
status = data[0];
data++;
for (i = 0; i < 5 && i < record_length - 1; i++) {
for (i = 0; i < 5 && i < record_length - 1; i++, data++) {
info.indication = (status >> i) & 1;
info.message_count = info.indication ? data[0] : 0;
@@ -732,6 +732,7 @@ static void mw_set_indicator(struct ofono_message_waiting *mw, int profile,
efmwis[i + 1] = mw->messages[i].message_count;
/* Fill in indicator state bits in byte 0 */
efmwis[0] = 0;
for (i = 0; i < 5 && i < mw->efmwis_length - 1; i++)
if (mw->messages[i].indication)
efmwis[0] |= 1 << i;

View File

@@ -2144,6 +2144,9 @@ void ofono_modem_reset(struct ofono_modem *modem)
if (err == -EINPROGRESS)
return;
if (err < 0)
return;
modem_change_state(modem, MODEM_STATE_PRE_SIM);
}

View File

@@ -50,14 +50,6 @@ enum network_registration_mode {
NETWORK_REGISTRATION_MODE_AUTO_ONLY = 5, /* Out of range of 27.007 */
};
/* 27.007 Section 7.3 <stat> */
enum operator_status {
OPERATOR_STATUS_UNKNOWN = 0,
OPERATOR_STATUS_AVAILABLE = 1,
OPERATOR_STATUS_CURRENT = 2,
OPERATOR_STATUS_FORBIDDEN = 3,
};
struct ofono_netreg {
int status;
int location;
@@ -718,6 +710,7 @@ static gboolean update_operator_list(struct ofono_netreg *netreg, int total,
GSList *o;
GSList *compressed;
GSList *c;
struct network_operator_data *current_op = NULL;
gboolean changed = FALSE;
compressed = compress_operator_list(list, total);
@@ -762,8 +755,19 @@ static gboolean update_operator_list(struct ofono_netreg *netreg, int total,
if (netreg->operator_list)
changed = TRUE;
for (o = netreg->operator_list; o; o = o->next)
network_operator_dbus_unregister(netreg, o->data);
for (o = netreg->operator_list; o; o = o->next) {
struct network_operator_data *op = o->data;
if (op != op->netreg->current_operator)
network_operator_dbus_unregister(netreg, op);
else
current_op = op;
}
if (current_op) {
n = g_slist_prepend(n, current_op);
netreg->operator_list =
g_slist_remove(netreg->operator_list, current_op);
}
g_slist_free(netreg->operator_list);

View File

@@ -8,7 +8,7 @@ Type=dbus
BusName=org.ofono
User=root
EnvironmentFile=-/var/lib/environment/ofono/*.conf
ExecStart=@prefix@/sbin/ofonod -n --nobacktrace $OFONO_ARGS
ExecStart=@prefix@/sbin/ofonod -n --nobacktrace $OFONO_ARGS $OFONO_DEBUG
StandardError=null
Restart=always
RestartSec=3

View File

@@ -40,6 +40,7 @@ static GSList *g_drivers = NULL;
struct ofono_radio_settings {
DBusMessage *pending;
GSList *pending_get_prop;
int flags;
enum ofono_radio_access_mode mode;
enum ofono_radio_band_gsm band_gsm;
@@ -387,14 +388,35 @@ static void radio_mode_set_callback(const struct ofono_error *error, void *data)
radio_set_rat_mode(rs, rs->pending_mode);
}
static void radio_send_properties_reply(struct ofono_radio_settings *rs)
static void radio_send_properties_ok(gpointer data, gpointer user_data)
{
DBusMessage *reply;
DBusMessage *msg = data;
struct ofono_radio_settings *rs = user_data;
DBusMessage *reply = radio_get_properties_reply(msg, rs);
__ofono_dbus_pending_reply(&msg, reply);
}
static void radio_send_properties_error(gpointer data, gpointer user_data)
{
DBusMessage *msg = data;
DBusMessage *reply = __ofono_error_failed(msg);
__ofono_dbus_pending_reply(&msg, reply);
}
static void radio_send_properties_reply(struct ofono_radio_settings *rs,
GFunc func)
{
g_slist_foreach(rs->pending_get_prop, func, rs);
g_slist_free(rs->pending_get_prop);
rs->pending_get_prop = NULL;
}
static void radio_send_properties_reply_ok(struct ofono_radio_settings *rs)
{
rs->flags |= RADIO_SETTINGS_FLAG_CACHED;
reply = radio_get_properties_reply(rs->pending, rs);
__ofono_dbus_pending_reply(&rs->pending, reply);
radio_send_properties_reply(rs, radio_send_properties_ok);
}
static void radio_available_rats_query_callback(const struct ofono_error *error,
@@ -408,14 +430,14 @@ static void radio_available_rats_query_callback(const struct ofono_error *error,
else
DBG("Error while querying available rats");
radio_send_properties_reply(rs);
radio_send_properties_reply_ok(rs);
}
static void radio_query_available_rats(struct ofono_radio_settings *rs)
{
/* Modem technology is not supposed to change, so one query is enough */
if (rs->driver->query_available_rats == NULL || rs->available_rats) {
radio_send_properties_reply(rs);
radio_send_properties_reply_ok(rs);
return;
}
@@ -427,14 +449,11 @@ static void radio_fast_dormancy_query_callback(const struct ofono_error *error,
ofono_bool_t enable, void *data)
{
struct ofono_radio_settings *rs = data;
DBusMessage *reply;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error during fast dormancy query");
reply = __ofono_error_failed(rs->pending);
__ofono_dbus_pending_reply(&rs->pending, reply);
radio_send_properties_reply(rs, radio_send_properties_error);
return;
}
@@ -459,14 +478,11 @@ static void radio_band_query_callback(const struct ofono_error *error,
void *data)
{
struct ofono_radio_settings *rs = data;
DBusMessage *reply;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error during radio frequency band query");
reply = __ofono_error_failed(rs->pending);
__ofono_dbus_pending_reply(&rs->pending, reply);
radio_send_properties_reply(rs, radio_send_properties_error);
return;
}
@@ -492,14 +508,11 @@ static void radio_rat_mode_query_callback(const struct ofono_error *error,
void *data)
{
struct ofono_radio_settings *rs = data;
DBusMessage *reply;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error during radio access mode query");
reply = __ofono_error_failed(rs->pending);
__ofono_dbus_pending_reply(&rs->pending, reply);
radio_send_properties_reply(rs, radio_send_properties_error);
return;
}
@@ -518,11 +531,15 @@ static DBusMessage *radio_get_properties(DBusConnection *conn,
if (rs->driver->query_rat_mode == NULL)
return __ofono_error_not_implemented(msg);
if (rs->pending)
return __ofono_error_busy(msg);
rs->pending = dbus_message_ref(msg);
rs->driver->query_rat_mode(rs, radio_rat_mode_query_callback, rs);
if (rs->pending_get_prop) {
rs->pending_get_prop = g_slist_append(rs->pending_get_prop,
dbus_message_ref(msg));
} else {
rs->pending_get_prop = g_slist_append(NULL,
dbus_message_ref(msg));
rs->driver->query_rat_mode(rs, radio_rat_mode_query_callback,
rs);
}
return NULL;
}
@@ -688,6 +705,13 @@ void ofono_radio_settings_driver_unregister(const struct ofono_radio_settings_dr
g_drivers = g_slist_remove(g_drivers, (void *) d);
}
static void radio_settings_cancel_get_properties(gpointer data)
{
DBusMessage *msg = data;
__ofono_dbus_pending_reply(&msg, __ofono_error_canceled(msg));
}
static void radio_settings_unregister(struct ofono_atom *atom)
{
struct ofono_radio_settings *rs = __ofono_atom_get_data(atom);
@@ -695,6 +719,12 @@ static void radio_settings_unregister(struct ofono_atom *atom)
DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = __ofono_atom_get_modem(rs->atom);
if (rs->pending_get_prop) {
g_slist_free_full(rs->pending_get_prop,
radio_settings_cancel_get_properties);
rs->pending_get_prop = NULL;
}
ofono_modem_remove_interface(modem, OFONO_RADIO_SETTINGS_INTERFACE);
g_dbus_unregister_interface(conn, path, OFONO_RADIO_SETTINGS_INTERFACE);
}
@@ -785,3 +815,9 @@ void *ofono_radio_settings_get_data(struct ofono_radio_settings *rs)
{
return rs->driver_data;
}
struct ofono_modem *ofono_radio_settings_get_modem(
struct ofono_radio_settings *rs)
{
return __ofono_atom_get_modem(rs->atom);
}

View File

@@ -2504,16 +2504,9 @@ void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
sim_inserted_update(sim);
call_state_watches(sim);
if (inserted)
if (inserted) {
sim_initialize(sim);
else {
/*
* Reset type to trigger property change signal after sim is
* removed and inserted.
* Can't reset in sim_free_main_state because it's called also
* when sim state changes to OFONO_SIM_STATE_LOCKED_OUT
* (PUK lock) if user fails to change PIN.
*/
} else {
sim->pin_type = OFONO_SIM_PASSWORD_NONE;
sim_free_state(sim);
@@ -2802,6 +2795,7 @@ static void sim_pin_query_cb(const struct ofono_error *error,
g_strfreev(locked_pins);
}
}
ofono_dbus_signal_property_changed(conn, path,
OFONO_SIM_MANAGER_INTERFACE,
"PinRequired", DBUS_TYPE_STRING,

View File

@@ -1195,6 +1195,7 @@ static void dispatch_app_datagram(struct ofono_sms *sms,
ofono_sms_datagram_notify_cb_t notify;
struct sms_handler *h;
GSList *l;
gboolean dispatched = FALSE;
ts = sms_scts_to_time(scts, &remote);
localtime_r(&ts, &local);
@@ -1206,9 +1207,15 @@ static void dispatch_app_datagram(struct ofono_sms *sms,
if (!port_equal(dst, h->dst) || !port_equal(src, h->src))
continue;
dispatched = TRUE;
notify(sender, &remote, &local, dst, src, buf, len,
h->item.notify_data);
}
if (!dispatched)
ofono_info("Datagram with ports [%d,%d] not delivered",
dst, src);
}
static void dispatch_text_message(struct ofono_sms *sms,

View File

@@ -1946,9 +1946,6 @@ static gboolean extract_app_port_common(struct sms_udh_iter *iter, int *dst,
if (((addr_hdr[0] << 8) | addr_hdr[1]) > 49151)
break;
if (((addr_hdr[2] << 8) | addr_hdr[3]) > 49151)
break;
dstport = (addr_hdr[0] << 8) | addr_hdr[1];
srcport = (addr_hdr[2] << 8) | addr_hdr[3];
is_addr_8bit = FALSE;

View File

@@ -1534,6 +1534,9 @@ static int voicecall_dial(struct ofono_voicecall *vc, const char *number,
if (g_slist_length(vc->call_list) >= MAX_VOICE_CALLS)
return -EPERM;
if (valid_ussd_string(number, vc->call_list != NULL))
return -EINVAL;
if (!valid_long_phone_number_format(number))
return -EINVAL;
@@ -2777,16 +2780,25 @@ static void emulator_hfp_unregister(struct ofono_atom *atom)
struct ofono_voicecall *vc = __ofono_atom_get_data(atom);
struct ofono_modem *modem = __ofono_atom_get_modem(atom);
struct emulator_status data;
data.vc = vc;
data.status = OFONO_EMULATOR_CALL_INACTIVE;
__ofono_modem_foreach_registered_atom(modem,
OFONO_ATOM_TYPE_EMULATOR_HFP,
emulator_call_status_cb, 0);
emulator_call_status_cb, &data);
data.status = OFONO_EMULATOR_CALLSETUP_INACTIVE;
__ofono_modem_foreach_registered_atom(modem,
OFONO_ATOM_TYPE_EMULATOR_HFP,
emulator_callsetup_status_cb,
0);
&data);
data.status = OFONO_EMULATOR_CALLHELD_NONE;
__ofono_modem_foreach_registered_atom(modem,
OFONO_ATOM_TYPE_EMULATOR_HFP,
emulator_callheld_status_cb, 0);
emulator_callheld_status_cb,
&data);
__ofono_modem_foreach_registered_atom(modem,
OFONO_ATOM_TYPE_EMULATOR_HFP,

20
ofono/test/reset-contexts Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/python3
import dbus
import 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("Resetting contexts for SIM on modem %s..." % path)
cm = dbus.Interface(bus.get_object('org.ofono', path),
'org.ofono.ConnectionManager')
cm.ResetContexts()

View File

@@ -10,6 +10,7 @@ Source0: http://www.kernel.org/pub/linux/network/ofono/ofono-%{version}.tar.x
Requires: dbus
Requires: systemd
Requires: ofono-configs
Requires: libgrilio >= 1.0.6
Requires(preun): systemd
Requires(post): systemd
Requires(postun): systemd
@@ -20,7 +21,7 @@ BuildRequires: pkgconfig(bluez) >= 4.85
BuildRequires: pkgconfig(mobile-broadband-provider-info)
BuildRequires: pkgconfig(libwspcodec) >= 2.0
BuildRequires: pkgconfig(libglibutil)
BuildRequires: pkgconfig(libgrilio)
BuildRequires: pkgconfig(libgrilio) >= 1.0.6
BuildRequires: libtool
BuildRequires: automake
BuildRequires: autoconf

20
test/reset-contexts Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/python3
import dbus
import 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("Resetting contexts for SIM on modem %s..." % path)
cm = dbus.Interface(bus.get_object('org.ofono', path),
'org.ofono.ConnectionManager')
cm.ResetContexts()