Compare commits

...

140 Commits

Author SHA1 Message Date
Slava Monich
cbd32e5aaa [ril] Query available band modes at startup. Contributes to JB#35461 2016-08-19 15:54:17 +03:00
Slava Monich
baa4fe30e5 Merge branch 'master' into 'master'
Ensure /var/lib/ofono exists on package.

Directory wasn't being created with new automake.

Makefile.am includes:

statedir = $(localstatedir)/lib/ofono
state_DATA =

Suspect newer just skips it as empty. mkdir should be a safe workaround.

See merge request !69
2016-07-04 16:58:03 +00:00
Slava Monich
d0d0793ccb Merge branch 'allow-data' into 'master'
Add allowDataReq ril_subscription.conf option

That fixes Nexus 5 port. Tested by community.

See merge request !70
2016-07-04 16:56:21 +00:00
Slava Monich
55dd461ce7 [ril] Allow to specify default values in Settings section of ril_subscription.conf
Those will become default for all modems but still can be overwritten in
per-modem config sections.
2016-07-03 16:18:48 +03:00
Slava Monich
4da1a30290 [ril] Added allowDataReq ril_subscription.conf option. Fixes MER#1613
Set to true if your RIL doesn't support RIL_REQUEST_ALLOW_DATA
2016-07-02 14:17:06 +03:00
Slava Monich
303f527d79 [ofono] Deleted obsolete debuglog-api.txt 2016-06-28 14:13:05 +03:00
Pekka Vuorela
27e8621c0b [ofono] Ensure /var/lib/ofono exists on package. Contributes to JB#35132 2016-06-16 15:47:44 +03:00
Slava Monich
200237372a Merge branch 'jb35406' into 'master'
Retry data call on PDP_FAIL_ERROR_UNSPECIFIED

According to comment in android's ril.h, if data call setup fails
with status PDP_FAIL_ERROR_UNSPECIFIED, then we need to silently
retry the call. Let's do that.

See merge request !68
2016-06-07 11:27:31 +00:00
Slava Monich
9cae262c80 [ril] Retry data call on PDP_FAIL_ERROR_UNSPECIFIED. Fixes JB#35406
According to comment in android's ril.h, if data call setup fails
with status PDP_FAIL_ERROR_UNSPECIFIED, then we need to silently
retry the call.
2016-06-07 11:23:49 +03:00
Slava Monich
5e23459b67 Merge branch 'debuglog' into 'master'
Control ofono logging over D-Bus

The previous solution only allowed switching logs on/off, this one
allows to pipe the log to another process.

See merge request !67
2016-05-30 20:29:56 +00:00
Slava Monich
a88d7af6c8 Merge branch 'dtmf' into 'master'
Fix memory trashing after sending DTMF tone

After a DTMF tone was sent,tone_queue buffer was becoming just
a few bytes long but the code kept on assuming that it's still
pointing to at least MAX_DTMF_BUFFER bytes of memory. Under
valgrind it looked like this:

==3914== Invalid write of size 1
==3914==    at 0x4B01AEE: g_strlcat (gstrfuncs.c:1488)
==3914==    by 0x33645: ril_voicecall_send_dtmf (ril_voicecall.c:639)
==3914==    by 0x7EE4B: tone_request_run (voicecall.c:4001)
==3914==    by 0x4AE5B57: g_timeout_dispatch (gmain.c:4577)
==3914==    by 0x4AE521B: g_main_dispatch (gmain.c:3154)
==3914==    by 0x4AE521B: g_main_context_dispatch (gmain.c:3769)
==3914==    by 0x4AE54C9: g_main_context_iterate.isra.4 (gmain.c:3840)
==3914==    by 0x4AE573B: g_main_loop_run (gmain.c:4034)
==3914==    by 0x1F0AF: main (main.c:252)
==3914==  Address 0x591c361 is 0 bytes after a block of size 1 alloc'd
==3914==    at 0x483F380: malloc (vg_replace_malloc.c:296)
==3914==    by 0x4AEA26F: g_malloc (gmem.c:94)
==3914==    by 0x4B0130D: g_strdup (gstrfuncs.c:363)
==3914==    by 0x336AB: ril_voicecall_send_dtmf_cb (ril_voicecall.c:600)
==3914==    by 0x489F679: grilio_channel_handle_packet (grilio_channel.c:711)
==3914==    by 0x489F679: grilio_channel_read (grilio_channel.c:811)
==3914==    by 0x489F679: grilio_channel_read_callback (grilio_channel.c:824)
==3914==    by 0x4AE521B: g_main_dispatch (gmain.c:3154)
==3914==    by 0x4AE521B: g_main_context_dispatch (gmain.c:3769)
==3914==    by 0x4AE54C9: g_main_context_iterate.isra.4 (gmain.c:3840)
==3914==    by 0x4AE573B: g_main_loop_run (gmain.c:4034)
==3914==    by 0x1F0AF: main (main.c:252)

This patch replaces tone_queue with a FIFO ring buffer.

See merge request !66
2016-05-30 19:56:28 +00:00
Slava Monich
290c3d2388 [ofono] Control ofono logging over D-Bus. Contributes to JB#34874
The previous solution only allowed switching logs on/off, this one
allows to pipe the log to another process.
2016-05-30 19:00:42 +03:00
Slava Monich
ee880398ad [ril] Fix memory trashing after sending DTMF tone. Fixes JB#35384 2016-05-30 16:18:23 +03:00
Slava Monich
d65bbc3236 Merge branch 'jb35249' into 'master'
Fix crash on exit if data call setup is pending

See merge request !65
2016-05-17 13:57:18 +00:00
Slava Monich
655544be45 [ril] Fix crash on exit if data call setup is pending. Fixes JB#35249
When context is being removed, the core has already completed its
pending D-Bus request, invoking the completion callback causes
libdbus to panic.
2016-05-16 18:04:34 +03:00
Slava Monich
50a544a191 Merge branch 'default-proto' into 'master'
Use the right data protocol for default context settings

Follow-up to mer-core/ofono!60

See merge request !64
2016-05-14 08:42:27 +00:00
Slava Monich
9e7a4a4d72 [ofono] Use the right data protocol for default context settings. Contributes to JB#32750 2016-05-14 11:40:38 +03:00
Slava Monich
c5b5e3109d Merge branch 'ackretry' into 'master'
Retry RIL_REQUEST_SMS_ACKNOWLEDGE

People report seeing `SMS acknowledgement failed: Further SMS
reception is not guaranteed` message in the log, when they have
some sort of trouble with SMS. Let's see if retry helps.

See merge request !63
2016-04-23 15:48:20 +00:00
Slava Monich
deb106343a [ril] Retry RIL_REQUEST_SMS_ACKNOWLEDGE. Contributes to JB#34851
People report seeing "SMS acknowledgement failed: Further SMS reception
is not guaranteed" message in the log, when they have some sort of trouble
with SMS. Let's see if retry helps.
2016-04-23 12:21:23 +03:00
Slava Monich
771e8becf2 Merge branch 'imei' into 'master'
Fix IMEI query at startup.

See merge request !62
2016-04-22 08:56:45 +00:00
Slava Monich
a0b69f974a [ril] Fixed IMEI query at startup. Fixes JB#34937
IMEI related queries were being completed too early.
2016-04-21 12:25:58 +03:00
Slava Monich
b3a4aaea95 [ofono] Silence "Interface xxx not found on the interface_list" messages
Attempt to remove a modem interface already removed (internally) by ofono
is not an error.
2016-04-20 12:22:33 +03:00
Slava Monich
137e504e10 Merge branch 'jb34928' into 'master'
Prevent crash in ril_delayed_register

See merge request !61
2016-04-19 12:18:32 +00:00
Slava Monich
2de3e445f0 Merge branch 'ipv4v6' into 'master'
Use IPV4V6 for internet contexts by default

Once the packet data protocol is configured, it's saved in the
config file and can be changed via UI. In other words, default
value only affects first-time configuration (i.e. provisioning)
and "Reset to default" function.

See merge request !60
2016-04-19 12:17:57 +00:00
Slava Monich
1cd0d60768 [ril] Prevent crash in ril_delayed_register. Fixes JB#34928
Delayed registration needs to be cancelled by ril_phonebook_remove
if it (registration) hasn't been done yet.
2016-04-19 00:41:33 +03:00
Slava Monich
d1f1f16355 [ofono] Use IPV4V6 (dual) for internet context by default. Fixes JB#32750 2016-04-18 18:59:09 +03:00
Slava Monich
4df72c9376 [ofono] mbpi: Make default packet data protocol configurable. Contributes to JB#32750
Note that according to TS 23.401, UE which is IPv6 and IPv4 capable
should request IPv4v6.
2016-04-18 18:53:50 +03:00
Slava Monich
a35ca2bbd9 [ofono] mbpi: Make MBPI database file configurable at runtime
Useful for provisioning unit tests, if nothing else.
2016-04-18 18:53:28 +03:00
Slava Monich
8376174c76 Merge branch 'oemraw' into 'master'
See merge request !59
2016-04-15 16:12:38 +00:00
Slava Monich
b6f5befcac [ril] Simplify OemRaw D-Bus interface implementation
Since support for this interface has never been merged upstream (and
most likely never will) there is no need to touch ofono core at all.
Moving everything into RIL plugin simplifies the implementation and
allows to delete a few hundred lines of unnecessary code.
2016-04-14 19:03:57 +03:00
Slava Monich
403f29320c [mbpi] Housekeeping 2016-04-13 17:51:32 +03:00
Slava Monich
54209b39bd Merge branch 'jb34842' into 'master'
See merge request !58
2016-04-12 06:48:00 +00:00
Slava Monich
3ca442ad15 [ril] Avoid double completion of data call deactivation requests. Fixes JB#34842
The core expects no more than one completion of each request.
2016-04-11 16:48:40 +03:00
Slava Monich
3a579dd7be [ril] CellInfo D-Bus API optimization. Contributes to JB#34561
As an optimization, CellAdded and CellRemoved signals are replaced with
CellsAdded and CellsRemoved which bring array of paths as a parameter.
Cells typically appear/disappear in bunches.
2016-04-06 11:20:32 +03:00
Slava Monich
a7266fc9c8 [ril] Reset the list of known cells when modem is powered off. Fixes JB#34745 2016-04-05 17:05:31 +03:00
Slava Monich
04dbd344b3 [ril] Unregister cells when removing CellInfo interface 2016-04-05 16:14:39 +03:00
Slava Monich
296534c2a8 Merge branch 'voicecall' into 'master'
Make sure that we don't complete dial request more than once

See merge request !55
2016-03-29 10:26:20 +00:00
Slava Monich
6114482e2a Merge branch 'wait' into 'master'
Startup issues

On some devices, it takes rild some time to become functional.
During that time, it fails many requests, including some critical
ones. For example, RIL_REQUEST_GET_IMSI failure results in
"Unable to read IMSI, emergency calls only" error.

RIL plugin has to retry critical requests to stop ofono from
getting into a non-functional state.

See merge request !54
2016-03-29 10:25:14 +00:00
Slava Monich
8281885ba5 Merge branch 'spn' into 'master'
See merge request !53
2016-03-29 10:22:50 +00:00
Slava Monich
9cd3b84421 [ril] Make sure that we don't complete dial request more than once. Fixes JB#34670 2016-03-27 17:50:57 +03:00
Slava Monich
8d65aaefed [ril] Cache SPN when registered with the home network. Contributes to JB#34131
Some SIM cards don't have EFspn record, i.e. we have no way of knowing the
service provider name. In that happens to be the case, then let's cache
the operator name when we are connected to the home network and use that
as the service provider name. That's a pretty accurate guess.
2016-03-25 18:55:24 +02:00
Slava Monich
ce15cfe48d [ril] Don't register modem until RIL_REQUEST_GET_IMEI completes. MER#1549
Waiting until rild responds to RIL_REQUEST_GET_IMEI (and retrying
the request on failure) gives rild time to finish whatever it's doing
during initialization.
2016-03-25 12:52:14 +02:00
Slava Monich
3a1e37b498 [ril] Retry RIL_REQUEST_GET_IMSI. MER#1549
If we fail the .read_imsi call, ofono gets into "Unable to read IMSI,
emergency calls only" state.
2016-03-25 12:49:35 +02:00
Slava Monich
ecef97dd83 [ril] Retry RIL_REQUEST_SIGNAL_STRENGTH 2016-03-25 12:17:54 +02:00
Slava Monich
a68f1e9c4d [ril] Retry RIL_REQUEST_GET_CURRENT_CALLS 2016-03-25 12:12:30 +02:00
Slava Monich
42808ed0f7 Merge branch 'cellinfo' into 'master'
Add cell info interfaces

See merge request !52
2016-03-24 11:48:37 +00:00
Slava Monich
d896ebcb37 [ril] Added cell info interfaces. Contributes to JB#34561
org.nemomobile.ofono.CellInfo is the modem interface:

    <interface name="org.nemomobile.ofono.CellInfo">
        <method name="GetCells">
            <arg name="paths" type="ao" direction="out"/>
        </method>
        <signal name="CellAdded">
            <arg name="path" type="o"/>
        </signal>
        <signal name="CellRemoved">
            <arg name="path" type="o"/>
        </signal>
    </interface>

and each cell supports org.nemomobile.ofono.Cell interface:

    <interface name="org.nemomobile.ofono.Cell">
        <method name="GetAll">
            <arg name="version" type="i" direction="out"/>
            <arg name="type" type="s" direction="out"/>
            <arg name="registered" type="b" direction="out"/>
            <arg name="properties" type="a{sv}" direction="out"/>
        </method>
        <method name="GetInterfaceVersion">
            <arg name="version" type="i" direction="out"/>
        </method>
        <method name="GetType">
            <arg name="type" type="s" direction="out"/>
        </method>
        <method name="GetRegistered">
            <arg name="registered" type="b" direction="out"/>
        </method>
        <method name="GetProperties">
            <arg name="properties" type="a{sv}" direction="out"/>
        </method>
        <signal name="RegisteredChanged">
            <arg name="registered" type="b"/>
        </signal>
        <signal name="PropertyChanged">
            <arg name="name" type="s"/>
            <arg name="value" type="v"/>
        </signal>
        <signal name="Removed"/>
    </interface>

Supported cell types are "gsm", "wcdma" and "lte", the set of properties
depends on the cell type:

gsm:   mcc,mnc,lac,cid,signalStrength,bitErrorRate
wcdma: mcc,mnc,lac,cid,psc,signalStrength,bitErrorRate
lte:   mcc,mnc,ci,pci,tac,signalStrength,rsrp,rsrq,rssnr,cqi,timingAdvance
2016-03-23 12:49:07 +02:00
Slava Monich
93c57284bd Merge branch 'phonebook' into 'master'
Remove unnecessary SIM I/O, pull in Canonical's RIL phonebook

SIM I/O has to go through ofono core to insure proper sequence of
SIM I/O requests.

Pulled in Canonical's RIL phonebook and ofono core patches required
by it, removed unnecessary code.

See merge request !50
2016-03-21 10:37:30 +00:00
Slava Monich
91436f9643 Merge branch 'import' into 'master'
phonebook: Block all Import requests while import is pending

Only the first one was blocked, other requests were rejected until
import is finished.

See merge request !51
2016-03-21 10:35:29 +00:00
Slava Monich
d0d2587b2a [ofono] phonebook: Block all Import requests while import is pending
Only the first one was blocked, other requests were rejected until
import is finished.
2016-03-21 12:34:30 +02:00
Slava Monich
3e10878348 [ril] Removed unnecessary direct SIM I/O 2016-03-10 18:49:46 +02:00
Slava Monich
6de8c4aa85 [ril] Canonical's RIL phonebook
More or less untouched
2016-03-10 18:36:25 +02:00
Slava Monich
a9da50f890 [ofono] sim: Pull in Canonical's simfs patches
ofono_sim_read_path, ofono_sim_read_info and ofono_sim_read_record
2016-03-10 17:57:41 +02:00
Slava Monich
3ca5161a78 Merge branch 'mce' into 'master'
Refactored mce support

See merge request !49
2016-03-10 07:54:29 +00:00
Slava Monich
03b3ca7776 [ril] Refactored mce support
Since there's only one mce, there's no need to have more than one mce client.
Implemented the initial display state query.
2016-03-09 15:24:34 +02:00
Slava Monich
6e5316aba9 [ril] Housekeeping 2016-03-09 09:42:41 +02:00
Slava Monich
49b752f0ad Merge branch 'mmsdata' into 'master'
Don't force 3G/LTE for MMS data slot

It wasn't doing any good, it only

* looked confusing and unpleasant (e.g. signal strength indicators)
* could result in a missed phone call
* could still take longer than if we just transmit MMS over 2G,
  because switching the network mode takes so long

See merge request !48
2016-03-08 13:48:39 +00:00
Slava Monich
268684eebf [ril] Don't force 3G/LTE for MMS data slot. Fixes JB#34350 2016-03-08 12:56:46 +02:00
Slava Monich
24db1db2b1 Merge branch 'disconnect' into 'master'
Handle the case of data call list changing before disconnect completes

It actually worked even though it was triggering asserts in ril_gprs_context_deactivate_primary_cb()

See merge request !47
2016-03-08 10:55:35 +00:00
Slava Monich
55977c1dac [ril] Handle the case of data call list changing before disconnect completes 2016-03-08 01:15:07 +02:00
Slava Monich
1025a6c6ed Merge branch 'ecclist' into 'master'
Load ECC list from a file

In addition to loading static ECC list from a file, this functionality
can be used to track Android system property by adding something like
this to /init.rc:

on property:ril.ecclist=*
    write /var/lib/ofono/ril.ecclist ${ril.ecclist}
    chmod 0644 /var/lib/ofono/ril.ecclist

See merge request !46
2016-03-07 12:01:42 +00:00
Slava Monich
98a143233d [ril] Load ecclist from a file. Contributes to JB#34084 2016-03-05 12:42:02 +02:00
Slava Monich
88013ff63e Merge branch 'nomodems' into 'master'
Set ready flag if there are no modems at all

See merge request !45
2016-03-04 14:49:45 +00:00
Slava Monich
efbe8b12c9 [ril] Set ready flag if there are no modems at all. Contributes to JB#34456 2016-03-04 16:01:40 +02:00
Slava Monich
ba9cc0eb4a Merge branch 'rat' into 'master'
Don't set preferred network mode if SIM isn't ready

Otherwise we may end up spamming system log with error messages
every 2 seconds.

See merge request !44
2016-03-03 12:49:34 +00:00
Slava Monich
46b5f22464 [ril] Don't set preferred network mode if SIM isn't ready. Fixes JB#34418
Otherwise we may end up spamming system log with error messages
every 2 seconds.
2016-03-02 17:41:58 +02:00
Slava Monich
a31332ebae [rpm] Bumped libglibutil version requirement 2016-03-02 17:41:18 +02:00
Slava Monich
b30141c3d3 Merge branch 'sim' into 'master'
Don't wait for radio power on before indicating SIM presence

I'm not sure why I waited for it in the first place,
probably "just in case".

See merge request !43
2016-03-02 14:00:46 +00:00
Slava Monich
e8ae8bba1c [ril] Don't wait for radio power on before indicating SIM presence. Fixes JB#34351 2016-03-02 14:55:20 +02:00
Slava Monich
3ea25fb81f [ril] Fixed ril_trace in release build 2016-03-02 14:48:12 +02:00
Slava Monich
197df7141d [ril] Ensure that all debug messages have the same syslog priority
So that don't get reordered by the system logger.
2016-03-01 17:23:28 +02:00
Slava Monich
eef6993391 Merge branch 'call' into 'master'
Clear cached callback pointer prior to invoking it

Otherwise we can bump into assert in ril_voicecall_dial

See merge request !42
2016-03-01 15:11:28 +00:00
Slava Monich
f1a5941b35 Merge branch 'handover' into 'master'
Let current data SIM in any slot use 3G/LTE

If 3G/LTE module is shared by the modems and 3G/LTE mode is enabled
for more than one SIM, we need to limit other SIMs to GSM in order
to ensure that the data SIM can use 3G/LTE.

See merge request !37
2016-03-01 15:06:31 +00:00
Slava Monich
5f6a258d0a [ril] Let current data SIM in any slot use 3G/LTE. Fixes JB#33358
If 3G/LTE hardware is shared by both modems, drop the current one to GSM
before switching the data SIM. That allows the other modem to use 3G/LTE.
The downside is that now switching data modems takes longer. This behavior
is configurable with /etc/ofono/ril_subscription.conf
2016-02-29 17:57:03 +02:00
Slava Monich
9fa18f967b [ofono] radio-settings: Made radio_access_mode_to/from_string public
So that they can be used by plugins.
2016-02-29 17:55:07 +02:00
Slava Monich
4d17a2e3b9 [ril] Moved online flag from slot to ril_radio object
To prevent radio power from being turned on when the modem is supposed
to be offline.
2016-02-29 17:54:54 +02:00
Slava Monich
c34b3c39b2 Merge branch 'ready' into 'master'
Add 'ready' flag to ModemManager interface

See merge request !40
2016-02-29 15:50:29 +00:00
Slava Monich
df1824b2e2 [ril] Clear cached callback pointer prior to invoking it.
Otherwise we can bump into assert in ril_voicecall_dial
2016-02-29 17:19:11 +02:00
Slava Monich
b3a18326e1 Merge branch 'pin' into 'master'
Don't expect that SIM changes state after pin change

See merge request !41
2016-02-29 13:44:38 +00:00
Slava Monich
93e564d5e5 [ril] Don't expect that SIM changes state after pin change. Fixes JB#34393 2016-02-29 15:26:10 +02:00
Slava Monich
42847e03b5 [ril] Fixed a memory leak in ril_sim_change_passwd 2016-02-29 15:08:34 +02:00
Slava Monich
f0d6b69972 [ril] Added 'ready' flag to ModemManager interface. Contributes to JB#34203
It allows the client to determine when ofono is done with startup,
i.e. all rild instances are running and have replied to the initial
GET_IMEI and GET_SIM_STATUS requests. At that point it's guaranteed
that ModemManager's SIM presence flags actually reflect the reality.
2016-02-27 02:47:44 +02:00
Slava Monich
2100a8d975 [ril] Removed incorrect asserts in ril_sim_info_handle_sim_state
It receives OFONO_SIM_STATE_NOT_PRESENT when SIM is removed
and there's nothing wrong with that.
2016-02-27 02:46:56 +02:00
Slava Monich
c393e63e4e [ril] Replaced G_INLINE_FUNC with 'static inline'
According to glib docs the use of this macro is strongly discouraged
2016-02-26 16:38:06 +02:00
Slava Monich
b24bc9761b Merge branch 'defaults' into 'master'
Try harder to pick the first SIM as the default

See merge request !39
2016-02-26 14:32:59 +00:00
Slava Monich
06daa7cf21 [ril] Try harder to pick the first SIM as the default. Contributes to JB#34203 2016-02-26 16:30:08 +02:00
Slava Monich
49215d60b2 Merge branch 'ussd' into 'master'
Complete ussd send requests immediately

Otherwise ofono ussd machinery may still be in the IDLE state when
the response arrives, breaking the workflow that involves user action.

See merge request !38
2016-02-22 14:50:13 +00:00
Slava Monich
f3f3b73d6f [ril] Complete ussd send requests immediately. Fixes JB#33891
Otherwise ofono ussd machinery may still be in the IDLE state
when the response arrives, breaking the workflow that involves
user action.
2016-02-22 15:15:45 +03:00
Slava Monich
113d9424b5 Merge branch 'power' into 'master'
See merge request !36
2016-02-18 12:33:12 +00:00
Slava Monich
2a8489c4d9 [ril] Don't power up the modem at startup. Fixes JB#34230
It's powered up when it goes online.
2016-02-18 13:21:57 +03:00
Slava Monich
c4f968b87a Merge branch 'nosimsettings' into 'master'
Remove org.nemomobile.ofono.SimSettings D-Bus interface

It's no longer being used. SIM name is stored in dconf and is of no use
to ofono, enable4G flag is useless - AvailableTechnologies property of
org.ofono.RadioSettings interface tells which radio technologies are
supported.

See merge request !35
2016-02-17 22:01:00 +00:00
Slava Monich
537c7ae8b4 Merge branch 'scan' into 'master'
Allow multiple Scan and (auto) Register requests.

While one of those requests is pending it makes no sense to block
other such requests.

See merge request !33
2016-02-17 22:00:00 +00:00
Slava Monich
b320fc7f59 [ril] Removed org.nemomobile.ofono.SimSettings D-Bus interface. Contributes to JB#34189
It's no longer being used. SIM name is stored in dconf and is of
no use to ofono, enable4G flag is useless - AvailableTechnologies
property of org.ofono.RadioSettings interface tells which radio
technologies are supported.
2016-02-11 22:00:29 +03:00
Slava Monich
edf49e6e99 [ril] Replaced assert with a comment 2016-02-10 12:24:53 +03:00
Slava Monich
b7985a1d67 Merge branch 'null' into 'master'
Fix crash on unexpected DATA_CALL_LIST payload

Debug trace didn't check pointers for NULL

See merge request !32
2016-02-08 11:35:24 +00:00
Slava Monich
bbb2c68a72 [ofono] network: Allow multiple Scan and (auto) Register requests.
While one of those requests is pending it makes no sense to
block other such requests.
2016-02-07 13:46:27 +03:00
Slava Monich
bd3f7f35eb [ril] Fixed crash on unexpected DATA_CALL_LIST payload
Debug trace didn't check pointers for NULL
2016-02-06 17:36:24 +03:00
Slava Monich
65bf1a24fa Merge branch 'sim_info' into 'master'
Slightly more generic handling of ofono watchlists

Without registering the free watch callback we can't be sure
whether the watchlist is still alive and that it's safe to call
the watch remove function (if the corresponding watchlist is
already deallocated, the ofono core may choose to crash). This
patch adds generic remove callback ril_sim_info_watch_done() for
all watches and fixes a few minor unrelated issues.

See merge request !31
2016-02-05 09:40:35 +00:00
Slava Monich
0c37015145 [ril] sim_info: Slightly more generic handling of ofono watchlists 2016-02-03 19:39:26 +02:00
Slava Monich
a8551cdce7 [ril] Housekeeping 2016-02-03 17:26:24 +02:00
Slava Monich
5bd2b96240 Merge branch 'mtu' into 'master'
MTU watcher

rild, modem driver or whatever is changing MTU of the mobile
data network interface without informing us. Since we don't
get any notifications from rild when that happens, the solution
that I came up with turned out to be slightly more complicated
than I hoped. But it works.

See merge request !30
2016-02-02 16:22:46 +00:00
Slava Monich
3bf309b887 [ofono] gprs: Took MTU management out of the ofono core
These changes have never been merged upstream and partially
duplicate MTU watcher (part of the RIL plugin).
2016-02-02 18:19:07 +02:00
Slava Monich
c14b9bbf93 [ril] MTU watcher. Fixes JB#33639
rild, modem driver or whatever is changing MTU of the mobile data
network interface without informing us. We don't want MTU to be
greater than 1280.
2016-02-02 18:19:07 +02:00
Slava Monich
568bd615cd Merge branch 'siminfo' into 'master'
org.nemomobile.ofono.SimInfo interface

Allows the client to fetch cached SubscriberIdentity and ServiceProviderName before the pin code is entered. ICCID
to IMSI map is stored in /var/lib/ofono/iccidmap, cached
SIM properties in /var/lib/ofono/IMSI/cache
2016-02-02 16:17:15 +00:00
Slava Monich
4d55f94015 [ril] Added org.nemomobile.ofono.SimInfo interface. Contributes to JB#34053
Allows the client to fetch cached SubscriberIdentity and
ServiceProviderName before the pin code is entered.
2016-01-31 17:08:27 +02:00
Slava Monich
95d06963cd [ofono] sim: Add iccid and imsi watches 2016-01-31 17:08:27 +02:00
Slava Monich
479458138a [ofono] watch: Ensure that watch id is non-zero 2016-01-31 17:08:27 +02:00
Slava Monich
c221d677d1 [rilmodem] Fixed compilation of the old rilmodem code 2016-01-31 16:48:06 +02:00
Slava Monich
a32da19192 [ril] Fixed possible crash on exit
==5482== Invalid free() / delete / delete[] / realloc()
==5482==    at 0x4840ABC: free (vg_replace_malloc.c:473)
==5482==    by 0x206E7: ril_data_call_setup_free (ril_data.c:727)
==5482==    by 0x1FE17: ril_data_call_request_free (ril_data.c:490)
==5482==    by 0x1FFC7: ril_data_call_request_cancel (ril_data.c:537)
==5482==    by 0x21707: ril_data_dispose (ril_data.c:1103)
==5482==    by 0x4A1EE57: g_object_unref (gobject.c:3160)
==5482==    by 0x21177: ril_data_unref (ril_data.c:971)
==5482==    by 0x2C32F: ril_plugin_shutdown_slot (ril_plugin.c:223)
==5482==    by 0x2EC2F: ril_plugin_delete_slot (ril_plugin.c:1023)
==5482==    by 0x2F077: ril_plugin_destroy_slot (ril_plugin.c:1127)
==5482==    by 0x4ACE9AF: g_slist_foreach (gslist.c:896)
==5482==    by 0x4ACE9C1: g_slist_free_full (gslist.c:179)
==5482==  Address 0x5bf1c40 is 0 bytes inside a block of size 48 free'd
==5482==    at 0x4840ABC: free (vg_replace_malloc.c:473)
==5482==    by 0x206E7: ril_data_call_setup_free (ril_data.c:727)
==5482==    by 0x1FE17: ril_data_call_request_free (ril_data.c:490)
==5482==    by 0x1FFC7: ril_data_call_request_cancel (ril_data.c:537)
==5482==    by 0x24A2B: ril_gprs_context_remove (ril_gprs_context.c:601)
==5482==    by 0x134803: gprs_context_remove (gprs.c:2841)
==5482==    by 0xDFD73: flush_atoms (modem.c:429)
==5482==    by 0xE002F: modem_change_state (modem.c:507)
==5482==    by 0xE0C7F: set_powered (modem.c:878)
==5482==    by 0xE3E5B: __ofono_modem_shutdown (modem.c:2207)
==5482==    by 0xDDDE7: signal_handler (main.c:77)
==5482==    by 0x4AB1B85: g_main_dispatch (gmain.c:3066)
==5482==    by 0x4AB1B85: g_main_context_dispatch (gmain.c:3642)
2016-01-31 03:24:25 +02:00
Slava Monich
a20da10621 [ril] Fixed assert in dbus library. Contributes to JB#28417
It doesn't like NULL strings so much that it terminates the app.
2016-01-30 00:37:50 +02:00
Slava Monich
64c754c3b9 [ril] Housekeeping
Use G_SOURCE_REMOVE instead of FALSE where appropriate
2016-01-29 17:48:13 +02:00
Slava Monich
d64fd7dca7 Merge branch 'enable4G' into 'master'
Remove Enable4GChanged signal from the introspection data

Enable4G flag never changes, therefore this signal is never sent.
    
Even though this flag it not being used by the UI anymore,
it still has to be kept it around to avoid breaking D-Bus API.

See merge request !28
2016-01-29 15:16:12 +00:00
Slava Monich
f608c0821a [ril] Remove Enable4GChanged signal from the introspection data
Enable4G flag never changes, therefore this signal is never sent.

Even though this flag it not being used by the UI anymore, it still
has to be kept it around to avoid breaking D-Bus API.
2016-01-29 12:43:01 +02:00
Slava Monich
7d29ef130a Housekeeping 2016-01-26 15:37:10 +02:00
Slava Monich
141eadee1d Merge branch 'mmssim' into 'master'
Add Get/SetMmsSim functionality

If MMS data SIM is different from the default data SIM, then MMS SIM
is selected for data and defaultDataModem is emptied, which tells
connman not to mess with mobile data while MMS is being transmitted.

SetMmsSim returns the path of the modem where the requested SIM is
or an empty string if there's no such SIM (or it's locked). This
information may or may not be useful to the client.
    
The behaviour gets reset back to default when IMSI of the MMS SIM is
set to empty string or the client which set it, exits. The client is
going to be mms-engine.

See merge request !26
2016-01-26 13:29:39 +00:00
Slava Monich
e84602d79c [ril] Add Get/SetMmsSim functionality. Contributes to #28417
If MMS data SIM is different from the default data SIM, then MMS SIM
is selected for data and defaultDataModem is emptied, which tells connman
not to mess with mobile data while MMS is being transmitted.

SetMmsSim returns the path of the modem where the requested SIM is
or an empty string if there's no such SIM (or it's locked).

The behaviour gets reset back to default when IMSI of the MMS SIM
is set to empty string or the client which set it, exits.
2016-01-26 02:10:07 +02:00
Slava Monich
b63b6355d5 [ril] Moved context setup and deactivation to ril_data. Contributes to JB#33358
This will allow to properly serialize the actions when switching
the data SIMs.
2016-01-26 02:10:07 +02:00
Slava Monich
f7f007a122 Merge branch 'EFspn' into 'master'
Add ServiceProviderName property to SimManager

Contains the service provider name fetched from the SIM card, if available.

See merge request !27
2016-01-25 23:57:21 +00:00
Slava Monich
5769656848 [ofono] sim: Add ServiceProviderName property to SimManager
Contains the service provider name fetched from the SIM card, if available.
2016-01-26 00:21:23 +02:00
Slava Monich
bbc276b4c7 [ril] Reduced the amount of debug trace produced by ril_radio.c 2016-01-23 18:53:05 +02:00
Slava Monich
4b79de53fe [gprs] Removed unnecessary debug trace 2016-01-21 14:05:11 +02:00
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
75 changed files with 8504 additions and 3316 deletions

View File

@@ -22,7 +22,7 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
include/private-network.h include/cdma-netreg.h \
include/cdma-provision.h include/handsfree.h \
include/handsfree-audio.h \
include/sim-mnclength.h include/oemraw.h \
include/sim-mnclength.h \
include/siri.h
nodist_pkginclude_HEADERS = include/version.h
@@ -125,13 +125,18 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_call_forward.c \
drivers/ril/ril_call_settings.c \
drivers/ril/ril_call_volume.c \
drivers/ril/ril_cell_info.c \
drivers/ril/ril_cell_info_dbus.c \
drivers/ril/ril_config.c \
drivers/ril/ril_cbs.c \
drivers/ril/ril_data.c \
drivers/ril/ril_devinfo.c \
drivers/ril/ril_ecclist.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_mtu.c \
drivers/ril/ril_netreg.c \
drivers/ril/ril_network.c \
drivers/ril/ril_oem_raw.c \
@@ -142,7 +147,9 @@ builtin_sources += drivers/ril/ril_call_barring.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_sim_info.c \
drivers/ril/ril_sim_info_dbus.c \
drivers/ril/ril_sim_settings.c \
drivers/ril/ril_sms.c \
drivers/ril/ril_stk.c \
drivers/ril/ril_ussd.c \
@@ -612,7 +619,7 @@ builtin_cflags += @WSPCODEC_CFLAGS@
builtin_libadd += @WSPCODEC_LIBS@
endif
if LOGCONTROL
if DEBUGLOG
builtin_modules += debuglog
builtin_sources += plugins/debuglog.c
endif
@@ -647,7 +654,7 @@ src_ofonod_SOURCES = $(builtin_sources) src/ofono.ver \
src/cdma-sms.c src/private-network.c src/cdma-netreg.c \
src/cdma-provision.c src/handsfree.c \
src/handsfree-audio.c src/bluetooth.h \
src/sim-mnclength.c src/oemraw.c src/voicecallagent.c \
src/sim-mnclength.c src/voicecallagent.c \
src/hfp.h src/siri.c
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \

View File

@@ -175,8 +175,8 @@ AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_rilmodem}" != "no")
if (test "${enable_jolla_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.6, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.6 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil, dummy=yes,
AC_MSG_ERROR(libglibutil is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.5, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.5 is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS"
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS"
fi
@@ -252,10 +252,16 @@ if (test "${enable_pushforwarder}" != "no"); then
AC_SUBST(WSPCODEC_LIBS)
fi
AC_ARG_ENABLE(logcontrol,
AC_HELP_STRING([--enable-logcontrol], [enable log control plugin]),
[enable_logcontrol=${enableval}], [enable_logcontrol="no"])
AM_CONDITIONAL(LOGCONTROL, test "${enable_logcontrol}" != "no")
AC_ARG_ENABLE(debuglog,
AC_HELP_STRING([--enable-debuglog], [enable log control plugin]),
[enable_debuglog=${enableval}], [enable_debuglog="no"])
AM_CONDITIONAL(DEBUGLOG, test "${enable_debuglog}" != "no")
if (test "${enable_debuglog}" = "yes"); then
PKG_CHECK_MODULES(DBUSLOG, libdbuslogserver-dbus, dummy=yes,
AC_MSG_ERROR(libdbuslogserver-dbus is required))
CFLAGS="$CFLAGS $DBUSLOG_CFLAGS"
LIBS="$LIBS $DBUSLOG_LIBS"
fi
if (test "${prefix}" = "NONE"); then
dnl no prefix and no localstatedir, so default to /var

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

@@ -1,28 +0,0 @@
Debug log control
=================
Service org.ofono
Interface org.ofono.DebugLog
Object path /
Methods void Enable(string pattern)
Enables all logs that match the pattern.
void Disable(string pattern)
Disables all logs that match the pattern.
array(string,boolean) List()
Returns all available log names and their current
states.
In order for Enable or Disable call to have any
effect, the pattern must match one or more of
these strings.
Signals Changed(string name, boolean enabled)
This signal indicates a changed log status of the
given log module.

View File

@@ -93,6 +93,11 @@ Properties boolean Present [readonly]
Contains the IMSI of the SIM, if available.
string ServiceProviderName [readonly, optional]
Contains the service provider name fetched from the
SIM card, if available.
string MobileCountryCode [readonly, optional]
Contains the Mobile Country Code (MCC) of the home

View File

@@ -0,0 +1,537 @@
/*
* 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_cell_info.h"
#include "ril_sim_card.h"
#include "ril_radio.h"
#include "ril_util.h"
#include "ril_mce.h"
#include "ril_log.h"
#include <grilio_channel.h>
#include <grilio_request.h>
#include <grilio_parser.h>
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
typedef GObjectClass RilCellInfoClass;
typedef struct ril_cell_info RilCellInfo;
struct ril_cell_info_priv {
GRilIoChannel *io;
struct ril_mce *mce;
struct ril_radio *radio;
struct ril_sim_card *sim_card;
gulong display_state_event_id;
gulong radio_state_event_id;
gulong sim_status_event_id;
gboolean sim_card_ready;
char *log_prefix;
gulong event_id;
guint query_id;
guint set_rate_id;
};
enum ril_cell_info_signal {
SIGNAL_CELLS_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_CELLS_CHANGED_NAME "ril-cell-info-cells-changed"
static guint ril_cell_info_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
#define RIL_CELL_INFO_TYPE (ril_cell_info_get_type())
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
RIL_CELL_INFO_TYPE, RilCellInfo))
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
gint ril_cell_compare_location(const struct ril_cell *c1,
const struct ril_cell *c2)
{
if (c1 && c2) {
if (c1->type != c2->type) {
return c1->type - c2->type;
} else if (c1->type == RIL_CELL_INFO_TYPE_GSM) {
const struct ril_cell_info_gsm *g1 = &c1->info.gsm;
const struct ril_cell_info_gsm *g2 = &c2->info.gsm;
if (g1->lac != g2->lac) {
return g1->lac - g2->lac;
} else {
return g1->cid - g2->cid;
}
} else if (c2->type == RIL_CELL_INFO_TYPE_WCDMA) {
const struct ril_cell_info_wcdma *w1 = &c1->info.wcdma;
const struct ril_cell_info_wcdma *w2 = &c2->info.wcdma;
if (w1->lac != w2->lac) {
return w1->lac - w2->lac;
} else {
return w1->cid - w2->cid;
}
} else {
const struct ril_cell_info_lte *l1 = &c1->info.lte;
const struct ril_cell_info_lte *l2 = &c2->info.lte;
GASSERT(c1->type == RIL_CELL_INFO_TYPE_LTE);
if (l1->ci != l2->ci) {
return l1->ci - l2->ci;
} else if (l1->pci != l2->pci) {
return l1->pci - l2->pci;
} else {
return l1->tac - l2->tac;
}
}
} else if (c1) {
return 1;
} else if (c2) {
return -1;
} else {
return 0;
}
}
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2)
{
return ril_cell_compare_location(v1, v2);
}
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
{
while (l1 && l2) {
if (memcmp(l1->data, l2->data, sizeof(struct ril_cell))) {
return FALSE;
}
l1 = l1->next;
l2 = l2->next;
}
return !l1 && !l2;
}
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
{
if (!ril_cell_info_list_identical(self->cells, l)) {
g_slist_free_full(self->cells, g_free);
self->cells = l;
g_signal_emit(self, ril_cell_info_signals[
SIGNAL_CELLS_CHANGED], 0);
} else {
g_slist_free_full(l, g_free);
}
}
static struct ril_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
gboolean registered)
{
struct ril_cell *cell = g_new0(struct ril_cell, 1);
struct ril_cell_info_gsm *gsm = &cell->info.gsm;
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
grilio_parser_get_int32(rilp, &gsm->mnc) &&
grilio_parser_get_int32(rilp, &gsm->lac) &&
grilio_parser_get_int32(rilp, &gsm->cid) &&
grilio_parser_get_int32(rilp, &gsm->signalStrength) &&
grilio_parser_get_int32(rilp, &gsm->bitErrorRate)) {
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,"
"strength=%d,err=%d", registered, gsm->mcc, gsm->mnc,
gsm->lac, gsm->cid, gsm->signalStrength,
gsm->bitErrorRate);
cell->type = RIL_CELL_INFO_TYPE_GSM;
cell->registered = registered;
return cell;
}
ofono_error("failed to parse GSM cell info");
g_free(cell);
return NULL;
}
static struct ril_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
gboolean registered)
{
struct ril_cell *cell = g_new0(struct ril_cell, 1);
struct ril_cell_info_wcdma *wcdma = &cell->info.wcdma;
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
grilio_parser_get_int32(rilp, &wcdma->lac) &&
grilio_parser_get_int32(rilp, &wcdma->cid) &&
grilio_parser_get_int32(rilp, &wcdma->psc) &&
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
DBG("[wcdma] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,psc=%d,"
"strength=%d,err=%d", registered, wcdma->mcc,
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
wcdma->signalStrength, wcdma->bitErrorRate);
cell->type = RIL_CELL_INFO_TYPE_WCDMA;
cell->registered = registered;
return cell;
}
ofono_error("failed to parse WCDMA cell info");
g_free(cell);
return NULL;
}
static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
gboolean registered)
{
struct ril_cell *cell = g_new0(struct ril_cell, 1);
struct ril_cell_info_lte *lte = &cell->info.lte;
if (grilio_parser_get_int32(rilp, &lte->mcc) &&
grilio_parser_get_int32(rilp, &lte->mnc) &&
grilio_parser_get_int32(rilp, &lte->ci) &&
grilio_parser_get_int32(rilp, &lte->pci) &&
grilio_parser_get_int32(rilp, &lte->tac) &&
grilio_parser_get_int32(rilp, &lte->signalStrength) &&
grilio_parser_get_int32(rilp, &lte->rsrp) &&
grilio_parser_get_int32(rilp, &lte->rsrq) &&
grilio_parser_get_int32(rilp, &lte->rssnr) &&
grilio_parser_get_int32(rilp, &lte->cqi) &&
grilio_parser_get_int32(rilp, &lte->timingAdvance)) {
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
"strength=%d,rsrp=%d,rsrq=0x%x,rssnr=0x%x,cqi=%d,"
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
cell->type = RIL_CELL_INFO_TYPE_LTE;
cell->registered = registered;
return cell;
}
ofono_error("failed to parse LTE cell info");
g_free(cell);
return NULL;
}
static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
struct ril_cell **cell_ptr)
{
int type, reg;
if (grilio_parser_get_int32(rilp, &type) &&
grilio_parser_get_int32(rilp, &reg) &&
grilio_parser_get_int32_array(rilp, NULL, 3)) {
int skip = 0;
struct ril_cell *cell = NULL;
switch (type) {
case RIL_CELL_INFO_TYPE_GSM:
cell = ril_cell_info_parse_cell_gsm(rilp, reg);
break;
case RIL_CELL_INFO_TYPE_WCDMA:
cell = ril_cell_info_parse_cell_wcdma(rilp, reg);
break;
case RIL_CELL_INFO_TYPE_LTE:
cell = ril_cell_info_parse_cell_lte(rilp, reg);
break;
case RIL_CELL_INFO_TYPE_CDMA:
skip = 10;
break;
case RIL_CELL_INFO_TYPE_TD_SCDMA:
skip = 6;
break;
default:
skip = 0;
break;
}
if (cell) {
*cell_ptr = cell;
return type;
}
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
*cell_ptr = NULL;
return type;
}
}
*cell_ptr = NULL;
return RIL_CELL_INFO_TYPE_NONE;
}
static GSList *ril_cell_info_parse_list(const void *data, guint len)
{
GSList *l = NULL;
GRilIoParser rilp;
int i, n;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
struct ril_cell *c;
DBG("%d cell(s):", n);
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, &c); i++) {
if (c) {
l = g_slist_insert_sorted(l, c,
ril_cell_compare_func);
}
}
}
return l;
}
static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
DBG_(self, "");
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
}
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
struct ril_cell_info_priv *priv = self->priv;
DBG_(self, "");
GASSERT(priv->query_id);
priv->query_id = 0;
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
}
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
struct ril_cell_info_priv *priv = self->priv;
DBG_(self, "");
GASSERT(priv->set_rate_id);
priv->set_rate_id = 0;
}
static void ril_cell_info_query(struct ril_cell_info *self)
{
struct ril_cell_info_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
priv->query_id = grilio_channel_send_request_full(priv->io, req,
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
NULL, self);
grilio_request_unref(req);
}
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
{
struct ril_cell_info_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, ms);
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_channel_cancel_request(priv->io, priv->set_rate_id, FALSE);
priv->set_rate_id = grilio_channel_send_request_full(priv->io, req,
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
ril_cell_info_set_rate_cb, NULL, self);
grilio_request_unref(req);
}
static void ril_cell_info_update_rate(struct ril_cell_info *self)
{
struct ril_cell_info_priv *priv = self->priv;
ril_cell_info_set_rate(self,
(priv->mce->display_state == RIL_MCE_DISPLAY_OFF) ?
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
}
static void ril_cell_info_display_state_cb(struct ril_mce *mce, void *arg)
{
struct ril_cell_info *self = RIL_CELL_INFO(arg);
struct ril_cell_info_priv *priv = self->priv;
if (priv->sim_card_ready) {
ril_cell_info_update_rate(self);
}
}
static void ril_cell_info_refresh(struct ril_cell_info *self)
{
struct ril_cell_info_priv *priv = self->priv;
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
if (priv->radio->state == RADIO_STATE_ON && priv->sim_card_ready) {
ril_cell_info_query(self);
} else {
ril_cell_info_update_cells(self, NULL);
}
}
static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
{
struct ril_cell_info *self = RIL_CELL_INFO(arg);
DBG_(self, "%s", ril_radio_state_to_string(radio->state));
ril_cell_info_refresh(self);
}
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
{
struct ril_cell_info *self = RIL_CELL_INFO(arg);
struct ril_cell_info_priv *priv = self->priv;
const gboolean sim_card_was_ready = priv->sim_card_ready;
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
priv->sim_card_ready = ril_sim_card_ready(sim);
if (priv->sim_card_ready != sim_card_was_ready) {
ril_cell_info_refresh(self);
if (priv->sim_card_ready) {
ril_cell_info_update_rate(self);
}
}
}
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *self,
ril_cell_info_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_CELLS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_cell_info_remove_handler(struct ril_cell_info *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, struct ril_mce *mce,
struct ril_radio *radio, struct ril_sim_card *sim_card)
{
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
struct ril_cell_info_priv *priv = self->priv;
priv->io = grilio_channel_ref(io);
priv->mce = ril_mce_ref(mce);
priv->radio = ril_radio_ref(radio);
priv->sim_card = ril_sim_card_ref(sim_card);
priv->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
DBG_(self, "");
priv->event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
priv->display_state_event_id =
ril_mce_add_display_state_changed_handler(mce,
ril_cell_info_display_state_cb, self);
priv->radio_state_event_id =
ril_radio_add_state_changed_handler(radio,
ril_cell_info_radio_state_cb, self);
priv->sim_status_event_id =
ril_sim_card_add_status_changed_handler(priv->sim_card,
ril_cell_info_sim_status_cb, self);
priv->sim_card_ready = ril_sim_card_ready(sim_card);
if (priv->sim_card_ready) {
ril_cell_info_query(self);
ril_cell_info_update_rate(self);
}
return self;
}
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_CELL_INFO(self));
return self;
} else {
return NULL;
}
}
void ril_cell_info_unref(struct ril_cell_info *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_CELL_INFO(self));
}
}
static void ril_cell_info_init(struct ril_cell_info *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_CELL_INFO_TYPE,
struct ril_cell_info_priv);
}
static void ril_cell_info_dispose(GObject *object)
{
struct ril_cell_info *self = RIL_CELL_INFO(object);
struct ril_cell_info_priv *priv = self->priv;
grilio_channel_remove_handlers(priv->io, &priv->event_id, 1);
if (priv->query_id) {
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
priv->query_id = 0;
}
if (priv->set_rate_id) {
grilio_channel_cancel_request(priv->io, priv->set_rate_id,
FALSE);
priv->set_rate_id = 0;
}
if (priv->display_state_event_id) {
ril_mce_remove_handler(priv->mce, priv->display_state_event_id);
priv->display_state_event_id = 0;
}
ril_radio_remove_handlers(priv->radio, &priv->radio_state_event_id, 1);
ril_sim_card_remove_handlers(priv->sim_card,
&priv->sim_status_event_id, 1);
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
}
static void ril_cell_info_finalize(GObject *object)
{
struct ril_cell_info *self = RIL_CELL_INFO(object);
struct ril_cell_info_priv *priv = self->priv;
DBG_(self, "");
g_free(priv->log_prefix);
grilio_channel_unref(priv->io);
ril_mce_unref(priv->mce);
ril_radio_unref(priv->radio);
ril_sim_card_unref(priv->sim_card);
g_slist_free_full(self->cells, g_free);
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
}
static void ril_cell_info_class_init(RilCellInfoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_cell_info_dispose;
object_class->finalize = ril_cell_info_finalize;
g_type_class_add_private(klass, sizeof(struct ril_cell_info_priv));
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
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,63 @@
/*
* 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_CELL_INFO_H
#define RIL_CELL_INFO_H
#include "ril_types.h"
struct ril_cell {
enum ril_cell_info_type type;
gboolean registered;
union {
struct ril_cell_info_gsm gsm;
struct ril_cell_info_wcdma wcdma;
struct ril_cell_info_lte lte;
} info;
};
struct ril_cell_info_priv;
struct ril_cell_info {
GObject object;
struct ril_cell_info_priv *priv;
GSList *cells;
};
typedef void (*ril_cell_info_cb_t)(struct ril_cell_info *info, void *arg);
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2);
gint ril_cell_compare_location(const struct ril_cell *c1,
const struct ril_cell *c2);
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, struct ril_mce *mce,
struct ril_radio *radio, struct ril_sim_card *sim_card);
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *info);
void ril_cell_info_unref(struct ril_cell_info *info);
struct ril_cell *ril_cell_find_cell(struct ril_cell_info *info,
const struct ril_cell *cell);
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *info,
ril_cell_info_cb_t cb, void *arg);
void ril_cell_info_remove_handler(struct ril_cell_info *info, gulong id);
#endif /* RIL_CELL_INFO_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

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

View File

@@ -0,0 +1,115 @@
/*
* 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_config.h"
/* Utilities for parsing ril_subscription.conf */
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
{
char *val = g_key_file_get_string(file, group, key, NULL);
if (!val && strcmp(group, RILCONF_SETTINGS_GROUP)) {
/* Check the common section */
val = g_key_file_get_string(file, RILCONF_SETTINGS_GROUP, key,
NULL);
}
return val;
}
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
const char *key, int *out_value)
{
GError *error = NULL;
int value = g_key_file_get_integer(file, group, key, &error);
if (!error) {
if (out_value) {
*out_value = value;
}
return TRUE;
} else {
g_error_free(error);
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
/* Check the common section */
error = NULL;
value = g_key_file_get_integer(file,
RILCONF_SETTINGS_GROUP, key, &error);
if (!error) {
if (out_value) {
*out_value = value;
}
return TRUE;
}
g_error_free(error);
}
return FALSE;
}
}
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
const char *key, gboolean *out_value)
{
GError *error = NULL;
gboolean value = g_key_file_get_boolean(file, group, key, &error);
if (!error) {
if (out_value) {
*out_value = value;
}
return TRUE;
} else {
g_error_free(error);
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
/* Check the common section */
error = NULL;
value = g_key_file_get_boolean(file,
RILCONF_SETTINGS_GROUP, key, &error);
if (!error) {
if (out_value) {
*out_value = value;
}
return TRUE;
}
g_error_free(error);
}
return FALSE;
}
}
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
const char *key, int flag, int *flags)
{
gboolean value;
if (ril_config_get_boolean(file, group, key, &value)) {
if (value) {
*flags |= flag;
} else {
*flags &= ~flag;
}
return TRUE;
} else {
return FALSE;
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,41 @@
/*
* 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_CONFIG_H
#define RIL_CONFIG_H
#include "ril_types.h"
/* Utilities for parsing ril_subscription.conf */
#define RILCONF_SETTINGS_GROUP "Settings"
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key);
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
const char *key, int *value);
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
const char *key, gboolean *value);
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
const char *key, int flag, int *flags);
#endif /* RIL_CONFIG_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -158,23 +158,54 @@ enum ril_radio_tech {
#define CALL_FAIL_FACILITY_REJECTED 29
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
/* see RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
enum ril_data_call_fail_cause {
PDP_FAIL_NONE = 0,
PDP_FAIL_OPERATOR_BARRED = 0x08,
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
PDP_FAIL_NSAPI_IN_USE = 0x23,
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
PDP_FAIL_SIGNAL_LOST = -3,
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
PDP_FAIL_RADIO_POWER_OFF = -5,
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
};
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
#define RIL_DEACTIVATE_DATA_CALL_NO_REASON 0
#define RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN 1
/* See RIL_REQUEST_SETUP_DATA_CALL */
/* RIL_REQUEST_SETUP_DATA_CALL */
enum ril_data_profile {
RIL_DATA_PROFILE_DEFAULT = 0,
RIL_DATA_PROFILE_TETHERED = 1,
RIL_DATA_PROFILE_IMS = 2,
RIL_DATA_PROFILE_FOTA = 3,
RIL_DATA_PROFILE_CBS = 4,
RIL_DATA_PROFILE_OEM_BASE = 1000,
RIL_DATA_PROFILE_INVALID = 0xFFFFFFFF
};
#define RIL_DATA_PROFILE_DEFAULT 0
#define RIL_DATA_PROFILE_TETHERED 1
#define RIL_DATA_PROFILE_IMS 2
#define RIL_DATA_PROFILE_FOTA 3 /* FOTA = Firmware Over the Air */
#define RIL_DATA_PROFILE_CBS 4
#define RIL_DATA_PROFILE_OEM_BASE 1000 /* Start of OEM-specific profiles */
#define RIL_AUTH_NONE 0
#define RIL_AUTH_PAP 1
#define RIL_AUTH_CHAP 2
#define RIL_AUTH_BOTH 3
enum ril_auth {
RIL_AUTH_NONE = 0,
RIL_AUTH_PAP = 1,
RIL_AUTH_CHAP = 2,
RIL_AUTH_BOTH = 3
};
#define RIL_CARD_MAX_APPS 8
@@ -246,6 +277,49 @@ enum ril_app_type {
RIL_APPTYPE_ISIM = 5
};
/* Cell info */
enum ril_cell_info_type {
RIL_CELL_INFO_TYPE_NONE = 0,
RIL_CELL_INFO_TYPE_GSM = 1,
RIL_CELL_INFO_TYPE_CDMA = 2,
RIL_CELL_INFO_TYPE_LTE = 3,
RIL_CELL_INFO_TYPE_WCDMA = 4,
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
};
struct ril_cell_info_gsm {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int lac; /* Location Area Code (0..65535) */
int cid; /* GSM Cell Identity (0..65535) TS 27.007 */
int signalStrength; /* (0-31, 99) TS 27.007 */
int bitErrorRate; /* (0-7, 99) TS 27.007 */
};
struct ril_cell_info_wcdma {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int lac; /* Location Area Code (0..65535) */
int cid; /* UMTS Cell Identity (0..268435455) TS 25.331 */
int psc; /* Primary Scrambling Code (0..511) TS 25.331) */
int signalStrength; /* (0-31, 99) TS 27.007 */
int bitErrorRate; /* (0-7, 99) TS 27.007 */
};
struct ril_cell_info_lte {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int ci; /* Cell Identity */
int pci; /* Physical cell id (0..503) */
int tac; /* Tracking area code */
int signalStrength; /* (0-31, 99) TS 27.007 8.5 */
int rsrp; /* Reference Signal Receive Power TS 36.133 */
int rsrq; /* Reference Signal Receive Quality TS 36.133 */
int rssnr; /* Reference Signal-to-Noise Ratio TS 36.101*/
int cqi; /* Channel Quality Indicator TS 36.101 */
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
};
/* RIL Request Messages */
#define RIL_REQUEST_GET_SIM_STATUS 1
#define RIL_REQUEST_ENTER_SIM_PIN 2

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
@@ -17,24 +17,96 @@
#define RIL_DATA_H
#include "ril_types.h"
#include <ofono/gprs-context.h>
enum ril_data_call_active {
RIL_DATA_CALL_INACTIVE = 0,
RIL_DATA_CALL_LINK_DOWN = 1,
RIL_DATA_CALL_ACTIVE = 2
};
struct ril_data_call {
int cid;
enum ril_data_call_fail_cause status;
enum ril_data_call_active active;
enum ofono_gprs_proto prot;
int retry_time;
int mtu;
char *ifname;
char **dnses;
char **gateways;
char **addresses;
};
struct ril_data_call_list {
guint version;
guint num;
GSList *calls;
};
struct ril_data {
GObject object;
struct ril_data_priv *priv;
struct ril_data_call_list *data_calls;
};
enum ril_data_manager_flags {
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01
};
enum ril_data_allow_data_opt {
RIL_ALLOW_DATA_AUTO,
RIL_ALLOW_DATA_ON,
RIL_ALLOW_DATA_OFF
};
enum ril_data_role {
RIL_DATA_ROLE_NONE, /* Data not allowed */
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
RIL_DATA_ROLE_INTERNET /* Data is allowed at full speed */
};
struct ril_data_manager;
struct ril_data_manager *ril_data_manager_new(void);
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
void ril_data_manager_unref(struct ril_data_manager *dm);
struct ril_data *ril_data_new(struct ril_data_manager *dm, GRilIoChannel *io);
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
int ril_status, const struct ril_data_call *call,
void *arg);
typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
int ril_status, void *arg);
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, enum ril_data_allow_data_opt opt);
struct ril_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);
gulong ril_data_add_calls_changed_handler(struct ril_data *data,
ril_data_cb_t cb, void *arg);
void ril_data_remove_handler(struct ril_data *data, gulong id);
void ril_data_allow(struct ril_data *data, enum ril_data_role role);
struct ril_data_request;
struct ril_data_request *ril_data_call_setup(struct ril_data *data,
const struct ofono_gprs_primary_context *ctx,
ril_data_call_setup_cb_t cb, void *arg);
struct ril_data_request *ril_data_call_deactivate(struct ril_data *data,
int cid, ril_data_call_deactivate_cb_t cb, void *arg);
void ril_data_request_detach(struct ril_data_request *req);
void ril_data_request_cancel(struct ril_data_request *req);
void ril_data_call_free(struct ril_data_call *call);
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
int cid);
#endif /* RIL_DATA_H */
/*

View File

@@ -0,0 +1,258 @@
/*
* 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_ecclist.h"
#include "ril_log.h"
#include <gutil_strv.h>
#include <gutil_inotify.h>
#include <sys/inotify.h>
typedef GObjectClass RilEccListClass;
typedef struct ril_ecclist RilEccList;
struct ril_ecclist_priv {
struct ofono_sim *sim;
GUtilInotifyWatchCallback *dir_watch;
GUtilInotifyWatchCallback *file_watch;
char *dir;
char *path;
char *name;
};
enum ril_ecclist_signal {
SIGNAL_LIST_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_LIST_CHANGED_NAME "ril-ecclist-changed"
static guint ril_ecclist_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilEccList, ril_ecclist, G_TYPE_OBJECT)
#define RIL_ECCLIST_TYPE (ril_ecclist_get_type())
#define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
RIL_ECCLIST_TYPE, RilEccList))
static char **ril_ecclist_read(struct ril_ecclist *self)
{
struct ril_ecclist_priv *priv = self->priv;
char **list = NULL;
if (g_file_test(priv->path, G_FILE_TEST_EXISTS)) {
gsize len = 0;
gchar *content = NULL;
GError *error = NULL;
if (g_file_get_contents(priv->path, &content, &len, &error)) {
char **ptr;
DBG("%s = %s", priv->name, content);
list = g_strsplit(content, ",", 0);
for (ptr = list; *ptr; ptr++) {
*ptr = g_strstrip(*ptr);
}
gutil_strv_sort(list, TRUE);
} else if (error) {
DBG("%s: %s", priv->path, GERRMSG(error));
g_error_free(error);
}
g_free (content);
} else {
DBG("%s doesn't exist", priv->path);
}
return list;
}
static void ril_ecclist_update(struct ril_ecclist *self)
{
struct ril_ecclist_priv *priv = self->priv;
char **list = ril_ecclist_read(self);
if (!gutil_strv_equal(self->list, list)) {
DBG("%s changed", priv->name);
g_strfreev(self->list);
self->list = list;
g_signal_emit(self, ril_ecclist_signals[SIGNAL_LIST_CHANGED], 0);
} else {
g_strfreev(list);
}
}
static void ril_ecclist_changed(GUtilInotifyWatch *watch, guint mask,
guint cookie, const char *name, void *user_data)
{
struct ril_ecclist *self = RIL_ECCLIST(user_data);
struct ril_ecclist_priv *priv = self->priv;
ril_ecclist_update(self);
if (mask & IN_IGNORED) {
DBG("file %s is gone", priv->path);
gutil_inotify_watch_callback_free(priv->file_watch);
priv->file_watch = NULL;
}
}
static void ril_ecclist_dir_changed(GUtilInotifyWatch *watch, guint mask,
guint cookie, const char *name, void *user_data)
{
struct ril_ecclist *self = RIL_ECCLIST(user_data);
struct ril_ecclist_priv *priv = self->priv;
DBG("0x%04x %s", mask, name);
if (!priv->file_watch && !g_strcmp0(name, priv->name)) {
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
IN_MODIFY | IN_CLOSE_WRITE,
ril_ecclist_changed, self);
if (priv->file_watch) {
DBG("watching %s", priv->path);
ril_ecclist_update(self);
}
}
if (mask & IN_IGNORED) {
DBG("%s is gone", priv->dir);
gutil_inotify_watch_callback_free(priv->dir_watch);
priv->dir_watch = NULL;
}
}
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *self,
ril_ecclist_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_LIST_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_ecclist_remove_handler(struct ril_ecclist *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
struct ril_ecclist *ril_ecclist_new(const char *path)
{
if (path) {
struct ril_ecclist *self = g_object_new(RIL_ECCLIST_TYPE, 0);
struct ril_ecclist_priv *priv = self->priv;
DBG("%s", path);
priv->path = g_strdup(path);
priv->name = g_path_get_basename(path);
priv->dir = g_path_get_dirname(path);
priv->dir_watch = gutil_inotify_watch_callback_new(priv->dir,
IN_MODIFY|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|
IN_CREATE|IN_DELETE_SELF|IN_CLOSE_WRITE,
ril_ecclist_dir_changed, self);
if (priv->dir_watch) {
DBG("watching %s", priv->dir);
}
self->list = ril_ecclist_read(self);
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
IN_MODIFY | IN_CLOSE_WRITE,
ril_ecclist_changed, self);
if (priv->file_watch) {
DBG("watching %s", priv->path);
}
return self;
}
return NULL;
}
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_ECCLIST(self));
return self;
} else {
return NULL;
}
}
void ril_ecclist_unref(struct ril_ecclist *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_ECCLIST(self));
}
}
static void ril_ecclist_init(struct ril_ecclist *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_ECCLIST_TYPE,
struct ril_ecclist_priv);
}
static void ril_ecclist_dispose(GObject *object)
{
struct ril_ecclist *self = RIL_ECCLIST(object);
struct ril_ecclist_priv *priv = self->priv;
if (priv->dir_watch) {
gutil_inotify_watch_callback_free(priv->dir_watch);
priv->dir_watch = NULL;
}
if (priv->file_watch) {
gutil_inotify_watch_callback_free(priv->file_watch);
priv->file_watch = NULL;
}
G_OBJECT_CLASS(ril_ecclist_parent_class)->dispose(object);
}
static void ril_ecclist_finalize(GObject *object)
{
struct ril_ecclist *self = RIL_ECCLIST(object);
struct ril_ecclist_priv *priv = self->priv;
GASSERT(!priv->dir_watch);
GASSERT(!priv->file_watch);
g_free(priv->dir);
g_free(priv->path);
g_free(priv->name);
g_strfreev(self->list);
G_OBJECT_CLASS(ril_ecclist_parent_class)->finalize(object);
}
static void ril_ecclist_class_init(RilEccListClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_ecclist_dispose;
object_class->finalize = ril_ecclist_finalize;
g_type_class_add_private(klass, sizeof(struct ril_ecclist_priv));
ril_ecclist_signals[SIGNAL_LIST_CHANGED] =
g_signal_new(SIGNAL_LIST_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,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_ECCLIST_H
#define RIL_ECCLIST_H
#include "ril_types.h"
struct ril_ecclist_priv;
struct ril_ecclist {
GObject object;
struct ril_ecclist_priv *priv;
char **list;
};
typedef void (*ril_ecclist_cb_t)(struct ril_ecclist *ecc, void *arg);
struct ril_ecclist *ril_ecclist_new(const char *path);
struct ril_ecclist *ril_ecclist_ref(struct ril_ecclist *ecc);
void ril_ecclist_unref(struct ril_ecclist *ecc);
gulong ril_ecclist_add_list_changed_handler(struct ril_ecclist *ecc,
ril_ecclist_cb_t cb, void *arg);
void ril_ecclist_remove_handler(struct ril_ecclist *ecc, gulong id);
#endif /* RIL_ECCLIST_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -9,128 +9,52 @@
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_network.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_mtu.h"
#include "ril_log.h"
#include <gutil_strv.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "common.h"
#define PROTO_IP_STR "IP"
#define PROTO_IPV6_STR "IPV6"
#define PROTO_IPV4V6_STR "IPV4V6"
#define MIN_DATA_CALL_LIST_SIZE 8
#define MIN_DATA_CALL_REPLY_SIZE 36
#define SETUP_DATA_CALL_PARAMS 7
#define DATA_PROFILE_DEFAULT_STR "0"
#define DEACTIVATE_DATA_CALL_PARAMS 2
#define CTX_ID_NONE ((unsigned int)(-1))
enum data_call_state {
DATA_CALL_INACTIVE,
DATA_CALL_LINK_DOWN,
DATA_CALL_ACTIVE,
};
#define MAX_MTU 1280
enum ril_gprs_context_state {
STATE_IDLE,
STATE_ACTIVATING,
STATE_DEACTIVATING,
STATE_ACTIVE,
struct ril_gprs_context_call {
struct ril_data_request *req;
ofono_gprs_context_cb_t cb;
gpointer data;
};
struct ril_gprs_context {
struct ofono_gprs_context *gc;
struct ril_modem *modem;
struct ril_network *network;
GRilIoChannel *io;
GRilIoQueue *q;
struct ril_data *data;
guint active_ctx_cid;
enum ril_gprs_context_state state;
gulong regid;
struct ril_gprs_context_data_call *active_call;
struct ril_gprs_context_deactivate_req *deactivate_req;
gulong calls_changed_event_id;
struct ril_mtu_watch *mtu_watch;
struct ril_data_call *active_call;
struct ril_gprs_context_call activate;
struct ril_gprs_context_call deactivate;
};
struct ril_gprs_context_data_call {
guint status;
gint cid;
guint active;
int retry_time;
int prot;
gint mtu;
gchar *ifname;
gchar **dnses;
gchar **gateways;
gchar **addresses;
};
struct ril_gprs_context_data_call_list {
guint version;
guint num;
GSList *calls;
};
struct ril_gprs_context_cbd {
struct ril_gprs_context *gcd;
ofono_gprs_context_cb_t cb;
gpointer data;
};
struct ril_gprs_context_deactivate_req {
struct ril_gprs_context_cbd cbd;
gint cid;
};
#define ril_gprs_context_cbd_free g_free
#define ril_gprs_context_deactivate_req_free g_free
static inline struct ril_gprs_context *ril_gprs_context_get_data(
struct ofono_gprs_context *gprs)
{
return ofono_gprs_context_get_data(gprs);
}
static struct ril_gprs_context_cbd *ril_gprs_context_cbd_new(
struct ril_gprs_context *gcd, ofono_gprs_context_cb_t cb, void *data)
{
struct ril_gprs_context_cbd *cbd =
g_new0(struct ril_gprs_context_cbd, 1);
cbd->gcd = gcd;
cbd->cb = cb;
cbd->data = data;
return cbd;
}
static struct ril_gprs_context_deactivate_req *
ril_gprs_context_deactivate_req_new(struct ril_gprs_context *gcd,
ofono_gprs_context_cb_t cb, void *data)
{
struct ril_gprs_context_deactivate_req *req =
g_new0(struct ril_gprs_context_deactivate_req, 1);
req->cbd.gcd = gcd;
req->cbd.cb = cb;
req->cbd.data = data;
req->cid = gcd->active_call->cid;
return req;
}
static char *ril_gprs_context_netmask(const char *address)
{
if (address) {
@@ -152,34 +76,6 @@ static char *ril_gprs_context_netmask(const char *address)
return g_strdup("255.255.255.0");
}
static const char *ril_gprs_ofono_protocol_to_ril(guint protocol)
{
switch (protocol) {
case OFONO_GPRS_PROTO_IPV6:
return PROTO_IPV6_STR;
case OFONO_GPRS_PROTO_IPV4V6:
return PROTO_IPV4V6_STR;
case OFONO_GPRS_PROTO_IP:
return PROTO_IP_STR;
default:
return NULL;
}
}
static int ril_gprs_protocol_to_ofono(gchar *protocol_str)
{
if (protocol_str) {
if (!strcmp(protocol_str, PROTO_IPV6_STR)) {
return OFONO_GPRS_PROTO_IPV6;
} else if (!strcmp(protocol_str, PROTO_IPV4V6_STR)) {
return OFONO_GPRS_PROTO_IPV4V6;
} else if (!strcmp(protocol_str, PROTO_IP_STR)) {
return OFONO_GPRS_PROTO_IP;
}
}
return -1;
}
static void ril_gprs_context_set_ipv4(struct ofono_gprs_context *gc,
char * const *ip_addr)
{
@@ -209,34 +105,71 @@ static void ril_gprs_context_set_ipv6(struct ofono_gprs_context *gc,
}
}
static void ril_gprs_context_data_call_free(
struct ril_gprs_context_data_call *call)
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
{
if (gcd->active_call) {
ril_data_call_free(gcd->active_call);
gcd->active_call = NULL;
}
if (gcd->calls_changed_event_id) {
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
gcd->calls_changed_event_id = 0;
}
if (gcd->mtu_watch) {
ril_mtu_watch_free(gcd->mtu_watch);
gcd->mtu_watch = NULL;
}
}
static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
const struct ril_data_call *call)
{
if (call) {
g_free(call->ifname);
g_strfreev(call->dnses);
g_strfreev(call->addresses);
g_strfreev(call->gateways);
g_free(call);
ril_data_call_free(gcd->active_call);
gcd->active_call = ril_data_call_dup(call);
if (!gcd->mtu_watch) {
gcd->mtu_watch = ril_mtu_watch_new(MAX_MTU);
}
ril_mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
} else {
ril_gprs_context_free_active_call(gcd);
}
}
static void ril_gprs_context_set_disconnected(struct ril_gprs_context *gcd)
{
gcd->state = STATE_IDLE;
if (gcd->active_call) {
if (gcd->deactivate_req &&
gcd->deactivate_req->cid == gcd->active_call->cid) {
/* Mark this request as done */
gcd->deactivate_req->cbd.gcd = NULL;
gcd->deactivate_req = NULL;
ril_gprs_context_free_active_call(gcd);
if (gcd->deactivate.req) {
struct ril_gprs_context_call deact = gcd->deactivate;
/*
* Complete the deactivate request. We need to
* clear gcd->deactivate first because cancelling
* the deactivation request will probably result
* in ril_gprs_context_deactivate_primary_cb() being
* invoked with GRILIO_CANCELLED status. And we don't
* want to fail the disconnect request because this
* is a success (we wanted to disconnect the data
* call and it's gone).
*
* Additionally, we need to make sure that we don't
* complete the same request twice - that would crash
* the core.
*/
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
ril_data_request_cancel(deact.req);
if (deact.cb) {
struct ofono_error error;
ofono_info("Deactivated data call");
deact.cb(ril_error_ok(&error), deact.data);
}
}
ril_gprs_context_data_call_free(gcd->active_call);
gcd->active_call = NULL;
}
if (gcd->active_ctx_cid != CTX_ID_NONE) {
guint id = gcd->active_ctx_cid;
gcd->active_ctx_cid = CTX_ID_NONE;
DBG("ofono context %u deactivated", id);
ofono_gprs_context_deactivated(gcd->gc, id);
}
}
@@ -316,57 +249,10 @@ static void ril_gprs_split_dns_by_protocol(char **dns_array, char ***dns_addr,
}
}
static gint ril_gprs_context_parse_data_call_compare(gconstpointer a,
gconstpointer b)
{
const struct ril_gprs_context_data_call *ca = a;
const struct ril_gprs_context_data_call *cb = b;
if (ca->cid < cb->cid) {
return -1;
} else if (ca->cid > cb->cid) {
return 1;
} else {
return 0;
}
}
static void ril_gprs_context_data_call_free1(gpointer data)
{
ril_gprs_context_data_call_free(data);
}
static void ril_gprs_context_data_call_list_free(
struct ril_gprs_context_data_call_list *list)
{
if (list) {
g_slist_free_full(list->calls, ril_gprs_context_data_call_free1);
g_free(list);
}
}
static struct ril_gprs_context_data_call *ril_gprs_context_data_call_find(
struct ril_gprs_context_data_call_list *list, gint cid)
{
if (list) {
GSList *entry;
for (entry = list->calls; entry; entry = entry->next) {
struct ril_gprs_context_data_call *call = entry->data;
if (call->cid == cid) {
return call;
}
}
}
return NULL;
}
/* Only compares the stuff that's important to us */
static gboolean ril_gprs_context_data_call_equal(
const struct ril_gprs_context_data_call *c1,
const struct ril_gprs_context_data_call *c2)
const struct ril_data_call *c1,
const struct ril_data_call *c2)
{
if (!c1 && !c2) {
return TRUE;
@@ -382,134 +268,58 @@ static gboolean ril_gprs_context_data_call_equal(
}
}
static struct ril_gprs_context_data_call *
ril_gprs_context_parse_data_call(int version, GRilIoParser *rilp)
static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
{
char *prot;
struct ril_gprs_context_data_call *call =
g_new0(struct ril_gprs_context_data_call, 1);
grilio_parser_get_uint32(rilp, &call->status);
grilio_parser_get_int32(rilp, &call->retry_time);
grilio_parser_get_int32(rilp, &call->cid);
grilio_parser_get_uint32(rilp, &call->active);
prot = grilio_parser_get_utf8(rilp);
call->ifname = grilio_parser_get_utf8(rilp);
call->addresses = grilio_parser_split_utf8(rilp, " ");
call->dnses = grilio_parser_split_utf8(rilp, " ");
call->gateways = grilio_parser_split_utf8(rilp, " ");
call->prot = ril_gprs_protocol_to_ofono(prot);
if (call->prot < 0) {
ofono_error("Invalid type(protocol) specified: %s", prot);
}
g_free(prot);
if (version >= 9) {
/* PCSCF */
grilio_parser_skip_string(rilp);
if (version >= 11) {
/* MTU */
grilio_parser_get_int32(rilp, &call->mtu);
}
}
return call;
}
static struct ril_gprs_context_data_call_list *
ril_gprs_context_parse_data_call_list(const void *data, guint len)
{
struct ril_gprs_context_data_call_list *reply =
g_new0(struct ril_gprs_context_data_call_list, 1);
GRilIoParser rilp;
unsigned int i, n;
grilio_parser_init(&rilp, data, len);
grilio_parser_get_uint32(&rilp, &reply->version);
grilio_parser_get_uint32(&rilp, &n);
DBG("version=%d,num=%d", reply->version, n);
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
struct ril_gprs_context_data_call *call =
ril_gprs_context_parse_data_call(reply->version, &rilp);
DBG("%d [status=%d,retry=%d,cid=%d,"
"active=%d,type=%s,ifname=%s,mtu=%d,"
"address=%s, dns=%s %s,gateways=%s]",
i, call->status, call->retry_time,
call->cid, call->active,
ril_gprs_ofono_protocol_to_ril(call->prot),
call->ifname, call->mtu, call->addresses[0],
call->dnses[0],
(call->dnses[0] && call->dnses[1]) ?
call->dnses[1] : "",
call->gateways[0]);
reply->num++;
reply->calls = g_slist_insert_sorted(reply->calls, call,
ril_gprs_context_parse_data_call_compare);
}
return reply;
}
static void ril_gprs_context_call_list_changed(GRilIoChannel *io, guint event,
const void *data, guint len, void *user_data)
{
struct ril_gprs_context *gcd = user_data;
struct ril_gprs_context *gcd = arg;
struct ofono_gprs_context *gc = gcd->gc;
struct ril_gprs_context_data_call *call = NULL;
struct ril_gprs_context_data_call *prev_call;
struct ril_gprs_context_data_call_list *unsol =
ril_gprs_context_parse_data_call_list(data, len);
if (gcd->active_call) {
/* Find our call */
call = ril_gprs_context_data_call_find(unsol,
gcd->active_call->cid);
if (call) {
/* Check if the call have been disconnected */
if (call->active == DATA_CALL_INACTIVE) {
ofono_error("Clearing active context");
ril_gprs_context_set_disconnected(gcd);
call = NULL;
/*
* gcd->active_call can't be NULL here because this callback
* is only registered when we have the active call and released
* when active call is dropped.
*/
struct ril_data_call *prev_call = gcd->active_call;
const struct ril_data_call *call =
ril_data_call_find(data->data_calls, prev_call->cid);
/* Compare it agains the last known state */
} else if (ril_gprs_context_data_call_equal(call,
gcd->active_call)) {
DBG("call %u didn't change", call->cid);
call = NULL;
} else {
/* Steal it from the list */
DBG("call %u changed", call->cid);
unsol->calls = g_slist_remove(unsol->calls,
call);
}
} else {
if (call) {
/* Check if the call has been disconnected */
if (call->active == RIL_DATA_CALL_INACTIVE) {
ofono_error("Clearing active context");
ril_gprs_context_set_disconnected(gcd);
}
}
call = NULL;
/* We don't need the rest of the list anymore */
ril_gprs_context_data_call_list_free(unsol);
/* Compare it against the last known state */
} else if (ril_gprs_context_data_call_equal(call, prev_call)) {
DBG("call %u didn't change", call->cid);
call = NULL;
} else {
DBG("call %u changed", call->cid);
}
} else {
ofono_error("Clearing active context");
ril_gprs_context_set_disconnected(gcd);
}
if (!call) {
/* We are not interested */
return;
}
/* Store the updated call data */
prev_call = gcd->active_call;
gcd->active_call = call;
/*
* prev_call points to the previous active call, and it will
* be deallocated at the end of the this function. Clear the
* gcd->active_call pointer so that we don't deallocate it twice.
*/
gcd->active_call = NULL;
ril_gprs_context_set_active_call(gcd, call);
if (call->status != 0) {
if (call->status != PDP_FAIL_NONE) {
ofono_info("data call status: %d", call->status);
}
if (call->active == DATA_CALL_ACTIVE) {
if (call->active == RIL_DATA_CALL_ACTIVE) {
gboolean signal = FALSE;
if (call->ifname && g_strcmp0(call->ifname, prev_call->ifname)) {
@@ -605,51 +415,35 @@ static void ril_gprs_context_call_list_changed(GRilIoChannel *io, guint event,
}
}
ril_gprs_context_data_call_free(prev_call);
ril_data_call_free(prev_call);
}
static void ril_gprs_context_activate_primary_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
int ril_status, const struct ril_data_call *call,
void *user_data)
{
struct ril_gprs_context_cbd *cbd = user_data;
ofono_gprs_context_cb_t cb = cbd->cb;
struct ril_gprs_context *gcd = cbd->gcd;
struct ril_gprs_context *gcd = user_data;
struct ofono_gprs_context *gc = gcd->gc;
struct ofono_error error;
struct ril_gprs_context_data_call_list *reply = NULL;
struct ril_gprs_context_data_call *call;
char **split_ip_addr = NULL;
char **split_ipv6_addr = NULL;
char* ip_gw = NULL;
char* ipv6_gw = NULL;
char** dns_addr = NULL;
char** dns_ipv6_addr = NULL;
ofono_gprs_context_cb_t cb;
gpointer cb_data;
ofono_info("setting up data call");
ril_error_init_ok(&error);
if (status != RIL_E_SUCCESS) {
ril_error_init_failure(&error);
if (ril_status != RIL_E_SUCCESS) {
ofono_error("GPRS context: Reply failure: %s",
ril_error_to_string(status));
error.type = OFONO_ERROR_TYPE_FAILURE;
error.error = status;
ril_gprs_context_set_disconnected(gcd);
ril_error_to_string(ril_status));
goto done;
}
reply = ril_gprs_context_parse_data_call_list(data, len);
if (reply->num != 1) {
ofono_error("Number of data calls: %u", reply->num);
ril_error_init_failure(&error);
ril_gprs_context_set_disconnected(gcd);
goto done;
}
call = reply->calls->data;
if (call->status != 0) {
if (call->status != PDP_FAIL_NONE) {
ofono_error("Unexpected data call status %d", call->status);
error.type = OFONO_ERROR_TYPE_FAILURE;
error.type = OFONO_ERROR_TYPE_CMS;
error.error = call->status;
goto done;
}
@@ -657,46 +451,35 @@ static void ril_gprs_context_activate_primary_cb(GRilIoChannel *io, int status,
/* Must have interface */
if (!call->ifname) {
ofono_error("GPRS context: No interface");
error.type = OFONO_ERROR_TYPE_FAILURE;
error.error = EINVAL;
ril_gprs_context_set_disconnected(gcd);
goto done;
}
ofono_info("setting up data call");
/* Check the ip address */
ril_gprs_split_ip_by_protocol(call->addresses, &split_ip_addr,
&split_ipv6_addr);
if (!split_ip_addr && !split_ipv6_addr) {
ofono_error("GPRS context: No IP address");
error.type = OFONO_ERROR_TYPE_FAILURE;
error.error = EINVAL;
ril_gprs_context_set_disconnected(gcd);
goto done;
}
/* Steal the call data from the list */
g_slist_free(reply->calls);
reply->calls = NULL;
ril_gprs_context_data_call_free(gcd->active_call);
gcd->active_call = call;
gcd->state = STATE_ACTIVE;
ril_error_init_ok(&error);
ril_gprs_context_set_active_call(gcd, call);
GASSERT(!gcd->calls_changed_event_id);
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
gcd->calls_changed_event_id =
ril_data_add_calls_changed_handler(gcd->data,
ril_gprs_context_call_list_changed, gcd);
ofono_gprs_context_set_interface(gc, call->ifname);
ril_gprs_split_gw_by_protocol(call->gateways, &ip_gw, &ipv6_gw);
ril_gprs_split_dns_by_protocol(call->dnses, &dns_addr, &dns_ipv6_addr);
/* TODO:
* RILD can return multiple addresses; oFono only supports setting
* a single IPv4 and single IPV6 address. At this time, we only use
* the first address. It's possible that a RIL may just specify
* the end-points of the point-to-point connection, in which case this
* code will need to changed to handle such a device.
*/
if (split_ipv6_addr &&
(call->prot == OFONO_GPRS_PROTO_IPV6 ||
call->prot == OFONO_GPRS_PROTO_IPV4V6)) {
ril_gprs_context_set_ipv6(gc, split_ipv6_addr);
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
ofono_gprs_context_set_ipv6_dns_servers(gc,
@@ -713,7 +496,6 @@ static void ril_gprs_context_activate_primary_cb(GRilIoChannel *io, int status,
}
done:
ril_gprs_context_data_call_list_free(reply);
g_strfreev(split_ip_addr);
g_strfreev(split_ipv6_addr);
g_strfreev(dns_addr);
@@ -721,7 +503,17 @@ done:
g_free(ip_gw);
g_free(ipv6_gw);
cb(&error, cbd->data);
cb = gcd->activate.cb;
cb_data = gcd->activate.data;
GASSERT(gcd->activate.req);
memset(&gcd->activate, 0, sizeof(gcd->activate));
if (cb) {
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
gcd->active_ctx_cid = CTX_ID_NONE;
}
cb(&error, cb_data);
}
}
static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
@@ -730,14 +522,11 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gcd->modem);
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
const int rs = ofono_netreg_get_status(netreg);
const gchar *protocol_str;
GRilIoRequest* req;
int tech, auth;
/* Let's make sure that we aren't connecting when roaming not allowed */
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
if (!ofono_gprs_get_roaming_allowed(gprs) &&
ril_netreg_check_if_really_roaming(netreg, rs) ==
NETWORK_REGISTRATION_STATUS_ROAMING) {
@@ -750,135 +539,51 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
}
ofono_info("Activating context: %d", ctx->cid);
protocol_str = ril_gprs_ofono_protocol_to_ril(ctx->proto);
GASSERT(protocol_str);
/* ril.h has this to say about the radio tech parameter:
*
* ((const char **)data)[0] Radio technology to use: 0-CDMA,
* 1-GSM/UMTS, 2... for values above 2
* this is RIL_RadioTechnology + 2.
*
* Makes little sense but it is what it is.
*/
tech = gcd->network->data.ril_tech;
if (tech > 2) {
tech += 2;
} else {
/*
* This value used to be hardcoded, let's keep using it
* as the default.
*/
tech = RADIO_TECH_HSPA;
}
/*
* We do the same as in $AOSP/frameworks/opt/telephony/src/java/com/
* android/internal/telephony/dataconnection/DataConnection.java,
* onConnect(), and use authentication or not depending on whether
* the user field is empty or not.
*/
auth = (ctx->username && ctx->username[0]) ?
RIL_AUTH_BOTH : RIL_AUTH_NONE;
/*
* TODO: add comments about tethering, other non-public
* profiles...
*/
req = grilio_request_new();
grilio_request_append_int32(req, SETUP_DATA_CALL_PARAMS);
grilio_request_append_format(req, "%d", tech);
grilio_request_append_utf8(req, DATA_PROFILE_DEFAULT_STR);
grilio_request_append_utf8(req, ctx->apn);
grilio_request_append_utf8(req, ctx->username);
grilio_request_append_utf8(req, ctx->password);
grilio_request_append_format(req, "%d", auth);
grilio_request_append_utf8(req, protocol_str);
GASSERT(!gcd->activate.req);
GASSERT(ctx->cid != CTX_ID_NONE);
gcd->active_ctx_cid = ctx->cid;
gcd->state = STATE_ACTIVATING;
grilio_queue_send_request_full(gcd->q, req, RIL_REQUEST_SETUP_DATA_CALL,
ril_gprs_context_activate_primary_cb, ril_gprs_context_cbd_free,
ril_gprs_context_cbd_new(gcd, cb, data));
grilio_request_unref(req);
gcd->activate.cb = cb;
gcd->activate.data = data;
gcd->activate.req = ril_data_call_setup(gcd->data, ctx,
ril_gprs_context_activate_primary_cb, gcd);
}
static void ril_gprs_context_deactivate_data_call_cb(GRilIoChannel *io, int err,
const void *data, guint len, void *user_data)
static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
int ril_status, void *user_data)
{
struct ofono_error error;
struct ril_gprs_context_deactivate_req *req = user_data;
struct ril_gprs_context *gcd = req->cbd.gcd;
if (!gcd) {
/*
* ril_gprs_context_remove() zeroes gcd pointer for the
* pending ril_gprs_context_deactivate_req. Or we may have
* received RIL_UNSOL_DATA_CALL_LIST_CHANGED event before
* RIL_REQUEST_DEACTIVATE_DATA_CALL completes, in which
* case gcd will also be NULL. In any case, it means that
* there's nothing left for us to do here. Just ignore it.
*/
DBG("late completion, cid: %d err: %d", req->cid, err);
} else {
ofono_gprs_context_cb_t cb = req->cbd.cb;
/* Mark it as done */
if (gcd->deactivate_req == req) {
gcd->deactivate_req = NULL;
}
if (err == RIL_E_SUCCESS) {
GASSERT(gcd->active_call &&
gcd->active_call->cid == req->cid);
ril_gprs_context_set_disconnected(gcd);
ofono_info("Deactivated data call");
if (cb) {
cb(ril_error_ok(&error), req->cbd.data);
}
} else {
ofono_error("Deactivate failure: %s",
ril_error_to_string(err));
if (cb) {
cb(ril_error_failure(&error), req->cbd.data);
}
}
}
}
static void ril_gprs_context_deactivate_data_call(struct ril_gprs_context *gcd,
ofono_gprs_context_cb_t cb, void *data)
{
GRilIoRequest *req = grilio_request_new();
/* Overlapping deactivate requests make no sense */
GASSERT(!gcd->deactivate_req);
if (gcd->deactivate_req) {
gcd->deactivate_req->cbd.gcd = NULL;
}
gcd->deactivate_req =
ril_gprs_context_deactivate_req_new(gcd, cb, data);
/* Caller is responsible for checking gcd->active_call */
GASSERT(gcd->active_call);
grilio_request_append_int32(req, DEACTIVATE_DATA_CALL_PARAMS);
grilio_request_append_format(req, "%d", gcd->active_call->cid);
grilio_request_append_format(req, "%d",
RIL_DEACTIVATE_DATA_CALL_NO_REASON);
struct ril_gprs_context *gcd = user_data;
/*
* Send it to GRilIoChannel so that it doesn't get cancelled
* by ril_gprs_context_remove()
* Data call list may change before the completion of the deactivate
* request, in that case ril_gprs_context_set_disconnected will be
* invoked and gcd->deactivate.req will be NULL.
*/
grilio_channel_send_request_full(gcd->io, req,
RIL_REQUEST_DEACTIVATE_DATA_CALL,
ril_gprs_context_deactivate_data_call_cb,
ril_gprs_context_deactivate_req_free,
gcd->deactivate_req);
grilio_request_unref(req);
gcd->state = STATE_DEACTIVATING;
if (gcd->deactivate.req) {
struct ofono_error error;
ofono_gprs_context_cb_t cb = gcd->deactivate.cb;
gpointer cb_data = gcd->deactivate.data;
if (ril_status == RIL_E_SUCCESS) {
GASSERT(gcd->active_call);
ril_error_init_ok(&error);
ofono_info("Deactivated data call");
} else {
ril_error_init_failure(&error);
ofono_error("Deactivate failure: %s",
ril_error_to_string(ril_status));
}
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
if (cb) {
ril_gprs_context_free_active_call(gcd);
cb(&error, cb_data);
return;
}
}
/* Make sure we are in the disconnected state */
ril_gprs_context_set_disconnected(gcd);
}
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
@@ -886,13 +591,16 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
GASSERT(cb);
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
ofono_info("Deactivate primary");
if (gcd->active_call && gcd->active_ctx_cid == id) {
ril_gprs_context_deactivate_data_call(gcd, cb, data);
} else {
gcd->deactivate.cb = cb;
gcd->deactivate.data = data;
gcd->deactivate.req = ril_data_call_deactivate(gcd->data,
gcd->active_call->cid,
ril_gprs_context_deactivate_primary_cb, gcd);
} else if (cb) {
struct ofono_error error;
cb(ril_error_ok(&error), data);
}
@@ -901,13 +609,8 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
unsigned int id)
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
DBG("%d", id);
GASSERT(gcd->active_ctx_cid == id);
if (gcd->active_call && !gcd->deactivate_req) {
ril_gprs_context_deactivate_data_call(gcd, NULL, NULL);
}
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
}
static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
@@ -920,12 +623,8 @@ static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
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,
ril_gprs_context_call_list_changed,
RIL_UNSOL_DATA_CALL_LIST_CHANGED, gcd);
ril_gprs_context_set_disconnected(gcd);
gcd->data = ril_data_ref(modem->data);
gcd->active_ctx_cid = CTX_ID_NONE;
ofono_gprs_context_set_data(gc, gcd);
return 0;
}
@@ -937,20 +636,29 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
DBG("");
ofono_gprs_context_set_data(gc, NULL);
if (gcd->active_call && !gcd->deactivate_req) {
ril_gprs_context_deactivate_data_call(gcd, NULL, NULL);
if (gcd->activate.req) {
/*
* The core has already completed its pending D-Bus
* request, invoking the completion callback will
* cause libdbus to panic.
*/
ril_data_request_detach(gcd->activate.req);
ril_data_request_cancel(gcd->activate.req);
}
if (gcd->deactivate_req) {
gcd->deactivate_req->cbd.gcd = NULL;
if (gcd->deactivate.req) {
/* Let it complete but we won't be around to be notified. */
ril_data_request_detach(gcd->deactivate.req);
} else if (gcd->active_call) {
ril_data_call_deactivate(gcd->data, gcd->active_call->cid,
NULL, NULL);
}
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
ril_data_unref(gcd->data);
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);
grilio_queue_unref(gcd->q);
ril_gprs_context_data_call_free(gcd->active_call);
ril_data_call_free(gcd->active_call);
ril_mtu_watch_free(gcd->mtu_watch);
g_free(gcd);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 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,118 +14,251 @@
*/
#include "ril_mce.h"
#include "ril_constants.h"
#include "ril_log.h"
#include <grilio_channel.h>
#include <grilio_request.h>
#include <ofono/log.h>
#include <ofono/dbus.h>
#include <gdbus.h>
/* <mce/dbus-names.h> */
#define MCE_SERVICE "com.nokia.mce"
#define MCE_SIGNAL_IF "com.nokia.mce.signal"
#define MCE_REQUEST_IF "com.nokia.mce.request"
#define MCE_REQUEST_PATH "/com/nokia/mce/request"
#define MCE_DISPLAY_STATUS_GET "get_display_status"
#define MCE_DISPLAY_SIG "display_status_ind"
#define MCE_DISPLAY_DIM_STRING "dimmed"
#define MCE_DISPLAY_ON_STRING "on"
#define MCE_DISPLAY_OFF_STRING "off"
struct ril_mce {
typedef GObjectClass RilMceClass;
typedef struct ril_mce RilMce;
struct ril_mce_priv {
GRilIoChannel *io;
DBusConnection *conn;
int screen_state;
DBusPendingCall *req;
guint daemon_watch;
guint signal_watch;
};
static void ril_mce_send_screen_state(struct ril_mce *mce, gboolean on)
enum ril_mce_signal {
SIGNAL_DISPLAY_STATE_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_DISPLAY_STATE_CHANGED_NAME "ril-mce-display-state-changed"
static guint ril_mce_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilMce, ril_mce, G_TYPE_OBJECT)
#define RIL_MCE_TYPE (ril_mce_get_type())
#define RIL_MCE(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_MCE_TYPE,RilMce))
static const char *ril_mce_display_state_string(enum ril_mce_display_state ds)
{
GRilIoRequest *req = grilio_request_sized_new(8);
switch (ds) {
case RIL_MCE_DISPLAY_OFF:
return MCE_DISPLAY_OFF_STRING;
case RIL_MCE_DISPLAY_DIM:
return MCE_DISPLAY_DIM_STRING;
case RIL_MCE_DISPLAY_ON:
return MCE_DISPLAY_ON_STRING;
default:
return NULL;
}
}
grilio_request_append_int32(req, 1); /* Number of params */
grilio_request_append_int32(req, on); /* screen on/off */
static enum ril_mce_display_state ril_mce_parse_display_state(DBusMessage *msg)
{
DBusMessageIter it;
grilio_channel_send_request(mce->io, req, RIL_REQUEST_SCREEN_STATE);
grilio_request_unref(req);
if (dbus_message_iter_init(msg, &it) &&
dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_STRING) {
const char *value = NULL;
dbus_message_iter_get_basic(&it, &value);
if (!g_strcmp0(value, MCE_DISPLAY_OFF_STRING)) {
return RIL_MCE_DISPLAY_OFF;
} else if (!g_strcmp0(value, MCE_DISPLAY_DIM_STRING)) {
return RIL_MCE_DISPLAY_DIM;
} else {
GASSERT(!g_strcmp0(value, MCE_DISPLAY_ON_STRING));
}
}
return RIL_MCE_DISPLAY_ON;
}
static void ril_mce_update_display_state(struct ril_mce *self,
enum ril_mce_display_state state)
{
if (self->display_state != state) {
self->display_state = state;
g_signal_emit(self, ril_mce_signals[
SIGNAL_DISPLAY_STATE_CHANGED], 0);
}
}
static gboolean ril_mce_display_changed(DBusConnection *conn,
DBusMessage *message, void *user_data)
DBusMessage *msg, void *user_data)
{
DBusMessageIter iter;
if (dbus_message_iter_init(message, &iter) &&
dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
struct ril_mce *mce = user_data;
const char *value = NULL;
int state;
dbus_message_iter_get_basic(&iter, &value);
DBG(" %s", value);
/* It is on if it's not off */
state = (g_strcmp0(value, MCE_DISPLAY_OFF_STRING) != 0);
if (mce->screen_state != state) {
mce->screen_state = state;
ril_mce_send_screen_state(mce, state);
}
} else {
DBG("");
}
enum ril_mce_display_state state = ril_mce_parse_display_state(msg);
DBG("%s", ril_mce_display_state_string(state));
ril_mce_update_display_state(RIL_MCE(user_data), state);
return TRUE;
}
static void ril_mce_display_status_reply(DBusPendingCall *call, void *user_data)
{
struct ril_mce *self = RIL_MCE(user_data);
struct ril_mce_priv *priv = self->priv;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
enum ril_mce_display_state state = ril_mce_parse_display_state(reply);
GASSERT(priv->req);
dbus_message_unref(reply);
dbus_pending_call_unref(priv->req);
priv->req = NULL;
DBG("%s", ril_mce_display_state_string(state));
ril_mce_update_display_state(self, state);
}
static void ril_mce_connect(DBusConnection *conn, void *user_data)
{
struct ril_mce *mce = user_data;
struct ril_mce *self = RIL_MCE(user_data);
struct ril_mce_priv *priv = self->priv;
DBG("");
if (!mce->signal_watch) {
mce->signal_watch = g_dbus_add_signal_watch(conn,
if (!priv->req) {
DBusMessage *msg = dbus_message_new_method_call(MCE_SERVICE,
MCE_REQUEST_PATH, MCE_REQUEST_IF,
MCE_DISPLAY_STATUS_GET);
if (g_dbus_send_message_with_reply(conn, msg, &priv->req, -1)) {
dbus_pending_call_set_notify(priv->req,
ril_mce_display_status_reply,
self, NULL);
dbus_message_unref(msg);
}
}
if (!priv->signal_watch) {
priv->signal_watch = g_dbus_add_signal_watch(conn,
MCE_SERVICE, NULL, MCE_SIGNAL_IF, MCE_DISPLAY_SIG,
ril_mce_display_changed, mce, NULL);
ril_mce_display_changed, self, NULL);
}
}
static void ril_mce_disconnect(DBusConnection *conn, void *user_data)
{
struct ril_mce *mce = user_data;
struct ril_mce *self = user_data;
struct ril_mce_priv *priv = self->priv;
DBG("");
if (mce->signal_watch) {
g_dbus_remove_watch(conn, mce->signal_watch);
mce->signal_watch = 0;
if (priv->signal_watch) {
g_dbus_remove_watch(conn, priv->signal_watch);
priv->signal_watch = 0;
}
if (priv->req) {
dbus_pending_call_cancel(priv->req);
dbus_pending_call_unref(priv->req);
}
}
struct ril_mce *ril_mce_new(GRilIoChannel *io)
struct ril_mce *ril_mce_new()
{
struct ril_mce *mce = g_new0(struct ril_mce, 1);
struct ril_mce *self = g_object_new(RIL_MCE_TYPE, NULL);
struct ril_mce_priv *priv = self->priv;
mce->conn = dbus_connection_ref(ofono_dbus_get_connection());
mce->io = grilio_channel_ref(io);
mce->screen_state = -1;
mce->daemon_watch = g_dbus_add_service_watch(mce->conn, MCE_SERVICE,
ril_mce_connect, ril_mce_disconnect, mce, NULL);
return mce;
DBG("");
priv->daemon_watch = g_dbus_add_service_watch(priv->conn, MCE_SERVICE,
ril_mce_connect, ril_mce_disconnect, self, NULL);
return self;
}
void ril_mce_free(struct ril_mce *mce)
struct ril_mce *ril_mce_ref(struct ril_mce *self)
{
if (mce) {
if (mce->signal_watch) {
g_dbus_remove_watch(mce->conn, mce->signal_watch);
}
if (mce->daemon_watch) {
g_dbus_remove_watch(mce->conn, mce->daemon_watch);
}
dbus_connection_unref(mce->conn);
grilio_channel_unref(mce->io);
g_free(mce);
if (G_LIKELY(self)) {
g_object_ref(RIL_MCE(self));
return self;
} else {
return NULL;
}
}
void ril_mce_unref(struct ril_mce *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_MCE(self));
}
}
gulong ril_mce_add_display_state_changed_handler(struct ril_mce *self,
ril_mce_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_DISPLAY_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_mce_remove_handler(struct ril_mce *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
static void ril_mce_init(struct ril_mce *self)
{
struct ril_mce_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_MCE_TYPE, struct ril_mce_priv);
priv->conn = dbus_connection_ref(ofono_dbus_get_connection());
self->priv = priv;
}
static void ril_mce_dispose(GObject *object)
{
struct ril_mce *self = RIL_MCE(object);
struct ril_mce_priv *priv = self->priv;
if (priv->signal_watch) {
g_dbus_remove_watch(priv->conn, priv->signal_watch);
priv->signal_watch = 0;
}
if (priv->daemon_watch) {
g_dbus_remove_watch(priv->conn, priv->daemon_watch);
priv->daemon_watch = 0;
}
if (priv->req) {
dbus_pending_call_cancel(priv->req);
dbus_pending_call_unref(priv->req);
}
G_OBJECT_CLASS(ril_mce_parent_class)->dispose(object);
}
static void ril_mce_finalize(GObject *object)
{
struct ril_mce *self = RIL_MCE(object);
struct ril_mce_priv *priv = self->priv;
dbus_connection_unref(priv->conn);
G_OBJECT_CLASS(ril_mce_parent_class)->finalize(object);
}
static void ril_mce_class_init(RilMceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_mce_dispose;
object_class->finalize = ril_mce_finalize;
g_type_class_add_private(klass, sizeof(struct ril_mce_priv));
ril_mce_signals[SIGNAL_DISPLAY_STATE_CHANGED] =
g_signal_new(SIGNAL_DISPLAY_STATE_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*
* 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,8 +18,27 @@
#include "ril_types.h"
struct ril_mce *ril_mce_new(GRilIoChannel *io);
void ril_mce_free(struct ril_mce *mce);
enum ril_mce_display_state {
RIL_MCE_DISPLAY_OFF,
RIL_MCE_DISPLAY_DIM,
RIL_MCE_DISPLAY_ON
};
struct ril_mce_priv;
struct ril_mce {
GObject object;
struct ril_mce_priv *priv;
enum ril_mce_display_state display_state;
};
struct ril_mce *ril_mce_new(void);
struct ril_mce *ril_mce_ref(struct ril_mce *mce);
void ril_mce_unref(struct ril_mce *mce);
typedef void (*ril_mce_cb_t)(struct ril_mce *mce, void *arg);
gulong ril_mce_add_display_state_changed_handler(struct ril_mce *mce,
ril_mce_cb_t cb, void *arg);
void ril_mce_remove_handler(struct ril_mce *mce, gulong id);
#endif /* RIL_MCE_H */

View File

@@ -9,7 +9,7 @@
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
@@ -17,6 +17,7 @@
#include "ril_network.h"
#include "ril_radio.h"
#include "ril_sim_card.h"
#include "ril_sim_settings.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -50,10 +51,9 @@ struct ril_modem_data {
struct ril_modem modem;
GRilIoQueue *q;
struct ofono_radio_settings *radio_settings;
char *default_name;
char *imei;
char *ecclist_file;
gboolean pre_sim_done;
gboolean devinfo_created;
gboolean allow_data;
guint online_check_id;
@@ -63,6 +63,9 @@ struct ril_modem_data {
ril_modem_cb_t removed_cb;
void *removed_cb_data;
ril_modem_online_cb_t online_cb;
void *online_cb_data;
struct ril_modem_online_request set_online;
struct ril_modem_online_request set_offline;
};
@@ -127,25 +130,13 @@ void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
md->removed_cb_data = data;
}
static void ril_modem_check_devinfo(struct ril_modem_data *md)
{
/* 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);
}
}
void ril_modem_set_imei(struct ril_modem *modem, const char *imei)
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
void *data)
{
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
if (md) {
g_free(md->imei);
modem->imei = md->imei = g_strdup(imei);
ril_modem_check_devinfo(md);
}
md->online_cb = cb;
md->online_cb_data = data;
}
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
@@ -208,7 +199,8 @@ static gboolean ril_modem_online_request_timeout(gpointer data)
req->data = NULL;
cb(ril_error_failure(&error), cb_data);
ril_modem_update_online_state(req->md);
return FALSE;
return G_SOURCE_REMOVE;
}
static gboolean ril_modem_online_check(gpointer data)
@@ -251,7 +243,7 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *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)
{
@@ -259,7 +251,7 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
DBG("%s", ofono_modem_get_path(modem));
md->pre_sim_done = TRUE;
ril_modem_check_devinfo(md);
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
ril_modem_update_radio_settings(md);
@@ -308,7 +300,6 @@ static void ril_modem_post_online(struct ofono_modem *modem)
ofono_netreg_create(modem, 0, RILMODEM_DRIVER, md);
ofono_ussd_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_settings_create(modem, 0, RILMODEM_DRIVER, md);
ofono_oem_raw_create(modem, 0, RILMODEM_DRIVER, md);
}
static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
@@ -320,6 +311,10 @@ static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
DBG("%s going %sline", ofono_modem_get_path(modem),
online ? "on" : "off");
if (md->online_cb) {
md->online_cb(&md->modem, online, md->online_cb_data);
}
if (online) {
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
req = &md->set_online;
@@ -402,19 +397,20 @@ static void ril_modem_remove(struct ofono_modem *ofono)
ril_network_unref(modem->network);
ril_sim_card_unref(modem->sim_card);
ril_sim_settings_unref(modem->sim_settings);
ril_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->ecclist_file);
g_free(md->imei);
g_free(md);
}
struct ril_modem *ril_modem_create(GRilIoChannel *io,
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,
struct ril_network *network, struct ril_sim_card *card,
struct ril_data *data)
struct ril_data *data, struct ril_sim_settings *settings)
{
/* Skip the slash from the path, it looks like "/ril_0" */
struct ofono_modem *ofono = ofono_modem_create(slot->path + 1,
@@ -424,22 +420,24 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io,
struct ril_modem_data *md = g_new0(struct ril_modem_data, 1);
struct ril_modem *modem = &md->modem;
/*
* ril_plugin.c must wait until IMEI becomes known before
* creating the modem
*/
GASSERT(slot->imei);
/* Copy config */
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",
slot->config->slot + 1);
}
modem->config.default_name = md->default_name;
modem->log_prefix = log_prefix;
modem->ecclist_file =
md->ecclist_file = g_strdup(slot->ecclist_file);
modem->ofono = ofono;
modem->radio = ril_radio_ref(radio);
modem->network = ril_network_ref(network);
modem->sim_card = ril_sim_card_ref(card);
modem->sim_settings = ril_sim_settings_ref(settings);
modem->data = ril_data_ref(data);
modem->io = grilio_channel_ref(io);
md->q = grilio_queue_new(io);
@@ -449,7 +447,6 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io,
err = ofono_modem_register(ofono);
if (!err) {
ril_radio_power_cycle(modem->radio);
ril_radio_power_on(modem->radio, RADIO_POWER_TAG(md));
GASSERT(io->connected);
/*
@@ -459,6 +456,15 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io,
ofono_modem_set_powered(modem->ofono, FALSE);
ofono_modem_set_powered(modem->ofono, TRUE);
md->power_state = POWERED_ON;
/*
* With some RIL implementations, querying available
* band modes causes some magic Android properties to
* appear. Otherwise this request is pretty harmless
* and useless.
*/
grilio_queue_send_request(md->q, NULL,
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
return modem;
} else {
ofono_error("Error %d registering %s",

223
ofono/drivers/ril/ril_mtu.c Normal file
View File

@@ -0,0 +1,223 @@
/*
* 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_mtu.h"
#include "ril_log.h"
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
struct ril_mtu_watch {
int max_mtu;
char *ifname;
void *buf;
int bufsize;
GIOChannel *channel;
guint io_watch;
int fd;
};
static void ril_mtu_watch_limit_mtu(struct ril_mtu_watch *self)
{
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd >= 0) {
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, self->ifname, IFNAMSIZ);
if (ioctl(fd, SIOCGIFMTU, &ifr) < 0 ||
ifr.ifr_mtu > self->max_mtu) {
DBG("%s mtu %d => %d", self->ifname, ifr.ifr_mtu,
self->max_mtu);
ifr.ifr_mtu = self->max_mtu;
if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
ofono_error("Failed to set MTU");
}
}
close(fd);
}
}
static void ril_mtu_watch_handle_rtattr(struct ril_mtu_watch *self,
const struct rtattr *rta, int len)
{
int mtu = 0;
const char *ifname = NULL;
while (len > 0 && RTA_OK(rta, len) && (!mtu || !ifname)) {
switch (rta->rta_type) {
case IFLA_IFNAME:
ifname = RTA_DATA(rta);
break;
case IFLA_MTU:
mtu = *((int*)RTA_DATA(rta));
break;
}
rta = RTA_NEXT(rta, len);
}
if (mtu > self->max_mtu && !g_strcmp0(ifname, self->ifname)) {
DBG("%s %d", ifname, mtu);
ril_mtu_watch_limit_mtu(self);
}
}
static void ril_mtu_watch_handle_ifinfomsg(struct ril_mtu_watch *self,
const struct ifinfomsg *ifi, int len)
{
if (ifi->ifi_flags & IFF_UP) {
const struct rtattr *rta = IFLA_RTA(ifi);
ril_mtu_watch_handle_rtattr(self, rta,
len - ((char*)rta - (char*)ifi));
}
}
static void ril_mtu_watch_handle_nlmsg(struct ril_mtu_watch *self,
const struct nlmsghdr *hdr, int len)
{
while (len > 0 && NLMSG_OK(hdr, len)) {
if (hdr->nlmsg_type == RTM_NEWLINK) {
ril_mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr),
IFLA_PAYLOAD(hdr));
}
hdr = NLMSG_NEXT(hdr, len);
}
}
static gboolean ril_mtu_watch_event(GIOChannel *ch, GIOCondition cond,
gpointer data)
{
struct ril_mtu_watch *self = data;
struct sockaddr_nl addr;
socklen_t addrlen = sizeof(addr);
ssize_t result = recvfrom(self->fd, self->buf, self->bufsize, 0,
(struct sockaddr *)&addr, &addrlen);
if (result > 0) {
if (!addr.nl_pid) {
ril_mtu_watch_handle_nlmsg(self, self->buf, result);
}
return G_SOURCE_CONTINUE;
} else if (result == 0 || errno == EINTR || errno == EAGAIN) {
return G_SOURCE_CONTINUE;
} else {
DBG("%s error %d", self->ifname, errno);
self->io_watch = 0;
return G_SOURCE_REMOVE;
}
}
static gboolean ril_mtu_watch_open_socket(struct ril_mtu_watch *self)
{
GASSERT(self->fd < 0);
self->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (self->fd >= 0) {
struct sockaddr_nl nl;
memset(&nl, 0, sizeof(nl));
nl.nl_pid = getpid();
nl.nl_family = AF_NETLINK;
nl.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE |
RTMGRP_LINK;
if (bind(self->fd, (struct sockaddr*)&nl, sizeof(nl)) >= 0) {
return TRUE;
}
close(self->fd);
self->fd = -1;
}
return FALSE;
}
static gboolean ril_mtu_watch_start(struct ril_mtu_watch *self)
{
if (self->fd >= 0) {
return TRUE;
} else if (ril_mtu_watch_open_socket(self)) {
GASSERT(!self->channel);
GASSERT(!self->io_watch);
self->channel = g_io_channel_unix_new(self->fd);
if (self->channel) {
g_io_channel_set_encoding(self->channel, NULL, NULL);
g_io_channel_set_buffered(self->channel, FALSE);
self->io_watch = g_io_add_watch(self->channel,
G_IO_IN | G_IO_NVAL | G_IO_HUP,
ril_mtu_watch_event, self);
return TRUE;
}
close(self->fd);
self->fd = -1;
}
return FALSE;
}
static void ril_mtu_watch_stop(struct ril_mtu_watch *self)
{
if (self->io_watch) {
g_source_remove(self->io_watch);
self->io_watch = 0;
}
if (self->channel) {
g_io_channel_shutdown(self->channel, TRUE, NULL);
g_io_channel_unref(self->channel);
self->channel = NULL;
}
if (self->fd >= 0) {
close(self->fd);
self->fd = -1;
}
}
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu)
{
struct ril_mtu_watch *self = g_new0(struct ril_mtu_watch, 1);
self->fd = -1;
self->max_mtu = max_mtu;
self->bufsize = 4096;
self->buf = g_malloc(self->bufsize);
return self;
}
void ril_mtu_watch_free(struct ril_mtu_watch *self)
{
if (self) {
ril_mtu_watch_stop(self);
g_free(self->ifname);
g_free(self->buf);
g_free(self);
}
}
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *self, const char *ifname)
{
if (self && g_strcmp0(self->ifname, ifname)) {
g_free(self->ifname);
if (ifname) {
self->ifname = g_strdup(ifname);
ril_mtu_watch_limit_mtu(self);
ril_mtu_watch_start(self);
} else {
self->ifname = NULL;
ril_mtu_watch_stop(self);
}
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,33 @@
/*
* 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_MTU_H
#define RIL_MTU_H
#include "ril_types.h"
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu);
void ril_mtu_watch_free(struct ril_mtu_watch *mw);
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *mw, const char *ifname);
#endif /* RIL_MTU_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -46,14 +46,6 @@ struct ril_netreg {
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
};
/* Defined in src/network.c */
enum operator_status {
OPERATOR_STATUS_UNKNOWN = 0,
OPERATOR_STATUS_AVAILABLE = 1,
OPERATOR_STATUS_CURRENT = 2,
OPERATOR_STATUS_FORBIDDEN = 3,
};
struct ril_netreg_cbd {
struct ril_netreg *nd;
union {
@@ -172,7 +164,13 @@ static void ril_netreg_current_operator(struct ofono_netreg *netreg,
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
GASSERT(!nd->current_operator_id);
/*
* Calling ofono_netreg_status_notify() may result in
* ril_netreg_current_operator() being invoked even if one
* is already pending. Since ofono core doesn't associate
* any context with individual calls, we can safely assume
* that such a call essentially cancels the previous one.
*/
if (nd->current_operator_id) {
g_source_remove(nd->current_operator_id);
}
@@ -405,10 +403,13 @@ static void ril_netreg_strength(struct ofono_netreg *netreg,
ofono_netreg_strength_cb_t cb, void *data)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
GRilIoRequest* req = grilio_request_new();
grilio_queue_send_request_full(nd->q, NULL,
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_SIGNAL_STRENGTH, ril_netreg_strength_cb,
ril_netreg_cbd_free, ril_netreg_cbd_new(nd, cb, data));
grilio_request_unref(req);
}
static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,

View File

@@ -9,12 +9,14 @@
*
* 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
* 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_sim_card.h"
#include "ril_sim_settings.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -22,22 +24,47 @@
#include <grilio_request.h>
#include <grilio_parser.h>
#include <gutil_misc.h>
#include <ofono/netreg.h>
#include "common.h"
#define SET_PREF_MODE_HOLDOFF_SEC RIL_RETRY_SECS
typedef GObjectClass RilNetworkClass;
typedef struct ril_network RilNetwork;
enum ril_network_timer {
TIMER_SET_RAT_HOLDOFF,
TIMER_FORCE_CHECK_PREF_MODE,
TIMER_COUNT
};
enum ril_network_radio_event {
RADIO_EVENT_STATE_CHANGED,
RADIO_EVENT_ONLINE_CHANGED,
RADIO_EVENT_COUNT
};
struct ril_network_priv {
GRilIoChannel *io;
GRilIoQueue *q;
struct ril_radio *radio;
struct ril_sim_card *sim_card;
enum ofono_radio_access_mode max_pref_mode;
int rat;
char *log_prefix;
gulong event_id;
guint operator_poll_id;
guint voice_poll_id;
guint data_poll_id;
gulong radio_event_id;
guint timer[TIMER_COUNT];
gulong query_rat_id;
gulong set_rat_id;
gulong ril_event_id;
gulong settings_event_id;
gulong sim_status_event_id;
gulong radio_event_id[RADIO_EVENT_COUNT];
struct ofono_network_operator operator;
};
@@ -45,12 +72,14 @@ enum ril_network_signal {
SIGNAL_OPERATOR_CHANGED,
SIGNAL_VOICE_STATE_CHANGED,
SIGNAL_DATA_STATE_CHANGED,
SIGNAL_PREF_MODE_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
@@ -59,6 +88,40 @@ G_DEFINE_TYPE(RilNetwork, ril_network, G_TYPE_OBJECT)
#define RIL_NETWORK(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,\
RIL_NETWORK_TYPE,RilNetwork))
#define RIL_NETWORK_SIGNAL(klass,name) \
ril_network_signals[SIGNAL_##name##_CHANGED] = \
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
/* Some assumptions: */
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_ANY == 0);
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_GSM > OFONO_RADIO_ACCESS_MODE_ANY);
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_UMTS > OFONO_RADIO_ACCESS_MODE_GSM);
G_STATIC_ASSERT(OFONO_RADIO_ACCESS_MODE_LTE > OFONO_RADIO_ACCESS_MODE_UMTS);
static void ril_network_query_pref_mode(struct ril_network *self);
static void ril_network_set_pref_mode(struct ril_network *self, int rat);
static void ril_network_emit(struct ril_network *self,
enum ril_network_signal sig)
{
g_signal_emit(self, ril_network_signals[sig], 0);
}
static void ril_network_stop_timer(struct ril_network *self,
enum ril_network_timer tid)
{
struct ril_network_priv *priv = self->priv;
if (priv->timer[tid]) {
g_source_remove(priv->timer[tid]);
priv->timer[tid] = 0;
}
}
static void ril_network_reset_state(struct ril_registration_state *reg)
{
memset(reg, 0, sizeof(*reg));
@@ -72,7 +135,6 @@ static void ril_network_reset_state(struct ril_registration_state *reg)
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;
@@ -83,13 +145,13 @@ static gboolean ril_network_parse_response(struct ril_network *self,
/* 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);
DBG_(self, "broken response");
return FALSE;
}
sstatus = grilio_parser_get_utf8(&rilp); /* response[0] */
if (!sstatus) {
DBG("%sNo sstatus value returned!", priv->log_prefix);
DBG_(self, "No sstatus value returned!");
return FALSE;
}
@@ -142,7 +204,7 @@ static gboolean ril_network_parse_response(struct ril_network *self,
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,
DBG_(self, "%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),
@@ -212,7 +274,7 @@ static void ril_network_poll_operator_cb(GRilIoChannel *io, int req_status,
op.tech = -1;
if (ril_parse_mcc_mnc(numeric, &op)) {
if (op.tech < 0) op.tech = self->voice.access_tech;
op.status = self->voice.status;
op.status = OPERATOR_STATUS_CURRENT;
op.name[0] = 0;
if (lalpha) {
strncpy(op.name, lalpha, sizeof(op.name));
@@ -237,16 +299,15 @@ static void ril_network_poll_operator_cb(GRilIoChannel *io, int req_status,
if (changed) {
if (self->operator) {
DBG("%slalpha=%s, salpha=%s, numeric=%s, %s, "
"mcc=%s, mnc=%s, %s", priv->log_prefix,
DBG_(self, "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));
} else {
DBG("%sno operator", priv->log_prefix);
DBG_(self, "no operator");
}
g_signal_emit(self, ril_network_signals[
SIGNAL_OPERATOR_CHANGED], 0);
ril_network_emit(self, SIGNAL_OPERATOR_CHANGED);
}
g_free(lalpha);
@@ -269,10 +330,9 @@ static void ril_network_poll_voice_state_cb(GRilIoChannel *io, int req_status,
ril_network_parse_response(self, data, len, &state);
if (memcmp(&state, &self->voice, sizeof(state))) {
DBG("%svoice registration changed", priv->log_prefix);
DBG_(self, "voice registration changed");
self->voice = state;
g_signal_emit(self, ril_network_signals[
SIGNAL_VOICE_STATE_CHANGED], 0);
ril_network_emit(self, SIGNAL_VOICE_STATE_CHANGED);
}
}
}
@@ -291,10 +351,9 @@ static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
ril_network_parse_response(self, data, len, &state);
if (memcmp(&state, &self->data, sizeof(state))) {
DBG("%sdata registration changed", priv->log_prefix);
DBG_(self, "data registration changed");
self->data = state;
g_signal_emit(self, ril_network_signals[
SIGNAL_DATA_STATE_CHANGED], 0);
ril_network_emit(self, SIGNAL_DATA_STATE_CHANGED);
}
}
}
@@ -323,7 +382,7 @@ static void ril_network_poll_state(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
DBG_(self, "");
priv->operator_poll_id = ril_network_poll_and_retry(self,
priv->operator_poll_id, RIL_REQUEST_OPERATOR,
ril_network_poll_operator_cb);
@@ -335,6 +394,221 @@ static void ril_network_poll_state(struct ril_network *self)
ril_network_poll_data_state_cb);
}
static enum ofono_radio_access_mode ril_network_rat_to_mode(int rat)
{
switch (rat) {
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_WCDMA_AUTO:
case PREF_NET_TYPE_WCDMA:
case PREF_NET_TYPE_GSM_WCDMA:
return OFONO_RADIO_ACCESS_MODE_UMTS;
default:
DBG("unexpected rat mode %d", rat);
case PREF_NET_TYPE_GSM_ONLY:
return OFONO_RADIO_ACCESS_MODE_GSM;
}
}
static int ril_network_mode_to_rat(struct ril_network *self,
enum ofono_radio_access_mode mode)
{
switch (mode) {
case OFONO_RADIO_ACCESS_MODE_ANY:
case OFONO_RADIO_ACCESS_MODE_LTE:
if (self->settings->enable_4g) {
return PREF_NET_TYPE_LTE_GSM_WCDMA;
}
/* no break */
default:
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;
}
}
static int ril_network_pref_mode_expected(struct ril_network *self)
{
struct ril_sim_settings *settings = self->settings;
struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode pref_mode = priv->max_pref_mode ?
MIN(settings->pref_mode, priv->max_pref_mode) :
settings->pref_mode;
return ril_network_mode_to_rat(self, pref_mode);
}
static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
return priv->radio->online && ril_sim_card_ready(priv->sim_card);
}
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
const int rat = ril_network_pref_mode_expected(self);
DBG_(self, "rat mode %d, expected %d", priv->rat, rat);
GASSERT(priv->timer[TIMER_SET_RAT_HOLDOFF]);
priv->timer[TIMER_SET_RAT_HOLDOFF] = 0;
/*
* Don't retry the request if modem is offline or SIM card isn't
* ready, to avoid spamming system log with error messages. Radio
* and SIM card state change callbacks will schedule a new check
* when it's appropriate.
*/
if (priv->rat != rat) {
if (ril_network_can_set_pref_mode(self)) {
ril_network_set_pref_mode(self, rat);
} else {
DBG_(self, "giving up");
}
}
return G_SOURCE_REMOVE;
}
static void ril_network_set_pref_mode_cb(GRilIoChannel *io, int 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->set_rat_id);
priv->set_rat_id = 0;
if (status != RIL_E_SUCCESS) {
ofono_error("failed to set rat mode");
}
ril_network_query_pref_mode(self);
}
static void ril_network_set_pref_mode(struct ril_network *self, int rat)
{
struct ril_network_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(8);
DBG_(self, "setting rat mode %d", rat);
grilio_request_append_int32(req, 1); /* Number of params */
grilio_request_append_int32(req, rat);
grilio_queue_cancel_request(priv->q, priv->set_rat_id, FALSE);
priv->set_rat_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
ril_network_set_pref_mode_cb, NULL, self);
grilio_request_unref(req);
/* Don't do it too often */
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
priv->timer[TIMER_SET_RAT_HOLDOFF] =
g_timeout_add_seconds(SET_PREF_MODE_HOLDOFF_SEC,
ril_network_set_rat_holdoff_cb, self);
}
static void ril_network_check_pref_mode(struct ril_network *self,
gboolean force)
{
struct ril_network_priv *priv = self->priv;
const int rat = ril_network_pref_mode_expected(self);
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
ril_network_stop_timer(self, TIMER_FORCE_CHECK_PREF_MODE);
/*
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
* ril_network_pref_mode_changed_cb and is meant
* to force radio tech check right now.
*/
force = TRUE;
}
if (priv->rat == rat || force) {
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
}
if (priv->rat != rat) {
/* Something isn't right, we need to fix it */
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
ril_network_set_pref_mode(self, rat);
} else {
/* OK, later */
DBG_(self, "need to set rat mode %d", rat);
}
}
}
static int ril_network_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_network_query_pref_mode_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
/* This request never fails because in case of error it gets retried */
GASSERT(status == RIL_E_SUCCESS);
GASSERT(priv->query_rat_id);
priv->query_rat_id = 0;
priv->rat = ril_network_parse_pref_resp(data, len);
self->pref_mode = ril_network_rat_to_mode(priv->rat);
DBG_(self, "rat mode %d (%s)", priv->rat,
ofono_radio_access_mode_to_string(self->pref_mode));
if (self->pref_mode != pref_mode) {
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
}
if (ril_network_can_set_pref_mode(self)) {
ril_network_check_pref_mode(self, FALSE);
}
}
static void ril_network_query_pref_mode(struct ril_network *self)
{
struct ril_network_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
grilio_queue_cancel_request(priv->q, priv->query_rat_id, FALSE);
priv->query_rat_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
ril_network_query_pref_mode_cb, NULL, self);
grilio_request_unref(req);
}
void ril_network_set_max_pref_mode(struct ril_network *self,
enum ofono_radio_access_mode max_mode,
gboolean force_check)
{
if (G_LIKELY(self)) {
struct ril_network_priv *priv = self->priv;
if (priv->max_pref_mode != max_mode || force_check) {
DBG_(self, "rat mode %d (%s)", max_mode,
ofono_radio_access_mode_to_string(max_mode));
priv->max_pref_mode = max_mode;
ril_network_check_pref_mode(self, TRUE);
}
}
}
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
@@ -356,6 +630,13 @@ gulong ril_network_add_data_state_changed_handler(struct ril_network *self,
SIGNAL_DATA_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_network_remove_handler(struct ril_network *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
@@ -363,43 +644,110 @@ void ril_network_remove_handler(struct ril_network *self, gulong id)
}
}
void ril_network_remove_handlers(struct ril_network *self, gulong *ids, int n)
{
gutil_disconnect_handlers(self, ids, n);
}
static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
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);
DBG_(self, "");
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)
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
{
struct ril_network *self = RIL_NETWORK(user_data);
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(self);
ril_network_poll_state(RIL_NETWORK(data));
}
}
struct ril_network *ril_network_new(GRilIoChannel *io, struct ril_radio *radio)
static void ril_network_radio_online_cb(struct ril_radio *radio, void *data)
{
struct ril_network *self = RIL_NETWORK(data);
if (ril_network_can_set_pref_mode(self)) {
ril_network_check_pref_mode(self, TRUE);
}
}
static gboolean ril_network_check_pref_mode_cb(gpointer user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
GASSERT(priv->timer[TIMER_FORCE_CHECK_PREF_MODE]);
priv->timer[TIMER_FORCE_CHECK_PREF_MODE] = 0;
DBG_(self, "checking pref mode");
ril_network_check_pref_mode(self, TRUE);
return G_SOURCE_REMOVE;
}
static void ril_network_pref_mode_changed_cb(struct ril_sim_settings *settings,
void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
/*
* Postpone ril_network_check_pref_mode because other pref_mode
* listeners (namely, ril_data) may want to tweak max_pref_mode
*/
if (!priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
DBG_(self, "scheduling pref mode check");
priv->timer[TIMER_FORCE_CHECK_PREF_MODE] =
g_idle_add(ril_network_check_pref_mode_cb, self);
} else {
DBG_(self, "pref mode check already scheduled");
}
}
static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
if (ril_network_can_set_pref_mode(self)) {
ril_network_check_pref_mode(self, FALSE);
}
}
struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
struct ril_radio *radio, struct ril_sim_card *sim_card,
struct ril_sim_settings *settings)
{
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
struct ril_network_priv *priv = self->priv;
self->settings = ril_sim_settings_ref(settings);
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,
priv->sim_card = ril_sim_card_ref(sim_card);
priv->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
DBG_(self, "");
priv->ril_event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_network_voice_state_changed_cb,
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);
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
ril_radio_add_state_changed_handler(priv->radio,
ril_network_radio_state_cb, self);
priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
ril_radio_add_online_changed_handler(priv->radio,
ril_network_radio_online_cb, self);
priv->settings_event_id =
ril_sim_settings_add_pref_mode_changed_handler(settings,
ril_network_pref_mode_changed_cb, self);
priv->sim_status_event_id =
ril_sim_card_add_status_changed_handler(priv->sim_card,
ril_network_sim_status_changed_cb, self);
/*
* Query the initial state. Querying network state before the radio
@@ -437,24 +785,31 @@ static void ril_network_init(struct ril_network *self)
self->priv = priv;
ril_network_reset_state(&self->voice);
ril_network_reset_state(&self->data);
priv->rat = -1;
}
static void ril_network_dispose(GObject *object)
{
struct ril_network *self = RIL_NETWORK(object);
struct ril_network_priv *priv = self->priv;
enum ril_network_timer tid;
if (priv->event_id) {
grilio_channel_remove_handler(priv->io, priv->event_id);
priv->event_id = 0;
}
grilio_channel_remove_handlers(priv->io, &priv->ril_event_id, 1);
ril_radio_remove_handlers(priv->radio, priv->radio_event_id,
G_N_ELEMENTS(priv->radio_event_id));
ril_sim_settings_remove_handlers(self->settings,
&priv->settings_event_id, 1);
ril_sim_card_remove_handlers(priv->sim_card,
&priv->sim_status_event_id, 1);
if (priv->radio_event_id) {
ril_radio_remove_handler(priv->radio, priv->radio_event_id);
priv->radio_event_id = 0;
for (tid=0; tid<TIMER_COUNT; tid++) {
ril_network_stop_timer(self, tid);
}
grilio_queue_cancel_all(priv->q, FALSE);
priv->set_rat_id = 0;
priv->query_rat_id = 0;
G_OBJECT_CLASS(ril_network_parent_class)->dispose(object);
}
@@ -463,11 +818,13 @@ 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);
DBG_(self, "");
g_free(priv->log_prefix);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
ril_radio_unref(priv->radio);
ril_sim_card_unref(priv->sim_card);
ril_sim_settings_unref(self->settings);
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
}
@@ -478,18 +835,10 @@ static void ril_network_class_init(RilNetworkClass *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);
RIL_NETWORK_SIGNAL(klass, OPERATOR);
RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
RIL_NETWORK_SIGNAL(klass, DATA_STATE);
RIL_NETWORK_SIGNAL(klass, PREF_MODE);
}
/*

View File

@@ -9,7 +9,7 @@
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
@@ -18,6 +18,8 @@
#include "ril_types.h"
#include <ofono/radio-settings.h>
struct ofono_network_operator;
struct ril_registration_state {
@@ -35,23 +37,34 @@ struct ril_network {
struct ril_registration_state voice;
struct ril_registration_state data;
const struct ofono_network_operator *operator;
enum ofono_radio_access_mode pref_mode;
struct ril_sim_settings *settings;
};
struct ofono_sim;
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
struct ril_network *ril_network_new(GRilIoChannel *io, struct ril_radio *radio);
struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
struct ril_radio *radio, struct ril_sim_card *sim_card,
struct ril_sim_settings *settings);
struct ril_network *ril_network_ref(struct ril_network *net);
void ril_network_unref(struct ril_network *net);
void ril_network_set_max_pref_mode(struct ril_network *net,
enum ofono_radio_access_mode max_pref_mode,
gboolean force_check);
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);
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
void ril_network_remove_handler(struct ril_network *net, gulong id);
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
#endif /* RIL_NETWORK */
#endif /* RIL_NETWORK_H */
/*
* Local Variables:

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,118 +16,147 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "gdbus.h"
#include "ofono.h"
#define RIL_OEM_RAW_INTERFACE "org.ofono.OemRaw"
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
struct ril_oem_raw {
struct ril_modem *modem;
GRilIoQueue *q;
guint timer_id;
DBusConnection *conn;
char *path;
char *log_prefix;
};
struct ril_oem_raw_cbd {
ofono_oem_raw_query_cb_t cb;
gpointer data;
};
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
#define ril_oem_raw_cbd_free g_free
static inline struct ril_oem_raw *ril_oem_raw_get_data(
struct ofono_oem_raw *raw)
{
return ofono_oem_raw_get_data(raw);
}
static struct ril_oem_raw_cbd *ril_oem_raw_cbd_new(ofono_oem_raw_query_cb_t cb,
void *data)
{
struct ril_oem_raw_cbd *cbd = g_new0(struct ril_oem_raw_cbd, 1);
cbd->cb = cb;
cbd->data = data;
return cbd;
}
static void ril_oem_raw_request_cb(GRilIoChannel *io, int status,
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_oem_raw_cbd *cbd = user_data;
DBusMessage *msg = user_data;
DBusMessage *reply;
if (status == RIL_E_SUCCESS) {
struct ofono_oem_raw_results result;
if (ril_status == RIL_E_SUCCESS) {
DBusMessageIter it, array;
const guchar* bytes = data;
guint i;
result.data = (void *)data;
result.length = len;
cbd->cb(ril_error_ok(&error), &result, cbd->data);
reply = dbus_message_new_method_return(msg);
dbus_message_iter_init_append(reply, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING, &array);
for (i = 0; i < len; i++) {
guchar byte = bytes[i];
dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE,
&byte);
}
dbus_message_iter_close_container(&it, &array);
} else if (ril_status == GRILIO_STATUS_TIMEOUT) {
DBG("Timed out");
reply = __ofono_error_timed_out(msg);
} else {
DBG("error:%d len:%d ", status, len);
cbd->cb(ril_error_failure(&error), NULL, cbd->data);
DBG("Error %s", ril_error_to_string(ril_status));
reply = __ofono_error_failed(msg);
}
__ofono_dbus_pending_reply(&msg, reply);
}
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
void *user_data)
{
DBusMessageIter it;
struct ril_oem_raw *oem = user_data;
dbus_message_iter_init(msg, &it);
if (dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY &&
dbus_message_iter_get_element_type(&it) == DBUS_TYPE_BYTE) {
char *data;
int data_len;
DBusMessageIter array;
GRilIoRequest *req;
/* Fetch the data */
dbus_message_iter_recurse(&it, &array);
dbus_message_iter_get_fixed_array(&array, &data, &data_len);
DBG_(oem, "%d bytes", data_len);
/*
* And forward it to rild. Set a timeout because rild may
* never respond to invalid requests.
*/
req = grilio_request_sized_new(data_len);
grilio_request_set_timeout(req, RIL_OEM_RAW_TIMEOUT);
grilio_request_append_bytes(req, data, data_len);
grilio_queue_send_request_full(oem->q, req,
RIL_REQUEST_OEM_HOOK_RAW, ril_oem_raw_send_cb,
NULL, dbus_message_ref(msg));
grilio_request_unref(req);
return NULL;
} else {
DBG_(oem, "Unexpected signature");
return __ofono_error_invalid_args(msg);
}
}
static void ril_oem_raw_request(struct ofono_oem_raw *raw,
const struct ofono_oem_raw_request *request,
ofono_oem_raw_query_cb_t cb, void *data)
{
struct ril_oem_raw *od = ril_oem_raw_get_data(raw);
GRilIoRequest *req = grilio_request_sized_new(request->length);
grilio_request_append_bytes(req, request->data, request->length);
grilio_queue_send_request_full(od->q, req, RIL_REQUEST_OEM_HOOK_RAW,
ril_oem_raw_request_cb, ril_oem_raw_cbd_free,
ril_oem_raw_cbd_new(cb, data));
grilio_request_unref(req);
}
static gboolean ril_oem_raw_register(gpointer user_data)
{
struct ofono_oem_raw *raw = user_data;
struct ril_oem_raw *od = ril_oem_raw_get_data(raw);
DBG("");
GASSERT(od->timer_id);
od->timer_id = 0;
ofono_oem_raw_dbus_register(raw);
/* Single-shot */
return FALSE;
}
static int ril_oem_raw_probe(struct ofono_oem_raw *raw, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
struct ril_oem_raw *od = g_new0(struct ril_oem_raw, 1);
DBG("");
od->q = grilio_queue_new(ril_modem_io(modem));
od->timer_id = g_idle_add(ril_oem_raw_register, raw);
ofono_oem_raw_set_data(raw, od);
return 0;
}
static void ril_oem_raw_remove(struct ofono_oem_raw *raw)
{
struct ril_oem_raw *od = ril_oem_raw_get_data(raw);
DBG("");
grilio_queue_cancel_all(od->q, TRUE);
ofono_oem_raw_set_data(raw, NULL);
if (od->timer_id) {
g_source_remove(od->timer_id);
}
grilio_queue_unref(od->q);
g_free(od);
}
/* const */ struct ofono_oem_raw_driver ril_oem_raw_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_oem_raw_probe,
.remove = ril_oem_raw_remove,
.request = ril_oem_raw_request,
static const GDBusMethodTable ril_oem_raw_methods[] = {
{ GDBUS_ASYNC_METHOD("Send",
GDBUS_ARGS({ "request", "ay" }),
GDBUS_ARGS({ "response", "ay" }),
ril_oem_raw_send) },
{ }
};
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
const char *log_prefix)
{
struct ril_oem_raw *oem = g_new0(struct ril_oem_raw, 1);
DBG("%s", ril_modem_get_path(modem));
oem->modem = modem;
oem->path = g_strdup(ril_modem_get_path(modem));
oem->conn = dbus_connection_ref(ofono_dbus_get_connection());
oem->q = grilio_queue_new(ril_modem_io(modem));
oem->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
/* Register D-Bus interface */
if (g_dbus_register_interface(oem->conn, oem->path,
RIL_OEM_RAW_INTERFACE, ril_oem_raw_methods,
NULL, NULL, oem, NULL)) {
ofono_modem_add_interface(modem->ofono, RIL_OEM_RAW_INTERFACE);
return oem;
} else {
ofono_error("OemRaw D-Bus register failed");
ril_oem_raw_free(oem);
return NULL;
}
}
void ril_oem_raw_free(struct ril_oem_raw *oem)
{
if (oem) {
DBG("%s", oem->path);
g_dbus_unregister_interface(oem->conn, oem->path,
RIL_OEM_RAW_INTERFACE);
ofono_modem_remove_interface(oem->modem->ofono,
RIL_OEM_RAW_INTERFACE);
dbus_connection_unref(oem->conn);
grilio_queue_cancel_all(oem->q, TRUE);
grilio_queue_unref(oem->q);
g_free(oem->log_prefix);
g_free(oem->path);
g_free(oem);
}
}
/*
* Local Variables:
* mode: C

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,6 @@
#include <ofono/gprs-context.h>
#include <ofono/gprs.h>
#include <ofono/netreg.h>
#include <ofono/oemraw.h>
#include <ofono/phonebook.h>
#include <ofono/radio-settings.h>
#include <ofono/sim.h>
@@ -45,57 +44,76 @@
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;
const char *ecclist_file;
gboolean enabled;
gboolean sim_present;
const struct ril_slot_config *config;
};
struct ril_plugin {
const char *mms_imsi;
const char *mms_path;
const char *default_voice_imsi;
const char *default_data_imsi;
const char *default_voice_path;
const char *default_data_path;
const ril_slot_info_ptr *slots;
gboolean ready;
};
struct ril_modem {
GRilIoChannel *io;
const char *imei;
const char *log_prefix;
const char *ecclist_file;
struct ofono_modem *ofono;
struct ril_radio *radio;
struct ril_data *data;
struct ril_network *network;
struct ril_sim_card *sim_card;
struct ril_sim_settings *sim_settings;
struct ril_slot_config config;
};
#define RIL_PLUGIN_SIGNAL_VOICE_IMSI (0x01)
#define RIL_PLUGIN_SIGNAL_DATA_IMSI (0x02)
#define RIL_PLUGIN_SIGNAL_VOICE_PATH (0x04)
#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x10)
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x20)
#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x08)
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x10)
#define RIL_PLUGIN_SIGNAL_MMS_IMSI (0x20)
#define RIL_PLUGIN_SIGNAL_MMS_PATH (0x40)
#define RIL_PLUGIN_SIGNAL_READY (0x80)
typedef void (*ril_modem_cb_t)(struct ril_modem *modem, void *data);
typedef void (*ril_modem_online_cb_t)(struct ril_modem *modem, gboolean online,
void *data);
void ril_plugin_set_enabled_slots(struct ril_plugin *plugin, char **slots);
gboolean ril_plugin_set_mms_imsi(struct ril_plugin *plugin, const char *imsi);
void ril_plugin_set_default_voice_imsi(struct ril_plugin *plugin,
const char *imsi);
void ril_plugin_set_default_data_imsi(struct ril_plugin *plugin,
const char *imsi);
struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *modem);
const char *ril_sim_dbus_imsi(struct ril_sim_dbus *dbus);
void ril_sim_dbus_free(struct ril_sim_dbus *dbus);
struct ril_oem_raw;
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *md,
const char *log_prefix);
void ril_oem_raw_free(struct ril_oem_raw *raw);
struct ril_sim_info_dbus;
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
struct ril_sim_info *info);
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus);
struct ril_cell_info_dbus;
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
struct ril_cell_info *info);
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus);
struct ril_plugin_dbus;
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin);
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus);
void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
@@ -104,36 +122,24 @@ 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,
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,
struct ril_network *network, struct ril_sim_card *card,
struct ril_data *data);
struct ril_data *data, struct ril_sim_settings *settings);
void ril_modem_delete(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);
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
void *data);
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
void *data);
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
#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,
unsigned int path_len, ofono_sim_read_cb_t cb, void *data);
void ril_sim_read_file_cyclic(struct ofono_sim *sim, int fileid,
int record, int length, const unsigned char *path,
unsigned int path_len, ofono_sim_read_cb_t cb, void *data);
void ril_sim_read_file_transparent(struct ofono_sim *sim, int fileid,
int start, int length, const unsigned char *path,
unsigned int path_len, ofono_sim_read_cb_t cb, void *data);
void ril_sim_read_file_info(struct ofono_sim *sim, int fileid,
const unsigned char *path, unsigned int path_len,
ofono_sim_file_info_cb_t cb, void *data);
int ril_sim_app_type(struct ofono_sim *sim);
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
@@ -147,7 +153,6 @@ extern const struct ofono_gprs_context_driver ril_gprs_context_driver;
extern const struct ofono_gprs_driver ril_gprs_driver;
extern const struct ofono_modem_driver ril_modem_driver;
extern const struct ofono_netreg_driver ril_netreg_driver;
extern /* const */ struct ofono_oem_raw_driver ril_oem_raw_driver;
extern const struct ofono_phonebook_driver ril_phonebook_driver;
extern const struct ofono_radio_settings_driver ril_radio_settings_driver;
extern const struct ofono_sim_driver ril_sim_driver;

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
@@ -41,18 +41,22 @@ struct ril_plugin_dbus {
DBusConnection *conn;
gboolean block_imei_req;
GSList *blocked_imei_req;
guint mms_watch;
};
#define RIL_DBUS_PATH "/"
#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
#define RIL_DBUS_INTERFACE_VERSION (3)
#define RIL_DBUS_INTERFACE_VERSION (5)
#define RIL_DBUS_ENABLED_MODEMS_CHANGED_SIGNAL "EnabledModemsChanged"
#define RIL_DBUS_PRESENT_SIMS_CHANGED_SIGNAL "PresentSimsChanged"
#define RIL_DBUS_DEFAULT_VOICE_SIM_CHANGED_SIGNAL "DefaultVoiceSimChanged"
#define RIL_DBUS_DEFAULT_DATA_SIM_CHANGED_SIGNAL "DefaultDataSimChanged"
#define RIL_DBUS_DEFAULT_VOICE_MODEM_CHANGED_SIGNAL "DefaultVoiceModemChanged"
#define RIL_DBUS_DEFAULT_DATA_MODEM_CHANGED_SIGNAL "DefaultDataModemChanged"
#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED "DefaultVoiceSimChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED "DefaultDataSimChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED "DefaultVoiceModemChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED "DefaultDataModemChanged"
#define RIL_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
#define RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
#define RIL_DBUS_SIGNAL_READY_CHANGED "ReadyChanged"
#define RIL_DBUS_IMSI_AUTO "auto"
static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
@@ -130,6 +134,17 @@ static void ril_plugin_dbus_append_boolean_array(DBusMessageIter *it,
dbus_message_iter_close_container(it, &array);
}
static void ril_plugin_dbus_append_boolean(DBusMessageIter *it, dbus_bool_t b)
{
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &b);
}
static void ril_plugin_dbus_append_string(DBusMessageIter *it, const char *str)
{
if (!str) str = "";
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
}
static void ril_plugin_dbus_append_imsi(DBusMessageIter *it, const char *imsi)
{
if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
@@ -170,12 +185,19 @@ static inline void ril_plugin_dbus_signal_imsi(struct ril_plugin_dbus *dbus,
name, DBUS_TYPE_STRING, &imsi, DBUS_TYPE_INVALID);
}
static inline void ril_plugin_dbus_signal_path(struct ril_plugin_dbus *dbus,
const char *name, const char *path)
static inline void ril_plugin_dbus_signal_string(struct ril_plugin_dbus *dbus,
const char *name, const char *str)
{
if (!path) path = "";
if (!str) str = "";
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
name, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
name, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
}
static inline void ril_plugin_dbus_signal_boolean(struct ril_plugin_dbus *dbus,
const char *name, dbus_bool_t value)
{
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
name, DBUS_TYPE_BOOLEAN, &value, DBUS_TYPE_INVALID);
}
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask)
@@ -183,29 +205,44 @@ void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask)
if (dbus) {
if (mask & RIL_PLUGIN_SIGNAL_VOICE_IMSI) {
ril_plugin_dbus_signal_imsi(dbus,
RIL_DBUS_DEFAULT_VOICE_SIM_CHANGED_SIGNAL,
RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
dbus->plugin->default_voice_imsi);
}
if (mask & RIL_PLUGIN_SIGNAL_DATA_IMSI) {
ril_plugin_dbus_signal_imsi(dbus,
RIL_DBUS_DEFAULT_DATA_SIM_CHANGED_SIGNAL,
RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
dbus->plugin->default_data_imsi);
}
if (mask & RIL_PLUGIN_SIGNAL_MMS_IMSI) {
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
dbus->plugin->mms_imsi);
}
if (mask & RIL_PLUGIN_SIGNAL_ENABLED_SLOTS) {
ril_plugin_dbus_signal_path_array(dbus,
RIL_DBUS_ENABLED_MODEMS_CHANGED_SIGNAL,
RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
ril_plugin_dbus_enabled);
}
if (mask & RIL_PLUGIN_SIGNAL_VOICE_PATH) {
ril_plugin_dbus_signal_path(dbus,
RIL_DBUS_DEFAULT_VOICE_MODEM_CHANGED_SIGNAL,
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
dbus->plugin->default_voice_path);
}
if (mask & RIL_PLUGIN_SIGNAL_DATA_PATH) {
ril_plugin_dbus_signal_path(dbus,
RIL_DBUS_DEFAULT_DATA_MODEM_CHANGED_SIGNAL,
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
dbus->plugin->default_data_path);
}
if (mask & RIL_PLUGIN_SIGNAL_MMS_PATH) {
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
dbus->plugin->mms_path);
}
if (mask & RIL_PLUGIN_SIGNAL_READY) {
ril_plugin_dbus_signal_boolean(dbus,
RIL_DBUS_SIGNAL_READY_CHANGED,
dbus->plugin->ready);
}
}
}
@@ -214,7 +251,7 @@ void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
{
dbus_bool_t value = present;
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
RIL_DBUS_PRESENT_SIMS_CHANGED_SIGNAL,
RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
DBUS_TYPE_INT32, &index,
DBUS_TYPE_BOOLEAN, &value,
DBUS_TYPE_INVALID);
@@ -323,6 +360,21 @@ static void ril_plugin_dbus_append_all3(DBusMessageIter *it,
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
}
static void ril_plugin_dbus_append_all4(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all3(it, dbus);
ril_plugin_dbus_append_string(it, dbus->plugin->mms_imsi);
ril_plugin_dbus_append_path(it, dbus->plugin->mms_path);
}
static void ril_plugin_dbus_append_all5(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all4(it, dbus);
ril_plugin_dbus_append_boolean(it, dbus->plugin->ready);
}
static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -344,6 +396,20 @@ static DBusMessage *ril_plugin_dbus_get_all3(DBusConnection *conn,
ril_plugin_dbus_append_all3);
}
static DBusMessage *ril_plugin_dbus_get_all4(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all4);
}
static DBusMessage *ril_plugin_dbus_get_all5(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all5);
}
static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -391,6 +457,17 @@ static DBusMessage *ril_plugin_dbus_get_imei(DBusConnection *conn,
ril_plugin_dbus_append_imei_array);
}
static DBusMessage *ril_plugin_dbus_reply_with_string(DBusMessage *msg,
const char *str)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
ril_plugin_dbus_append_string(&iter, str);
return reply;
}
static DBusMessage *ril_plugin_dbus_reply_with_imsi(DBusMessage *msg,
const char *imsi)
{
@@ -420,6 +497,14 @@ static DBusMessage *ril_plugin_dbus_get_default_voice_sim(DBusConnection *conn,
dbus->plugin->default_voice_imsi);
}
static DBusMessage *ril_plugin_dbus_get_mms_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_string(msg, dbus->plugin->mms_imsi);
}
static DBusMessage *ril_plugin_dbus_reply_with_path(DBusMessage *msg,
const char *path)
{
@@ -449,6 +534,26 @@ static DBusMessage *ril_plugin_dbus_get_default_voice_modem(DBusConnection *conn
dbus->plugin->default_voice_path);
}
static DBusMessage *ril_plugin_dbus_get_mms_modem(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_path(msg, dbus->plugin->mms_path);
}
static DBusMessage *ril_plugin_dbus_get_ready(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it;
dbus_message_iter_init_append(reply, &it);
ril_plugin_dbus_append_boolean(&it, dbus->plugin->ready);
return reply;
}
static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -519,37 +624,117 @@ static DBusMessage *ril_plugin_dbus_set_default_data_sim(DBusConnection *conn,
ril_plugin_set_default_data_imsi);
}
static void ril_plugin_dbus_mms_disconnect(DBusConnection *conn, void *data)
{
struct ril_plugin_dbus *dbus = data;
dbus->mms_watch = 0;
if (dbus->plugin->mms_imsi) {
DBG("MMS client is gone");
ril_plugin_set_mms_imsi(dbus->plugin, NULL);
}
}
static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessageIter iter;
struct ril_plugin_dbus *dbus = data;
GASSERT(conn == dbus->conn);
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
DBusBasicValue value;
const char *imsi;
dbus_message_iter_get_basic(&iter, &value);
imsi = value.str;
/*
* MMS IMSI is not persistent and has to be eventually
* reset by the client or cleaned up if the client
* unexpectedly disappears.
*/
if (ril_plugin_set_mms_imsi(dbus->plugin, imsi)) {
/*
* Clear the previous MMS owner
*/
if (dbus->mms_watch) {
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
dbus->mms_watch = 0;
}
if (dbus->plugin->mms_imsi &&
dbus->plugin->mms_imsi[0]) {
/*
* This client becomes the owner
*/
DBG("Owner: %s", dbus_message_get_sender(msg));
dbus->mms_watch =
g_dbus_add_disconnect_watch(dbus->conn,
dbus_message_get_sender(msg),
ril_plugin_dbus_mms_disconnect,
dbus, NULL);
}
return ril_plugin_dbus_reply_with_string(msg,
dbus->plugin->mms_path);
} else {
return __ofono_error_not_available(msg);
}
} else {
return __ofono_error_invalid_args(msg);
}
}
/*
* The client can call GetInterfaceVersion followed by the appropriate
* GetAllx call to get all settings in two steps. Alternatively, it can
* call GetAll followed by GetAllx based on the interface version returned
* by GetAll. In either case, two D-Bus calls are required, unless the
* client is willing to make the assumption about the ofono version it's
* talking to.
*/
#define RIL_DBUS_GET_ALL_ARGS \
{"version", "i" }, \
{"availableModems", "ao" }, \
{"enabledModems", "ao" }, \
{"defaultDataSim", "s" }, \
{"defaultVoiceSim", "s" }, \
{"defaultDataModem", "s" }, \
{"defaultVoiceModem" , "s"}
#define RIL_DBUS_GET_ALL2_ARGS \
RIL_DBUS_GET_ALL_ARGS, \
{"presentSims" , "ab"}
#define RIL_DBUS_GET_ALL3_ARGS \
RIL_DBUS_GET_ALL2_ARGS, \
{"imei" , "as"}
#define RIL_DBUS_GET_ALL4_ARGS \
RIL_DBUS_GET_ALL3_ARGS, \
{"mmsSim", "s" }, \
{"mmsModem" , "s"}
#define RIL_DBUS_GET_ALL5_ARGS \
RIL_DBUS_GET_ALL4_ARGS, \
{"ready" , "b"}
static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("GetAll", NULL,
GDBUS_ARGS({"version", "i" },
{"availableModems", "ao" },
{"enabledModems", "ao" },
{"defaultDataSim", "s" },
{"defaultVoiceSim", "s" },
{"defaultDataModem", "s" },
{"defaultVoiceModem" , "s"}),
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
ril_plugin_dbus_get_all) },
{ GDBUS_METHOD("GetAll2", NULL,
GDBUS_ARGS({"version", "i" },
{"availableModems", "ao" },
{"enabledModems", "ao" },
{"defaultDataSim", "s" },
{"defaultVoiceSim", "s" },
{"defaultDataModem", "s" },
{"defaultVoiceModem" , "s"},
{"presentSims" , "ab"}),
{ GDBUS_METHOD("GetAll2",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL2_ARGS),
ril_plugin_dbus_get_all2) },
{ GDBUS_ASYNC_METHOD("GetAll3", NULL,
GDBUS_ARGS({"version", "i" },
{"availableModems", "ao" },
{"enabledModems", "ao" },
{"defaultDataSim", "s" },
{"defaultVoiceSim", "s" },
{"defaultDataModem", "s" },
{"defaultVoiceModem" , "s"},
{"presentSims" , "ab"},
{"imei" , "as"}),
{ GDBUS_ASYNC_METHOD("GetAll3",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL3_ARGS),
ril_plugin_dbus_get_all3) },
{ GDBUS_ASYNC_METHOD("GetAll4",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL4_ARGS),
ril_plugin_dbus_get_all4) },
{ GDBUS_ASYNC_METHOD("GetAll5",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL5_ARGS),
ril_plugin_dbus_get_all5) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
ril_plugin_dbus_get_interface_version) },
@@ -571,12 +756,21 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("GetDefaultVoiceSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
ril_plugin_dbus_get_default_voice_sim) },
{ GDBUS_METHOD("GetMmsSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
ril_plugin_dbus_get_mms_sim) },
{ GDBUS_METHOD("GetDefaultDataModem",
NULL, GDBUS_ARGS({ "path", "s" }),
ril_plugin_dbus_get_default_data_modem) },
{ GDBUS_METHOD("GetDefaultVoiceModem",
NULL, GDBUS_ARGS({ "path", "s" }),
ril_plugin_dbus_get_default_voice_modem) },
{ GDBUS_METHOD("GetMmsModem",
NULL, GDBUS_ARGS({ "path", "s" }),
ril_plugin_dbus_get_mms_modem) },
{ GDBUS_METHOD("GetReady",
NULL, GDBUS_ARGS({ "ready", "b" }),
ril_plugin_dbus_get_ready) },
{ GDBUS_METHOD("SetEnabledModems",
GDBUS_ARGS({ "modems", "ao" }), NULL,
ril_plugin_dbus_set_enabled_modems) },
@@ -586,23 +780,32 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("SetDefaultVoiceSim",
GDBUS_ARGS({ "imsi", "s" }), NULL,
ril_plugin_dbus_set_default_voice_sim) },
{ GDBUS_METHOD("SetMmsSim",
GDBUS_ARGS({ "imsi", "s" }), NULL,
ril_plugin_dbus_set_mms_sim) },
{ }
};
static const GDBusSignalTable ril_plugin_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_DBUS_ENABLED_MODEMS_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
GDBUS_ARGS({ "modems", "ao" })) },
{ GDBUS_SIGNAL(RIL_DBUS_PRESENT_SIMS_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
GDBUS_ARGS({"index", "i" },
{"present" , "b"})) },
{ GDBUS_SIGNAL(RIL_DBUS_DEFAULT_DATA_SIM_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_DEFAULT_VOICE_SIM_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_DEFAULT_DATA_MODEM_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_DEFAULT_VOICE_MODEM_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_READY_CHANGED,
GDBUS_ARGS({ "ready", "b" })) },
{ }
};
@@ -626,6 +829,10 @@ struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin)
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus)
{
if (dbus) {
if (dbus->mms_watch) {
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
}
g_slist_free_full(dbus->blocked_imei_req,
ril_plugin_dbus_cancel_request);
g_dbus_unregister_interface(dbus->conn, RIL_DBUS_PATH,

View File

@@ -9,7 +9,7 @@
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
@@ -21,6 +21,8 @@
#include <grilio_request.h>
#include <grilio_parser.h>
#include <gutil_misc.h>
typedef GObjectClass RilRadioClass;
typedef struct ril_radio RilRadio;
@@ -48,38 +50,53 @@ struct ril_radio_priv {
enum ril_radio_signal {
SIGNAL_STATE_CHANGED,
SIGNAL_ONLINE_CHANGED,
SIGNAL_COUNT
};
#define POWER_RETRY_SECS (1)
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
#define SIGNAL_ONLINE_CHANGED_NAME "ril-radio-online-changed"
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
#define NEW_SIGNAL(klass,name) \
ril_radio_signals[SIGNAL_##name##_CHANGED] = \
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
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)
static inline 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;
return self->online && !priv->power_cycle &&
g_hash_table_size(priv->req_table) > 0;
}
G_INLINE_FUNC gboolean ril_radio_state_off(enum ril_radio_state radio_state)
static inline 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)
static inline gboolean ril_radio_state_on(enum ril_radio_state radio_state)
{
return !ril_radio_state_off(radio_state);
}
static inline void ril_radio_emit_signal(struct ril_radio *self,
enum ril_radio_signal id)
{
g_signal_emit(self, ril_radio_signals[id], 0);
}
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
{
struct ril_radio *self = user_data;
@@ -89,7 +106,8 @@ static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
GASSERT(priv->retry_id);
priv->retry_id = 0;
ril_radio_submit_power_request(self, ril_radio_power_should_be_on(self));
return FALSE;
return G_SOURCE_REMOVE;
}
static void ril_radio_cancel_retry(struct ril_radio *self)
@@ -132,7 +150,7 @@ static void ril_radio_check_state(struct ril_radio *self)
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);
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
}
}
@@ -228,12 +246,15 @@ 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);
if (!g_hash_table_contains(priv->req_table, tag)) {
gboolean was_on = ril_radio_power_should_be_on(self);
DBG("%s%p", priv->log_prefix, tag);
g_hash_table_insert(priv->req_table, tag, tag);
if (!was_on && ril_radio_power_should_be_on(self)) {
ril_radio_power_request(self, TRUE, FALSE);
}
}
}
}
@@ -243,15 +264,29 @@ 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);
if (g_hash_table_remove(priv->req_table, tag)) {
DBG("%s%p", priv->log_prefix, tag);
if (!ril_radio_power_should_be_on(self)) {
/* The last one turns the lights off */
ril_radio_power_request(self, FALSE, FALSE);
}
}
}
}
void ril_radio_set_online(struct ril_radio *self, gboolean online)
{
if (G_LIKELY(self) && self->online != online) {
gboolean on, was_on = ril_radio_power_should_be_on(self);
self->online = online;
on = ril_radio_power_should_be_on(self);
if (was_on != on) {
ril_radio_power_request(self, on, FALSE);
}
ril_radio_emit_signal(self, SIGNAL_ONLINE_CHANGED);
}
}
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
ril_radio_cb_t cb, void *arg)
{
@@ -259,6 +294,13 @@ gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_radio_add_online_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_ONLINE_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)) {
@@ -266,6 +308,11 @@ void ril_radio_remove_handler(struct ril_radio *self, gulong id)
}
}
void ril_radio_remove_handlers(struct ril_radio *self, gulong *ids, int count)
{
gutil_disconnect_handlers(self, ids, count);
}
enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
{
GRilIoParser rilp;
@@ -390,10 +437,8 @@ static void ril_radio_class_init(RilRadioClass *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);
NEW_SIGNAL(klass, STATE);
NEW_SIGNAL(klass, ONLINE);
}
/*

View File

@@ -9,7 +9,7 @@
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
@@ -22,6 +22,7 @@ struct ril_radio {
GObject object;
struct ril_radio_priv *priv;
enum ril_radio_state state;
gboolean online;
};
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
@@ -32,14 +33,18 @@ 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);
void ril_radio_confirm_power_on(struct ril_radio *radio);
void ril_radio_set_online(struct ril_radio *radio, gboolean online);
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
ril_radio_cb_t cb, void *arg);
gulong ril_radio_add_online_changed_handler(struct ril_radio *radio,
ril_radio_cb_t cb, void *arg);
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
void ril_radio_remove_handlers(struct ril_radio *radio, gulong *ids, int n);
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
#endif /* RIL_RADIO */
#endif /* RIL_RADIO_H */
/*
* Local Variables:

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,17 +14,17 @@
*/
#include "ril_plugin.h"
#include "ril_sim_settings.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.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 query_rats_id;
struct ril_sim_settings *settings;
const char *log_prefix;
char *allocated_log_prefix;
guint source_id;
};
struct ril_radio_settings_cbd {
@@ -38,7 +38,7 @@ struct ril_radio_settings_cbd {
gpointer data;
};
#define ril_radio_settings_cbd_free g_free
#define DBG_(rsd,fmt,args...) DBG("%s" fmt, (rsd)->log_prefix, ##args)
static inline struct ril_radio_settings *ril_radio_settings_get_data(
struct ofono_radio_settings *rs)
@@ -46,8 +46,8 @@ static inline struct ril_radio_settings *ril_radio_settings_get_data(
return ofono_radio_settings_get_data(rs);
}
static struct ril_radio_settings_cbd *ril_radio_settings_cbd_new(
struct ril_radio_settings *rsd, void *cb, void *data)
static void ril_radio_settings_later(struct ril_radio_settings *rsd,
GSourceFunc fn, void *cb, void *data)
{
struct ril_radio_settings_cbd *cbd;
@@ -55,89 +55,22 @@ static struct ril_radio_settings_cbd *ril_radio_settings_cbd_new(
cbd->rsd = rsd;
cbd->cb.ptr = cb;
cbd->data = data;
return cbd;
GASSERT(!rsd->source_id);
rsd->source_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
fn, cbd, g_free);
}
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)
{
grilio_queue_send_request_full(rsd->q, req, code, response,
ril_radio_settings_cbd_free,
ril_radio_settings_cbd_new(rsd, cb, data));
}
static void ril_radio_settings_set_rat_mode_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
static gboolean ril_radio_settings_set_rat_mode_cb(gpointer user_data)
{
struct ofono_error error;
struct ril_radio_settings_cbd *cbd = user_data;
ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb.rat_mode_set;
struct ril_radio_settings *rsd = cbd->rsd;
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
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;
GASSERT(rsd->source_id);
rsd->source_id = 0;
cbd->cb.rat_mode_set(ril_error_ok(&error), cbd->data);
return G_SOURCE_REMOVE;
}
static void ril_radio_settings_set_rat_mode(struct ofono_radio_settings *rs,
@@ -145,45 +78,24 @@ static void ril_radio_settings_set_rat_mode(struct ofono_radio_settings *rs,
ofono_radio_settings_rat_mode_set_cb_t cb, void *data)
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
int pref = ril_radio_settings_mode_to_pref(rsd, mode);
GRilIoRequest *req;
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);
DBG_(rsd, "%s", ofono_radio_access_mode_to_string(mode));
ril_sim_settings_set_pref_mode(rsd->settings, mode);
ril_radio_settings_later(rsd, ril_radio_settings_set_rat_mode_cb,
cb, data);
}
static void ril_radio_settings_query_rat_mode_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
static gboolean ril_radio_settings_query_rat_mode_cb(gpointer 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;
enum ofono_radio_access_mode mode = rsd->settings->pref_mode;
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
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 {
/*
* 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);
DBG_(rsd, "rat mode %s", ofono_radio_access_mode_to_string(mode));
GASSERT(rsd->source_id);
rsd->source_id = 0;
cbd->cb.rat_mode_query(ril_error_ok(&error), mode, cbd->data);
return G_SOURCE_REMOVE;
}
static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
@@ -191,26 +103,26 @@ static void ril_radio_settings_query_rat_mode(struct ofono_radio_settings *rs,
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
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);
DBG_(rsd, "");
ril_radio_settings_later(rsd, ril_radio_settings_query_rat_mode_cb,
cb, data);
}
static gboolean ril_radio_settings_query_available_rats_cb(gpointer data)
{
struct ofono_error error;
struct ril_radio_settings_cbd *cbd = data;
struct ril_radio_settings *rsd = cbd->rsd;
guint rats = OFONO_RADIO_ACCESS_MODE_GSM | OFONO_RADIO_ACCESS_MODE_UMTS;
if (cbd->rsd->enable_4g) {
if (cbd->rsd->settings->enable_4g) {
rats |= OFONO_RADIO_ACCESS_MODE_LTE;
}
GASSERT(cbd->rsd->query_rats_id);
cbd->rsd->query_rats_id = 0;
GASSERT(cbd->rsd->source_id);
rsd->source_id = 0;
cbd->cb.available_rats(ril_error_ok(&error), rats, cbd->data);
return FALSE;
return G_SOURCE_REMOVE;
}
static void ril_radio_settings_query_available_rats(
@@ -219,50 +131,18 @@ static void ril_radio_settings_query_available_rats(
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(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);
DBG_(rsd, "");
ril_radio_settings_later(rsd, ril_radio_settings_query_available_rats_cb,
cb, data);
}
static void ril_radio_settings_init_query_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
static gboolean ril_radio_settings_register(gpointer 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);
}
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);
}
GASSERT(rsd->source_id);
rsd->source_id = 0;
ofono_radio_settings_register(rsd->rs);
return G_SOURCE_REMOVE;
}
static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
@@ -271,13 +151,17 @@ static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
struct ril_modem *modem = data;
struct ril_radio_settings *rsd = g_new0(struct ril_radio_settings, 1);
DBG("");
DBG("%s", modem->log_prefix);
rsd->rs = rs;
rsd->q = grilio_queue_new(ril_modem_io(modem));
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->settings = ril_sim_settings_ref(modem->sim_settings);
rsd->source_id = g_idle_add(ril_radio_settings_register, rsd);
if (modem->log_prefix && modem->log_prefix[0]) {
rsd->log_prefix = rsd->allocated_log_prefix =
g_strconcat(modem->log_prefix, " ", NULL);
} else {
rsd->log_prefix = "";
}
ofono_radio_settings_set_data(rs, rsd);
return 0;
@@ -287,14 +171,13 @@ static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
DBG("");
DBG_(rsd, "");
ofono_radio_settings_set_data(rs, NULL);
if (rsd->query_rats_id > 0) {
g_source_remove(rsd->query_rats_id);
if (rsd->source_id) {
g_source_remove(rsd->source_id);
}
grilio_queue_cancel_all(rsd->q, FALSE);
grilio_queue_unref(rsd->q);
ril_sim_settings_unref(rsd->settings);
g_free(rsd->allocated_log_prefix);
g_free(rsd);
}

View File

@@ -14,7 +14,6 @@
*/
#include "ril_plugin.h"
#include "ril_radio.h"
#include "ril_sim_card.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -68,18 +67,15 @@
struct ril_sim {
GRilIoChannel *io;
GRilIoQueue *q;
GRilIoQueue *q2;
GList *pin_cbd_list;
struct ofono_sim *sim;
struct ril_sim_card *card;
struct ril_radio *radio;
enum ofono_sim_password_type ofono_passwd_state;
int retries[OFONO_SIM_PASSWORD_INVALID];
guint slot;
gboolean inserted;
guint idle_id;
gulong card_status_id;
gulong radio_state_id;
/* query_passwd_state context */
ofono_sim_passwd_cb_t query_passwd_state_cb;
@@ -141,6 +137,7 @@ static void ril_sim_pin_cbd_state_event_count_cb(struct ril_sim_card *sc,
static struct ril_sim_pin_cbd *ril_sim_pin_cbd_new(struct ril_sim *sd,
enum ofono_sim_password_type passwd_type,
gboolean state_change_expected,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim_pin_cbd *cbd = g_new0(struct ril_sim_pin_cbd, 1);
@@ -150,8 +147,11 @@ static struct ril_sim_pin_cbd *ril_sim_pin_cbd_new(struct ril_sim *sd,
cbd->data = data;
cbd->passwd_type = passwd_type;
cbd->card = ril_sim_card_ref(sd->card);
cbd->card_status_id = ril_sim_card_add_status_received_handler(sd->card,
if (state_change_expected) {
cbd->card_status_id =
ril_sim_card_add_status_received_handler(sd->card,
ril_sim_pin_cbd_state_event_count_cb, cbd);
}
return cbd;
}
@@ -385,36 +385,19 @@ static guint ril_sim_request_io(struct ril_sim *sd, GRilIoQueue *q, int fileid,
return id;
}
static void ril_sim_internal_read_file_info(struct ril_sim *sd, GRilIoQueue *q,
int fileid, const unsigned char *path, unsigned int path_len,
ofono_sim_file_info_cb_t cb, void *data)
{
if (!sd || !ril_sim_request_io(sd, q, fileid, CMD_GET_RESPONSE,
0, 0, 15, path, path_len, ril_sim_file_info_cb,
ril_sim_cbd_new(sd, cb, data))) {
struct ofono_error error;
cb(ril_error_failure(&error), -1, -1, -1, NULL,
EF_STATUS_INVALIDATED, data);
}
}
static void ril_sim_ofono_read_file_info(struct ofono_sim *sim, int fileid,
const unsigned char *path, unsigned int len,
ofono_sim_file_info_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_internal_read_file_info(sd, sd->q, fileid, path, len, cb, data);
}
void ril_sim_read_file_info(struct ofono_sim *sim, int fileid,
const unsigned char *path, unsigned int path_len,
ofono_sim_file_info_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_internal_read_file_info(sd, sd->q2, fileid, path, path_len,
cb, data);
if (!sd || !ril_sim_request_io(sd, sd->q, fileid, CMD_GET_RESPONSE,
0, 0, 15, path, len, ril_sim_file_info_cb,
ril_sim_cbd_new(sd, cb, data))) {
struct ofono_error error;
cb(ril_error_failure(&error), -1, -1, -1, NULL,
EF_STATUS_INVALIDATED, data);
}
}
static void ril_sim_read_cb(GRilIoChannel *io, int status,
@@ -457,42 +440,14 @@ static void ril_sim_read(struct ril_sim *sd, GRilIoQueue *q, int fileid,
}
}
static inline void ril_sim_internal_read_file_transparent(struct ril_sim *sd,
GRilIoQueue *q, int fileid, int start, int length,
const unsigned char *path, unsigned int path_len,
ofono_sim_read_cb_t cb, void *data)
{
ril_sim_read(sd, q, fileid, CMD_READ_BINARY, (start >> 8),
(start & 0xff), length, path, path_len, cb, data);
}
static void ril_sim_ofono_read_file_transparent(struct ofono_sim *sim,
int fileid, int start, int length, const unsigned char *path,
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_internal_read_file_transparent(sd, sd->q, fileid, start, length,
path, path_len, cb, data);
}
void ril_sim_read_file_transparent(struct ofono_sim *sim, int fileid,
int start, int length, const unsigned char *path,
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_internal_read_file_transparent(sd, sd->q2, fileid, start,
length, path, path_len, cb, data);
}
static inline void ril_sim_internal_read_file_linear(struct ril_sim *sd,
GRilIoQueue *q, int fileid, int record, int length,
const unsigned char *path, unsigned int path_len,
ofono_sim_read_cb_t cb, void *data)
{
ril_sim_read(sd, q, fileid, CMD_READ_RECORD, record, 4, length,
path, path_len, cb, data);
ril_sim_read(sd, sd->q, fileid, CMD_READ_BINARY, (start >> 8),
(start & 0xff), length, path, path_len, cb, data);
}
static void ril_sim_ofono_read_file_linear(struct ofono_sim *sim, int fileid,
@@ -501,29 +456,10 @@ static void ril_sim_ofono_read_file_linear(struct ofono_sim *sim, int fileid,
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_internal_read_file_linear(sd, sd->q, fileid, record, length,
ril_sim_read(sd, sd->q, fileid, CMD_READ_RECORD, record, 4, length,
path, path_len, cb, data);
}
void ril_sim_read_file_linear(struct ofono_sim *sim, int fileid,
int record, int length, const unsigned char *path,
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_internal_read_file_linear(sd, sd->q2, fileid, record, length,
path, path_len, cb, data);
}
void ril_sim_read_file_cyclic(struct ofono_sim *sim, int fileid,
int rec, int length, const unsigned char *path,
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
{
/* Hmmm... Is this right? */
ril_sim_read_file_linear(sim, fileid, rec, length, path, path_len,
cb, data);
}
static void ril_sim_ofono_read_file_cyclic(struct ofono_sim *sim, int fileid,
int rec, int length, const unsigned char *path,
unsigned int path_len, ofono_sim_read_cb_t cb, void *data)
@@ -569,6 +505,13 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
DBG("%s", ril_sim_app_id(sd));
grilio_request_append_int32(req, GET_IMSI_NUM_PARAMS);
grilio_request_append_utf8(req, ril_sim_app_id(sd));
/*
* If we fail the .read_imsi call, ofono gets into "Unable to
* read IMSI, emergency calls only" state. Retry the request
* on failure.
*/
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_GET_IMSI,
ril_sim_get_imsi_cb, ril_sim_cbd_free,
ril_sim_cbd_new(sd, cb, data));
@@ -644,24 +587,6 @@ static gboolean ril_sim_app_in_transient_state(struct ril_sim *sd)
return FALSE;
}
static void ril_sim_insert_check(struct ril_sim *sd)
{
if (!sd->inserted &&
ril_sim_passwd_state(sd) != OFONO_SIM_PASSWORD_INVALID) {
switch (sd->radio->state) {
case RADIO_STATE_SIM_READY:
case RADIO_STATE_RUIM_READY:
case RADIO_STATE_ON:
sd->inserted = TRUE;
ofono_info("SIM card OK");
ofono_sim_inserted_notify(sd->sim, TRUE);
break;
default:
break;
}
}
}
static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
enum ofono_sim_password_type state)
{
@@ -709,7 +634,12 @@ static void ril_sim_status_cb(struct ril_sim_card *sc, void *user_data)
if (sc->app) {
enum ofono_sim_password_type ps;
ril_sim_insert_check(sd);
if (!sd->inserted) {
sd->inserted = TRUE;
ofono_info("SIM card OK");
ofono_sim_inserted_notify(sd->sim, TRUE);
}
ps = ril_sim_passwd_state(sd);
if (ps != OFONO_SIM_PASSWORD_INVALID) {
ril_sim_finish_passwd_state_query(sd, ps);
@@ -727,13 +657,6 @@ static void ril_sim_status_cb(struct ril_sim_card *sc, void *user_data)
}
}
static void ril_sim_radio_state_cb(struct ril_radio *radio, void *user_data)
{
struct ril_sim *sd = user_data;
ril_sim_insert_check(sd);
}
static void ril_sim_query_pin_retries(struct ofono_sim *sim,
ofono_sim_pin_retries_cb_t cb, void *data)
{
@@ -752,7 +675,8 @@ static gboolean ril_sim_query_passwd_state_timeout_cb(gpointer user_data)
GASSERT(sd->query_passwd_state_cb);
sd->query_passwd_state_timeout_id = 0;
ril_sim_finish_passwd_state_query(sd, OFONO_SIM_PASSWORD_INVALID);
return FALSE;
return G_SOURCE_REMOVE;
}
static void ril_sim_query_passwd_state(struct ofono_sim *sim,
@@ -795,7 +719,8 @@ static gboolean ril_sim_pin_change_state_timeout_cb(gpointer user_data)
sd->pin_cbd_list = g_list_remove(sd->pin_cbd_list, cbd);
cbd->cb(ril_error_failure(&error), cbd->data);
ril_sim_pin_cbd_free(cbd);
return FALSE;
return G_SOURCE_REMOVE;
}
static void ril_sim_pin_change_state_status_cb(struct ril_sim_card *sc,
@@ -841,7 +766,8 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
ril_status, cbd->passwd_type, retry_count);
cbd->ril_status = ril_status;
if (!cbd->state_event_count || ril_sim_app_in_transient_state(sd)) {
if (cbd->card_status_id && (!cbd->state_event_count ||
ril_sim_app_in_transient_state(sd))) {
GASSERT(!g_list_find(sd->pin_cbd_list, cbd));
GASSERT(!cbd->timeout_id);
@@ -862,7 +788,7 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
} else {
struct ofono_error error;
/* Looks like the state has already changed */
/* It's either already changed or not expected at all */
if (ril_status == RIL_E_SUCCESS) {
cbd->cb(ril_error_ok(&error), cbd->data);
} else {
@@ -884,7 +810,8 @@ static void ril_sim_pin_send(struct ofono_sim *sim, const char *passwd,
DBG("%s,aid=%s", passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PIN,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PIN, cb, data));
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PIN,
TRUE, cb, data));
grilio_request_unref(req);
}
@@ -917,7 +844,7 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
if (req) {
id = grilio_queue_send_request_full(sd->q, req, code,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, passwd_type, cb, data));
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
grilio_request_unref(req);
}
@@ -979,7 +906,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SET_FACILITY_LOCK,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, passwd_type, cb, data));
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
grilio_request_unref(req);
}
@@ -1003,7 +930,8 @@ static void ril_sim_pin_send_puk(struct ofono_sim *sim,
DBG("puk=%s,pin=%s,aid=%s", puk, passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PUK,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PUK, cb, data));
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PUK,
TRUE, cb, data));
grilio_request_unref(req);
}
@@ -1025,7 +953,8 @@ static void ril_sim_change_passwd(struct ofono_sim *sim,
(passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2) ?
RIL_REQUEST_CHANGE_SIM_PIN2 : RIL_REQUEST_CHANGE_SIM_PIN,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, passwd_type, cb, data));
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
grilio_request_unref(req);
}
static gboolean ril_sim_register(gpointer user)
@@ -1039,8 +968,6 @@ static gboolean ril_sim_register(gpointer user)
ofono_sim_register(sd->sim);
/* Register for change notifications */
sd->radio_state_id = ril_radio_add_state_changed_handler(sd->radio,
ril_sim_radio_state_cb, sd);
sd->card_status_id = ril_sim_card_add_status_changed_handler(sd->card,
ril_sim_status_cb, sd);
@@ -1060,19 +987,7 @@ static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
sd->slot = ril_modem_slot(modem);
sd->io = grilio_channel_ref(ril_modem_io(modem));
sd->card = ril_sim_card_ref(modem->sim_card);
sd->radio = ril_radio_ref(modem->radio);
/* NB: One queue is used for the requests originated from the ofono
* core, and the second one if for the requests initiated internally
* by the RIL code.
*
* The difference is that when SIM card is removed, ofono requests
* are cancelled without invoking the completion callbacks (otherwise
* ofono would crash) while our completion callbacks have to be
* notified in this case (otherwise we would leak memory)
*/
sd->q = grilio_queue_new(sd->io);
sd->q2 = grilio_queue_new(sd->io);
DBG("[%u]", sd->slot);
@@ -1093,7 +1008,6 @@ static void ril_sim_remove(struct ofono_sim *sim)
DBG("[%u]", sd->slot);
g_list_free_full(sd->pin_cbd_list, ril_sim_pin_cbd_list_free_cb);
grilio_queue_cancel_all(sd->q, FALSE);
grilio_queue_cancel_all(sd->q2, TRUE);
ofono_sim_set_data(sim, NULL);
if (sd->idle_id) {
@@ -1104,15 +1018,11 @@ static void ril_sim_remove(struct ofono_sim *sim)
g_source_remove(sd->query_passwd_state_timeout_id);
}
ril_radio_remove_handler(sd->radio, sd->radio_state_id);
ril_radio_unref(sd->radio);
ril_sim_card_remove_handler(sd->card, sd->card_status_id);
ril_sim_card_unref(sd->card);
grilio_channel_unref(sd->io);
grilio_queue_unref(sd->q);
grilio_queue_unref(sd->q2);
g_free(sd);
}

View File

@@ -22,6 +22,8 @@
#include <grilio_request.h>
#include <grilio_parser.h>
#include <gutil_misc.h>
typedef GObjectClass RilSimCardClass;
typedef struct ril_sim_card RilSimCard;
@@ -436,6 +438,14 @@ void ril_sim_card_unref(struct ril_sim_card *self)
}
}
gboolean ril_sim_card_ready(struct ril_sim_card *self)
{
return self && self->app &&
((self->app->app_state == RIL_APPSTATE_READY) ||
(self->app->app_state == RIL_APPSTATE_SUBSCRIPTION_PERSO &&
self->app->perso_substate == RIL_PERSOSUBSTATE_READY));
}
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *self,
ril_sim_card_cb_t cb, void *arg)
{
@@ -471,6 +481,11 @@ void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong id)
}
}
void ril_sim_card_remove_handlers(struct ril_sim_card *self, gulong *ids, int n)
{
gutil_disconnect_handlers(self, ids, n);
}
static void ril_sim_card_init(struct ril_sim_card *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIMCARD_TYPE,

View File

@@ -55,6 +55,7 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
void ril_sim_card_unref(struct ril_sim_card *sc);
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
gulong ril_sim_card_add_status_changed_handler(struct ril_sim_card *sc,
@@ -64,9 +65,10 @@ gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *sc,
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);
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
/* Inline wrappers */
G_INLINE_FUNC enum ril_app_type
static inline enum ril_app_type
ril_sim_card_app_type(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }

View File

@@ -1,242 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_log.h"
#include <ofono/dbus.h>
#include <gdbus.h>
#include "ofono.h"
#include "storage.h"
struct ril_sim_dbus {
char *path;
char *imsi;
char *name;
char *default_name;
gboolean enable_4g;
GKeyFile *storage;
DBusConnection *conn;
struct ril_modem *md;
};
#define RIL_SIM_STORE "ril"
#define RIL_SIM_STORE_GROUP "Settings"
#define RIL_SIM_STORE_ENABLE_4G "Enable4G"
#define RIL_SIM_STORE_DISPLAY_NAME "DisplayName"
#define RIL_SIM_DBUS_INTERFACE "org.nemomobile.ofono.SimSettings"
#define RIL_SIM_DBUS_INTERFACE_VERSION (1)
#define RIL_SIM_DBUS_DISPLAY_NAME_CHANGED_SIGNAL "DisplayNameChanged"
#define RIL_SIM_DBUS_ENABLE_4G_CHANGED_SIGNAL "Enable4GChanged"
static DBusMessage *ril_sim_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
dbus_int32_t version = RIL_SIM_DBUS_INTERFACE_VERSION;
dbus_bool_t enable_4g = dbus->enable_4g;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &enable_4g);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &dbus->name);
return reply;
}
static DBusMessage *ril_sim_dbus_get_interface_version(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
dbus_int32_t version = RIL_SIM_DBUS_INTERFACE_VERSION;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
return reply;
}
static DBusMessage *ril_sim_dbus_get_enable_4g(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
dbus_bool_t enable_4g = dbus->enable_4g;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &enable_4g);
return reply;
}
static DBusMessage *ril_sim_dbus_get_display_name(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &dbus->name);
return reply;
}
static void ril_sim_dbus_update_display_name(struct ril_sim_dbus *dbus,
const char *name)
{
if (g_strcmp0(dbus->name, name)) {
g_free(dbus->name);
dbus->name = g_strdup(name);
g_key_file_set_string(dbus->storage, RIL_SIM_STORE_GROUP,
RIL_SIM_STORE_DISPLAY_NAME, name);
storage_sync(dbus->imsi, RIL_SIM_STORE, dbus->storage);
g_dbus_emit_signal(dbus->conn, dbus->path,
RIL_SIM_DBUS_INTERFACE,
RIL_SIM_DBUS_DISPLAY_NAME_CHANGED_SIGNAL,
DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
}
}
static DBusMessage *ril_sim_dbus_set_display_name(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessageIter iter;
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
struct ril_sim_dbus *dbus = data;
DBusBasicValue value;
const char *name;
dbus_message_iter_get_basic(&iter, &value);
name = value.str;
if (!name || !name[0]) name = dbus->default_name;
ril_sim_dbus_update_display_name(dbus, name);
return dbus_message_new_method_return(msg);
} else {
return __ofono_error_invalid_args(msg);
}
}
static const GDBusMethodTable ril_sim_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS({ "settings", "ibs" }),
ril_sim_dbus_get_all) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
ril_sim_dbus_get_interface_version) },
{ GDBUS_METHOD("GetEnable4G",
NULL, GDBUS_ARGS({ "enable", "b" }),
ril_sim_dbus_get_enable_4g) },
{ GDBUS_METHOD("GetDisplayName",
NULL, GDBUS_ARGS({ "name", "s" }),
ril_sim_dbus_get_display_name) },
{ GDBUS_METHOD("SetDisplayName",
GDBUS_ARGS({ "name", "s" }), NULL,
ril_sim_dbus_set_display_name) },
{ }
};
static const GDBusSignalTable ril_sim_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_SIM_DBUS_DISPLAY_NAME_CHANGED_SIGNAL,
GDBUS_ARGS({ "name", "s" })) },
{ GDBUS_SIGNAL(RIL_SIM_DBUS_ENABLE_4G_CHANGED_SIGNAL,
GDBUS_ARGS({ "enabled", "b" })) },
{ }
};
const char *ril_sim_dbus_imsi(struct ril_sim_dbus *dbus)
{
return dbus ? dbus->imsi : NULL;
}
struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *md)
{
const char *imsi = ofono_sim_get_imsi(ril_modem_ofono_sim(md));
if (imsi) {
GError *error = NULL;
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));
dbus->md = md;
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
dbus->path = g_strdup(ril_modem_get_path(md));
dbus->imsi = g_strdup(imsi);
dbus->default_name = g_strdup(config->default_name);
/* Load settings */
dbus->storage = storage_open(imsi, RIL_SIM_STORE);
dbus->enable_4g = g_key_file_get_boolean(dbus->storage,
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_ENABLE_4G, &error);
if (error) {
dbus->enable_4g = config->enable_4g;
g_error_free(error);
error = NULL;
}
dbus->name = g_key_file_get_string(dbus->storage,
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_DISPLAY_NAME, NULL);
if (!dbus->name) {
dbus->name = g_strdup(config->default_name);
GASSERT(dbus->name);
}
/* Register D-Bus interface */
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(md->ofono,
RIL_SIM_DBUS_INTERFACE);
return dbus;
} else {
ofono_error("RIL D-Bus register failed");
ril_sim_dbus_free(dbus);
}
}
return NULL;
}
void ril_sim_dbus_free(struct ril_sim_dbus *dbus)
{
if (dbus) {
DBG("%s", dbus->path);
g_dbus_unregister_interface(dbus->conn, dbus->path,
RIL_SIM_DBUS_INTERFACE);
ofono_modem_remove_interface(dbus->md->ofono,
RIL_SIM_DBUS_INTERFACE);
dbus_connection_unref(dbus->conn);
g_key_file_free(dbus->storage);
g_free(dbus->path);
g_free(dbus->imsi);
g_free(dbus->name);
g_free(dbus->default_name);
g_free(dbus);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

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

View File

@@ -0,0 +1,53 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_SIM_INFO_H
#define RIL_SIM_INFO_H
#include "ril_types.h"
struct ril_sim_info {
GObject object;
struct ril_sim_info_priv *priv;
const char *iccid;
const char *imsi;
const char *spn;
};
struct ofono_sim;
typedef void (*ril_sim_info_cb_t)(struct ril_sim_info *info, void *arg);
struct ril_sim_info *ril_sim_info_new(const char *log_prefix);
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *info);
void ril_sim_info_unref(struct ril_sim_info *si);
void ril_sim_info_set_ofono_sim(struct ril_sim_info *si, struct ofono_sim *sim);
void ril_sim_info_set_network(struct ril_sim_info *si, struct ril_network *net);
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *si,
ril_sim_info_cb_t cb, void *arg);
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *si,
ril_sim_info_cb_t cb, void *arg);
gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *si,
ril_sim_info_cb_t cb, void *arg);
void ril_sim_info_remove_handler(struct ril_sim_info *si, gulong id);
#endif /* RIL_SIM_INFO_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

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

View File

@@ -0,0 +1,305 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_sim_settings.h"
#include "ril_log.h"
#include <gutil_misc.h>
#include <ofono/sim.h>
#include "storage.h"
#define RIL_SIM_STORE "ril"
#define RIL_SIM_STORE_GROUP "Settings"
#define RIL_SIM_STORE_PREF_MODE "TechnologyPreference"
#define RIL_SIM_STORE_PREF_MODE_DEFAULT(self) ((self)->enable_4g ? \
OFONO_RADIO_ACCESS_MODE_LTE : OFONO_RADIO_ACCESS_MODE_UMTS)
typedef GObjectClass RilSimSettingsClass;
typedef struct ril_sim_settings RilSimSettings;
struct ril_sim_settings_priv {
struct ofono_sim *sim;
guint imsi_watch_id;
guint state_watch_id;
GKeyFile *storage;
char *imsi;
};
enum ril_sim_settings_signal {
SIGNAL_IMSI_CHANGED,
SIGNAL_PREF_MODE_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_IMSI_CHANGED_NAME "ril-sim-settings-imsi-changed"
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-sim-settings-pref-mode-changed"
static guint ril_sim_settings_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilSimSettings, ril_sim_settings, G_TYPE_OBJECT)
#define RIL_SIM_SETTINGS_TYPE (ril_sim_settings_get_type())
#define RIL_SIM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
RIL_SIM_SETTINGS_TYPE, RilSimSettings))
#define NEW_SIGNAL(klass,name) \
ril_sim_settings_signals[SIGNAL_##name##_CHANGED] = \
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
static void ril_sim_settings_signal_emit(struct ril_sim_settings *self,
enum ril_sim_settings_signal id)
{
g_signal_emit(self, ril_sim_settings_signals[id], 0);
}
static void ril_sim_settings_reload(struct ril_sim_settings *self)
{
struct ril_sim_settings_priv *priv = self->priv;
if (priv->storage) {
g_key_file_free(priv->storage);
priv->storage = NULL;
}
if (priv->imsi) {
char *mode_str;
enum ofono_radio_access_mode mode;
priv->storage = storage_open(priv->imsi, RIL_SIM_STORE);
mode_str = g_key_file_get_string(priv->storage,
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_PREF_MODE, NULL);
if (ofono_radio_access_mode_from_string(mode_str, &mode)) {
if (!self->enable_4g &&
mode == OFONO_RADIO_ACCESS_MODE_LTE) {
mode = OFONO_RADIO_ACCESS_MODE_ANY;
}
} else {
mode = OFONO_RADIO_ACCESS_MODE_ANY;
}
if (mode == OFONO_RADIO_ACCESS_MODE_ANY) {
self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
} else {
self->pref_mode = mode;
}
g_free(mode_str);
}
}
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *self,
enum ofono_radio_access_mode mode)
{
if (G_LIKELY(self) && self->pref_mode != mode) {
struct ril_sim_settings_priv *priv = self->priv;
const char *mode_str = ofono_radio_access_mode_to_string(mode);
GASSERT(priv->storage);
if (mode_str) {
if (priv->storage) {
g_key_file_set_string(priv->storage,
RIL_SIM_STORE_GROUP,
RIL_SIM_STORE_PREF_MODE, mode_str);
storage_sync(self->imsi, RIL_SIM_STORE,
priv->storage);
}
self->pref_mode = mode;
ril_sim_settings_signal_emit(self,
SIGNAL_PREF_MODE_CHANGED);
}
}
}
static void ril_sim_settings_set_imsi(struct ril_sim_settings *self,
const char *imsi)
{
struct ril_sim_settings_priv *priv = self->priv;
if (g_strcmp0(priv->imsi, imsi)) {
enum ofono_radio_access_mode prev_mode = self->pref_mode;
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(imsi);
ril_sim_settings_reload(self);
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
if (prev_mode != self->pref_mode) {
ril_sim_settings_signal_emit(self,
SIGNAL_PREF_MODE_CHANGED);
}
}
}
static void ril_sim_settings_imsi_watch_cb(const char *imsi, void *user_data)
{
ril_sim_settings_set_imsi(RIL_SIM_SETTINGS(user_data), imsi);
}
static void ril_sim_settings_imsi_watch_done(void *user_data)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
struct ril_sim_settings_priv *priv = self->priv;
GASSERT(priv->imsi_watch_id);
priv->imsi_watch_id = 0;
}
static void ril_sim_settings_ready(struct ril_sim_settings *self)
{
struct ril_sim_settings_priv *priv = self->priv;
GASSERT(!priv->imsi_watch_id);
priv->imsi_watch_id = ofono_sim_add_imsi_watch(priv->sim,
ril_sim_settings_imsi_watch_cb, self,
ril_sim_settings_imsi_watch_done);
}
static void ril_sim_settings_state_watch(enum ofono_sim_state new_state,
void *user_data)
{
if (new_state == OFONO_SIM_STATE_READY) {
ril_sim_settings_ready(RIL_SIM_SETTINGS(user_data));
}
}
static void ril_sim_settings_state_watch_done(void *user_data)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
struct ril_sim_settings_priv *priv = self->priv;
GASSERT(priv->state_watch_id);
priv->state_watch_id = 0;
}
void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
struct ofono_sim *sim)
{
if (G_LIKELY(self)) {
struct ril_sim_settings_priv *priv = self->priv;
if (priv->sim != sim) {
GASSERT(priv->sim || !priv->imsi_watch_id);
if (priv->imsi_watch_id) {
ofono_sim_remove_imsi_watch(priv->sim,
priv->imsi_watch_id);
/* ril_sim_settings_imsi_watch_done clears it */
GASSERT(!priv->imsi_watch_id);
}
if (priv->state_watch_id) {
ofono_sim_remove_state_watch(priv->sim,
priv->state_watch_id);
/* ril_sim_settings_state_watch_done clears it */
GASSERT(!priv->state_watch_id);
}
priv->sim = sim;
if (sim) {
priv->state_watch_id =
ofono_sim_add_state_watch(sim,
ril_sim_settings_state_watch, self,
ril_sim_settings_state_watch_done);
GASSERT(priv->state_watch_id);
if (ofono_sim_get_state(sim) ==
OFONO_SIM_STATE_READY) {
ril_sim_settings_ready(self);
}
} else {
ril_sim_settings_set_imsi(self, NULL);
}
}
}
}
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *self,
ril_sim_settings_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_sim_settings_add_pref_mode_changed_handler(
struct ril_sim_settings *self,
ril_sim_settings_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_sim_settings_remove_handler(struct ril_sim_settings *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
void ril_sim_settings_remove_handlers(struct ril_sim_settings *self,
gulong *ids, int count)
{
gutil_disconnect_handlers(self, ids, count);
}
struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc)
{
struct ril_sim_settings *self = g_object_new(RIL_SIM_SETTINGS_TYPE, 0);
self->enable_4g = sc->enable_4g;
self->slot = sc->slot;
self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
return self;
}
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_SIM_SETTINGS(self));
return self;
} else {
return NULL;
}
}
void ril_sim_settings_unref(struct ril_sim_settings *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_SIM_SETTINGS(self));
}
}
static void ril_sim_settings_init(struct ril_sim_settings *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIM_SETTINGS_TYPE,
struct ril_sim_settings_priv);
}
static void ril_sim_settings_dispose(GObject *object)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
ril_sim_settings_set_ofono_sim(self, NULL);
G_OBJECT_CLASS(ril_sim_settings_parent_class)->dispose(object);
}
static void ril_sim_settings_class_init(RilSimSettingsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_sim_settings_dispose;
g_type_class_add_private(klass, sizeof(struct ril_sim_settings_priv));
NEW_SIGNAL(klass, IMSI);
NEW_SIGNAL(klass, PREF_MODE);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,59 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_SIM_SETTINGS_H
#define RIL_SIM_SETTINGS_H
#include "ril_types.h"
#include <ofono/radio-settings.h>
struct ril_sim_settings_priv;
struct ril_sim_settings {
GObject object;
struct ril_sim_settings_priv *priv;
gboolean enable_4g;
guint slot;
const char *imsi;
enum ofono_radio_access_mode pref_mode;
};
typedef void (*ril_sim_settings_cb_t)(struct ril_sim_settings *s, void *arg);
struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc);
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *s);
void ril_sim_settings_unref(struct ril_sim_settings *s);
void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *s,
struct ofono_sim *sim);
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *s,
enum ofono_radio_access_mode mode);
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *s,
ril_sim_settings_cb_t cb, void *arg);
gulong ril_sim_settings_add_pref_mode_changed_handler(struct ril_sim_settings *s,
ril_sim_settings_cb_t cb, void *arg);
void ril_sim_settings_remove_handler(struct ril_sim_settings *s, gulong id);
void ril_sim_settings_remove_handlers(struct ril_sim_settings *s, gulong *ids,
int count);
#endif /* RIL_SIM_SETTINGS_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
@@ -22,13 +22,16 @@
#include "util.h"
#include "simutil.h"
#define RIL_SMS_ACK_RETRY_MS 1000
#define RIL_SMS_ACK_RETRY_COUNT 10
#define SIM_EFSMS_FILEID 0x6F3C
#define EFSMS_LENGTH 176
#define TYPE_LOCAL 129
#define TYPE_INTERNATIONAL 145
static unsigned char path[4] = {0x3F, 0x00, 0x7F, 0x10};
static unsigned char sim_path[4] = {0x3F, 0x00, 0x7F, 0x10};
enum ril_sms_events {
SMS_EVENT_NEW_SMS,
@@ -42,6 +45,7 @@ struct ril_sms {
GRilIoQueue *q;
struct ril_modem *modem;
struct ofono_sms *sms;
struct ofono_sim_context *sim_context;
gulong event_id[SMS_EVENT_COUNT];
guint timer_id;
};
@@ -277,6 +281,8 @@ static void ril_ack_delivery(struct ril_sms *sd, gboolean error)
grilio_request_append_int32(req, code); /* error code */
/* ACK the incoming NEW_SMS */
grilio_request_set_retry(req, RIL_SMS_ACK_RETRY_MS,
RIL_SMS_ACK_RETRY_COUNT);
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SMS_ACKNOWLEDGE, ril_ack_delivery_cb, NULL, NULL);
grilio_request_unref(req);
@@ -366,11 +372,10 @@ static void ril_request_delete_sms_om_sim(struct ril_sms *sd, int record)
grilio_request_unref(req);
}
static void ril_sms_on_sim_cb(const struct ofono_error *error,
const unsigned char *sdata,
int length, void *data)
static void ril_sms_on_sim_cb(int ok, int total_length, int record,
const unsigned char *sdata, int length, void *userdata)
{
struct ril_sms_on_sim_req *cbd = data;
struct ril_sms_on_sim_req *cbd = userdata;
struct ril_sms *sd = cbd->sd;
/*
@@ -383,7 +388,7 @@ static void ril_sms_on_sim_cb(const struct ofono_error *error,
* the read length to take into account this read octet in order
* to calculate the proper tpdu length.
*/
if (error->type == OFONO_ERROR_TYPE_NO_ERROR) {
if (ok) {
unsigned int smsc_len = sdata[1] + 1;
ofono_sms_deliver_notify(sd->sms, sdata + 1, length - 1,
length - smsc_len - 1);
@@ -409,10 +414,15 @@ static void ril_sms_on_sim(GRilIoChannel *io, guint ril_event,
grilio_parser_get_int32(&rilp, &data_len) && data_len > 0 &&
grilio_parser_get_int32(&rilp, &rec)) {
DBG("rec %d", rec);
ril_sim_read_file_linear(sim, SIM_EFSMS_FILEID, rec,
EFSMS_LENGTH, path, sizeof(path),
ril_sms_on_sim_cb,
ril_sms_on_sim_req_new(sd,rec));
if (sd->sim_context) {
ofono_sim_read_record(sd->sim_context,
SIM_EFSMS_FILEID,
OFONO_SIM_FILE_STRUCTURE_FIXED,
rec, EFSMS_LENGTH,
sim_path, sizeof(sim_path),
ril_sms_on_sim_cb,
ril_sms_on_sim_req_new(sd,rec));
}
}
}
@@ -444,14 +454,18 @@ static int ril_sms_probe(struct ofono_sms *sms, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
struct ofono_sim *sim = ril_modem_ofono_sim(modem);
struct ril_sms *sd = g_new0(struct ril_sms, 1);
sd->modem = modem;
sd->sms = sms;
sd->io = grilio_channel_ref(ril_modem_io(modem));
sd->sim_context = ofono_sim_context_create(sim);
sd->q = grilio_queue_new(sd->io);
sd->timer_id = g_idle_add(ril_sms_register, sd);
ofono_sms_set_data(sms, sd);
GASSERT(sd->sim_context);
return 0;
}
@@ -463,6 +477,10 @@ static void ril_sms_remove(struct ofono_sms *sms)
DBG("");
ofono_sms_set_data(sms, NULL);
if (sd->sim_context) {
ofono_sim_context_free(sd->sim_context);
}
for (i=0; i<G_N_ELEMENTS(sd->event_id); i++) {
grilio_channel_remove_handler(sd->io, sd->event_id[i]);

View File

@@ -1,11 +1,31 @@
# This is a sample configuration file for the ril driver
# This is a sample configuration file for Jolla 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.
# Configuration for each modem is defined in its own [ril_x] section,
# common settings are in the [Settings] section, all other sections
# are ignored.
#
# If any value from [ril_x] section (except "socket") is defined
# in the [Settings] section, it becomes the default for all modems.
# Default values can still be redefined at [ril_x] level.
#
[Settings]
# If the phone has more than one SIM slot, the 3G/LTE module may be
# shared by all modems, meaning that only one of the slots can use
# 3G/LTE. In order to "hand 4G over" to the other slot, the modem
# currently using 3G/LTE has to drop to GSM, release 3G/LTE module
# and only then 3G/LTE can be used by the other modem. This setting
# allows to disable this behaviour (say, if your phone has independent
# 3G/LTE modules for each slot or you don't need 4G for both slots).
# Obviously, it only has any effect if you have more than one SIM.
#
# Default is true (switch the current data modem to 2G when changing
# the data modems)
#
#3GLTEHandover=true
[ril_0]
@@ -53,3 +73,25 @@ socket=/dev/socket/rild
# Default is true (select SET_UICC_SUBSCRIPTION based on the RIL version)
#
#uiccWorkaround=true
# Points to the file containing comma-separated ECC (Emergency List Codes)
# list, e.g. 911,112,*911,#911. The file is tracked by ofono and when its
# contents changes, it's reflected in the EmergencyNumbers property of
# org.ofono.VoiceCallManager.
#
# If necessary, the contents of the file can be synchronized with the
# Android system property by adding something like this to /init.rc:
#
# on property:ril.ecclist=*
# write /var/lib/ofono/ril.ecclist ${ril.ecclist}
# chmod 0644 /var/lib/ofono/ril.ecclist
#
#ecclistFile=/var/lib/ofono/ril.ecclist
# RIL_REQUEST_ALLOW_DATA may or may not be supported by your RIL.
# This option allows you to forcibly enable or disable use of this request.
# Possible values are auto, on and off
#
# Default is auto (usage based on the RIL version)
#
#allowDataReq=auto

View File

@@ -26,6 +26,7 @@
#include <ofono/types.h>
struct ofono_modem;
struct ofono_sim;
#include <stdio.h>
#include <errno.h>
@@ -38,12 +39,20 @@ struct ofono_modem;
#define RIL_RETRY_SECS (2)
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
struct ril_mce;
struct ril_data;
struct ril_modem;
struct ril_radio;
struct ril_network;
struct ril_sim_card;
struct ril_plugin_dbus;
struct ril_sim_info;
struct ril_sim_settings;
struct ril_cell_info;
struct ril_slot_config {
guint slot;
gboolean enable_4g;
};
#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
@@ -9,7 +9,7 @@
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
@@ -101,11 +101,10 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
}
grilio_request_append_utf8_chars(req, (char*)
unpacked_buf, length);
grilio_queue_send_request_full(ud->q, req,
RIL_REQUEST_SEND_USSD, ril_ussd_cb,
ril_ussd_cbd_free,
ril_ussd_cbd_new(cb, data));
grilio_queue_send_request(ud->q, req,
RIL_REQUEST_SEND_USSD);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
return;
}
}

View File

@@ -15,14 +15,15 @@
#include "ril_plugin.h"
#include "ril_constants.h"
#include "ril_ecclist.h"
#include "ril_util.h"
#include "ril_log.h"
#include "common.h"
/* Amount of ms we wait between CLCC calls */
#include <gutil_ring.h>
#define FLAG_NEED_CLIP 1
#define MAX_DTMF_BUFFER 32
enum ril_voicecall_events {
VOICECALL_EVENT_CALL_STATE_CHANGED,
@@ -36,24 +37,19 @@ struct ril_voicecall {
GRilIoChannel *io;
GRilIoQueue *q;
struct ofono_voicecall *vc;
struct ril_ecclist *ecclist;
unsigned int local_release;
unsigned char flags;
ofono_voicecall_cb_t cb;
void *data;
guint timer_id;
gchar *tone_queue;
GUtilRing* dtmf_queue;
guint send_dtmf_id;
guint clcc_poll_id;
gulong event_id[VOICECALL_EVENT_COUNT];
gulong supp_svc_notification_id;
gulong ringback_tone_event_id;
};
struct release_id_req {
struct ofono_voicecall *vc;
ofono_voicecall_cb_t cb;
gpointer data;
int id;
gulong ecclist_change_id;
};
struct ril_voicecall_change_state_req {
@@ -68,12 +64,6 @@ struct lastcause_req {
int id;
};
struct ril_voicecall_req {
struct ofono_voicecall *vc;
ofono_voicecall_cb_t cb;
gpointer data;
};
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
@@ -322,9 +312,10 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
ofono_voicecall_notify(vd->vc, nc);
if (vd->cb) {
ofono_voicecall_cb_t cb = vd->cb;
cb(ril_error_ok(&error), vd->data);
void *cbdata = vd->data;
vd->cb = NULL;
vd->data = NULL;
cb(ril_error_ok(&error), cbdata);
}
}
@@ -383,9 +374,12 @@ static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
{
GASSERT(vd);
if (!vd->clcc_poll_id) {
GRilIoRequest* req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
vd->clcc_poll_id = grilio_queue_send_request_full(vd->q,
NULL, RIL_REQUEST_GET_CURRENT_CALLS,
req, RIL_REQUEST_GET_CURRENT_CALLS,
ril_voicecall_clcc_poll_cb, NULL, vd);
grilio_request_unref(req);
}
}
@@ -443,9 +437,7 @@ static void ril_voicecall_request(const guint rreq, struct ofono_voicecall *vc,
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_voicecall_req *cbd = user_data;
struct ofono_voicecall *vc = cbd->vc;
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ril_voicecall *vd = user_data;
if (status == RIL_E_SUCCESS) {
if (vd->cb) {
@@ -454,11 +446,21 @@ static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
ril_voicecall_clcc_poll(vd);
}
} else {
struct ofono_error error;
ofono_error("call failed.");
vd->cb = cbd->cb;
vd->data = cbd->data;
cbd->cb(ril_error_failure(&error), cbd->data);
/*
* Even though this dial request may have already been
* completed (successfully) by ril_voicecall_clcc_poll_cb,
* RIL_REQUEST_DIAL may still fail.
*/
if (vd->cb) {
struct ofono_error error;
ofono_voicecall_cb_t cb = vd->cb;
void *cbdata = vd->data;
vd->cb = NULL;
vd->data = NULL;
cb(ril_error_failure(&error), cbdata);
}
}
}
@@ -468,27 +470,22 @@ static void ril_voicecall_dial(struct ofono_voicecall *vc,
void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ril_voicecall_req *cbd = g_new(struct ril_voicecall_req, 1);
const char *phstr = phone_number_to_string(ph);
GRilIoRequest *req = grilio_request_new();
ofono_info("dialing \"%s\"", phstr);
DBG("%s,%d,0", phstr, clir);
cbd->vc = vc;
cbd->cb = cb;
cbd->data = data;
GASSERT(!vd->cb);
vd->cb = cbd->cb;
vd->data = cbd->data;
vd->cb = cb;
vd->data = data;
grilio_request_append_utf8(req, phstr); /* Number to dial */
grilio_request_append_int32(req, clir); /* CLIR mode */
grilio_request_append_int32(req, 0); /* UUS information (absent) */
grilio_queue_send_request_full(vd->q, req, RIL_REQUEST_DIAL,
ril_voicecall_dial_cb, g_free, cbd);
ril_voicecall_dial_cb, NULL, vd);
grilio_request_unref(req);
}
@@ -599,11 +596,6 @@ static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
vd->send_dtmf_id = 0;
if (status == RIL_E_SUCCESS) {
/* Remove sent DTMF character from queue */
gchar *tmp = g_strdup(vd->tone_queue + 1);
g_free(vd->tone_queue);
vd->tone_queue = tmp;
/* Send the next one */
ril_voicecall_send_one_dtmf(vd);
} else {
@@ -614,12 +606,15 @@ static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd)
{
if (!vd->send_dtmf_id && vd->tone_queue && vd->tone_queue[0]) {
if (!vd->send_dtmf_id && gutil_ring_size(vd->dtmf_queue) > 0) {
GRilIoRequest *req = grilio_request_sized_new(4);
const char dtmf_char = (char)
GPOINTER_TO_UINT(gutil_ring_get(vd->dtmf_queue));
/* RIL wants just one character */
DBG("%c", vd->tone_queue[0]);
grilio_request_append_utf8_chars(req, vd->tone_queue, 1);
GASSERT(dtmf_char);
DBG("%c", dtmf_char);
grilio_request_append_utf8_chars(req, &dtmf_char, 1);
vd->send_dtmf_id = grilio_queue_send_request_full(vd->q, req,
RIL_REQUEST_DTMF, ril_voicecall_send_dtmf_cb, NULL, vd);
grilio_request_unref(req);
@@ -632,23 +627,23 @@ static void ril_voicecall_send_dtmf(struct ofono_voicecall *vc,
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ofono_error error;
DBG("Queue '%s'",dtmf);
/*
* Queue any incoming DTMF (up to MAX_DTMF_BUFFER characters),
* send them to RIL one-by-one, immediately call back
* core with no error
* Queue any incoming DTMF, send them to RIL one-by-one,
* immediately call back core with no error
*/
g_strlcat(vd->tone_queue, dtmf, MAX_DTMF_BUFFER);
ril_voicecall_send_one_dtmf(vd);
DBG("Queue '%s'", dtmf);
while (*dtmf) {
gutil_ring_put(vd->dtmf_queue, GUINT_TO_POINTER(*dtmf));
dtmf++;
}
ril_voicecall_send_one_dtmf(vd);
cb(ril_error_ok(&error), data);
}
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd)
{
g_free(vd->tone_queue);
vd->tone_queue = g_strnfill(MAX_DTMF_BUFFER + 1, '\0');
gutil_ring_clear(vd->dtmf_queue);
if (vd->send_dtmf_id) {
grilio_channel_cancel_request(vd->io, vd->send_dtmf_id, FALSE);
vd->send_dtmf_id = 0;
@@ -759,6 +754,13 @@ static void ril_voicecall_ringback_tone_event(GRilIoChannel *io,
ofono_voicecall_ringback_tone_notify(vd->vc, playTone);
}
static void ril_voicecall_ecclist_changed(struct ril_ecclist *list, void *data)
{
struct ril_voicecall *vd = data;
ofono_voicecall_en_list_notify(vd->vc, vd->ecclist->list);
}
static gboolean ril_delayed_register(gpointer user_data)
{
struct ril_voicecall *vd = user_data;
@@ -767,6 +769,14 @@ static gboolean ril_delayed_register(gpointer user_data)
vd->timer_id = 0;
ofono_voicecall_register(vd->vc);
/* Emergency Call Codes */
if (vd->ecclist) {
ofono_voicecall_en_list_notify(vd->vc, vd->ecclist->list);
vd->ecclist_change_id =
ril_ecclist_add_list_changed_handler(vd->ecclist,
ril_voicecall_ecclist_changed, vd);
}
/* Initialize call list */
ril_voicecall_clcc_poll(vd);
@@ -805,8 +815,12 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
vd = g_new0(struct ril_voicecall, 1);
vd->io = grilio_channel_ref(ril_modem_io(modem));
vd->q = grilio_queue_new(vd->io);
vd->dtmf_queue = gutil_ring_new();
vd->vc = vc;
vd->timer_id = g_idle_add(ril_delayed_register, vd);
if (modem->ecclist_file) {
vd->ecclist = ril_ecclist_new(modem->ecclist_file);
}
ril_voicecall_clear_dtmf_queue(vd);
ofono_voicecall_set_data(vc, vd);
return 0;
@@ -814,26 +828,25 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
static void ril_voicecall_remove(struct ofono_voicecall *vc)
{
int i;
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
DBG("");
ofono_voicecall_set_data(vc, NULL);
g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
g_slist_free(vd->calls);
for (i=0; i<G_N_ELEMENTS(vd->event_id); i++) {
grilio_channel_remove_handler(vd->io, vd->event_id[i]);
}
g_slist_free_full(vd->calls, g_free);
if (vd->timer_id > 0) {
g_source_remove(vd->timer_id);
}
ril_ecclist_remove_handler(vd->ecclist, vd->ecclist_change_id);
ril_ecclist_unref(vd->ecclist);
grilio_channel_remove_handlers(vd->io, vd->event_id,
G_N_ELEMENTS(vd->event_id));
grilio_channel_unref(vd->io);
grilio_queue_cancel_all(vd->q, FALSE);
grilio_queue_unref(vd->q);
g_free(vd->tone_queue);
gutil_ring_unref(vd->dtmf_queue);
g_free(vd);
}

View File

@@ -58,14 +58,6 @@ struct netreg_data {
int corestatus; /* Registration status previously reported to core */
};
/* 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 *current_netreg;
static void extract_mcc_mnc(const char *str, char *mcc, char *mnc)

View File

@@ -3,7 +3,7 @@
* oFono - Open Telephony stack for Linux
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013 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
@@ -61,7 +61,6 @@ extern "C" {
#define OFONO_GNSS_POSR_AGENT_INTERFACE "org.ofono.PositioningRequestAgent"
#define OFONO_HANDSFREE_INTERFACE OFONO_SERVICE ".Handsfree"
#define OFONO_NETWORK_TIME_INTERFACE OFONO_SERVICE ".NetworkTime"
#define OFONO_OEM_RAW_INTERFACE "org.ofono.OemRaw"
#define OFONO_SIRI_INTERFACE OFONO_SERVICE ".Siri"
/* CDMA Interfaces */

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

@@ -3,6 +3,7 @@
* oFono - Open Telephony stack for Linux
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,6 +23,8 @@
#ifndef __OFONO_LOG_H
#define __OFONO_LOG_H
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -50,6 +53,7 @@ struct ofono_debug_desc {
const char *file;
#define OFONO_DEBUG_FLAG_DEFAULT (0)
#define OFONO_DEBUG_FLAG_PRINT (1 << 0)
#define OFONO_DEBUG_FLAG_HIDE_NAME (1 << 1)
unsigned int flags;
void (*notify)(struct ofono_debug_desc* desc);
} __attribute__((aligned(OFONO_DEBUG_ALIGN)));
@@ -67,10 +71,20 @@ struct ofono_debug_desc {
.file = __FILE__, .flags = OFONO_DEBUG_FLAG_DEFAULT, \
}; \
if (__ofono_debug_desc.flags & OFONO_DEBUG_FLAG_PRINT) \
ofono_debug("%s:%s() " fmt, \
__FILE__, __FUNCTION__ , ## arg); \
__ofono_dbg(&__ofono_debug_desc, "%s() " fmt, \
__FUNCTION__ , ## arg); \
} while (0)
void __ofono_dbg(const struct ofono_debug_desc *desc, const char *format, ...)
__attribute__((format(printf, 2, 3)));
typedef void (*ofono_log_hook_cb_t)(const struct ofono_debug_desc *desc,
int priority, const char *format, va_list va);
extern ofono_log_hook_cb_t ofono_log_hook;
extern struct ofono_debug_desc __start___debug[];
extern struct ofono_debug_desc __stop___debug[];
#ifdef __cplusplus
}
#endif

View File

@@ -1,77 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2013 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __OFONO_OEM_RAW_H
#define __OFONO_OEM_RAW_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <dbus/dbus.h>
#include <ofono/types.h>
struct ofono_oem_raw;
/* Request response from driver to core */
struct ofono_oem_raw_results {
char *data;
int length;
};
/* Request details from core to driver */
struct ofono_oem_raw_request {
char *data;
int length; /* Number of bytes in data */
DBusMessage *pending;
};
typedef void (*ofono_oem_raw_query_cb_t)(const struct ofono_error *error,
const struct ofono_oem_raw_results *results, void *data);
struct ofono_oem_raw_driver {
const char *name;
int (*probe)(struct ofono_oem_raw *raw,
unsigned int vendor,
void *data);
void (*remove)(struct ofono_oem_raw *raw);
void (*request)(struct ofono_oem_raw *raw,
const struct ofono_oem_raw_request *request,
ofono_oem_raw_query_cb_t cb,
void *data);
};
struct ofono_oem_raw *ofono_oem_raw_create(struct ofono_modem *modem,
unsigned int vendor,
const char *driver,
void *data);
void ofono_oem_raw_dbus_register(struct ofono_oem_raw *raw);
void ofono_oem_raw_remove(struct ofono_oem_raw *raw);
int ofono_oem_raw_driver_register(struct ofono_oem_raw_driver *driver);
void ofono_oem_raw_driver_unregister(struct ofono_oem_raw_driver *driver);
void *ofono_oem_raw_get_data(struct ofono_oem_raw *raw);
void ofono_oem_raw_set_data(struct ofono_oem_raw *raw, void *cid);
#ifdef __cplusplus
}
#endif
#endif /* __OFONO_OEM_RAW_H */

View File

@@ -133,6 +133,13 @@ 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);
const char *ofono_radio_access_mode_to_string(enum ofono_radio_access_mode m);
ofono_bool_t ofono_radio_access_mode_from_string(const char *str,
enum ofono_radio_access_mode *mode);
#ifdef __cplusplus
}
#endif

View File

@@ -104,6 +104,11 @@ typedef void (*ofono_sim_state_event_cb_t)(enum ofono_sim_state new_state,
typedef void (*ofono_sim_file_read_cb_t)(int ok, int total_length, int record,
const unsigned char *data,
int record_length, void *userdata);
typedef void (*ofono_sim_read_info_cb_t)(int ok, unsigned char file_status,
int total_length, int record_length,
void *userdata);
typedef void (*ofono_sim_file_changed_cb_t)(int id, void *userdata);
typedef void (*ofono_sim_file_write_cb_t)(int ok, void *userdata);
@@ -215,6 +220,22 @@ ofono_bool_t ofono_sim_add_spn_watch(struct ofono_sim *sim, unsigned int *id,
ofono_bool_t ofono_sim_remove_spn_watch(struct ofono_sim *sim, unsigned int *id);
typedef void (*ofono_sim_iccid_event_cb_t)(const char *iccid, void *data);
unsigned int ofono_sim_add_iccid_watch(struct ofono_sim *sim,
ofono_sim_iccid_event_cb_t cb, void *data,
ofono_destroy_func destroy);
void ofono_sim_remove_iccid_watch(struct ofono_sim *sim, unsigned int id);
typedef void (*ofono_sim_imsi_event_cb_t)(const char *imsi, void *data);
unsigned int ofono_sim_add_imsi_watch(struct ofono_sim *sim,
ofono_sim_imsi_event_cb_t cb, void *data,
ofono_destroy_func destroy);
void ofono_sim_remove_imsi_watch(struct ofono_sim *sim, unsigned int id);
void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted);
struct ofono_sim_context *ofono_sim_context_create(struct ofono_sim *sim);
@@ -231,6 +252,22 @@ int ofono_sim_read(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected,
ofono_sim_file_read_cb_t cb, void *data);
int ofono_sim_read_path(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
const unsigned char *path, unsigned int path_len,
ofono_sim_file_read_cb_t cb, void *data);
int ofono_sim_read_info(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
const unsigned char *path, unsigned int pth_len,
ofono_sim_read_info_cb_t cb, void *data);
int ofono_sim_read_record(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
int record, int record_length,
const unsigned char *path, unsigned int pth_len,
ofono_sim_file_read_cb_t cb, void *data);
int ofono_sim_write(struct ofono_sim_context *context, int id,
ofono_sim_file_write_cb_t cb,
enum ofono_sim_file_structure structure, int record,

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

@@ -2,7 +2,7 @@
*
* oFono - Open Source Telephony
*
* Copyright (C) 2015 Jolla Ltd. All rights reserved.
* Copyright (C) 2015-2016 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,49 +13,148 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gdbus.h>
#include <string.h>
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include <ofono/dbus.h>
#include <ofono/log.h>
#include <ofono.h>
#define DEBUGLOG_INTERFACE OFONO_SERVICE ".DebugLog"
#define DEBUGLOG_PATH "/"
#define DEBUGLOG_CHANGED_SIGNAL "Changed"
#include <dbuslog_server_dbus.h>
#include <gutil_log.h>
static DBusConnection *connection = NULL;
#include <string.h>
#include <syslog.h>
extern struct ofono_debug_desc __start___debug[];
extern struct ofono_debug_desc __stop___debug[];
#define DEBUGLOG_PATH "/"
static void debuglog_signal(DBusConnection *conn, const char *name,
guint flags)
enum _debug_server_event {
DEBUG_EVENT_CATEGORY_ENABLED,
DEBUG_EVENT_CATEGORY_DISABLED,
DEBUG_EVENT_COUNT
};
static DBusLogServer *debuglog_server;
static GLogProc2 debuglog_default_log_proc;
static gulong debuglog_event_id[DEBUG_EVENT_COUNT];
static void debuglog_ofono_log_hook(const struct ofono_debug_desc *desc,
int priority, const char *format, va_list va)
{
DBusMessage *signal = dbus_message_new_signal(DEBUGLOG_PATH,
DEBUGLOG_INTERFACE, DEBUGLOG_CHANGED_SIGNAL);
DBUSLOG_LEVEL dbuslevel;
const char *category;
if (signal) {
DBusMessageIter iter;
const dbus_bool_t on = (flags & OFONO_DEBUG_FLAG_PRINT) != 0;
dbus_message_iter_init_append(signal, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &on);
g_dbus_send_message(conn, signal);
if (desc) {
category = desc->name ? desc->name : desc->file;
} else {
category = NULL;
}
/* ofono is only using these four priorities: */
switch (priority) {
case LOG_ERR:
dbuslevel = DBUSLOG_LEVEL_ERROR;
break;
case LOG_WARNING:
dbuslevel = DBUSLOG_LEVEL_WARNING;
break;
case LOG_INFO:
dbuslevel = DBUSLOG_LEVEL_INFO;
break;
case LOG_DEBUG:
dbuslevel = DBUSLOG_LEVEL_DEBUG;
break;
default:
dbuslevel = DBUSLOG_LEVEL_UNDEFINED;
break;
}
dbus_log_server_logv(debuglog_server, dbuslevel, category, format, va);
}
static void debuglog_gutil_log_func(const GLogModule* log, int level,
const char* format, va_list va)
{
DBUSLOG_LEVEL loglevel;
switch (level) {
case GLOG_LEVEL_ERR:
loglevel = DBUSLOG_LEVEL_ERROR;
break;
case GLOG_LEVEL_WARN:
loglevel = DBUSLOG_LEVEL_WARNING;
break;
case GLOG_LEVEL_INFO:
loglevel = DBUSLOG_LEVEL_INFO;
break;
case GLOG_LEVEL_DEBUG:
loglevel = DBUSLOG_LEVEL_DEBUG;
break;
case GLOG_LEVEL_VERBOSE:
loglevel = DBUSLOG_LEVEL_VERBOSE;
break;
default:
loglevel = DBUSLOG_LEVEL_UNDEFINED;
break;
}
dbus_log_server_logv(debuglog_server, loglevel, log->name, format, va);
if (debuglog_default_log_proc) {
debuglog_default_log_proc(log, level, format, va);
}
}
static gboolean debuglog_match(const char* s1, const char* s2)
{
return s1 && s2 && !strcmp(s1, s2);
}
static void debuglog_update_flags(const char* name, guint set, guint clear)
{
const guint flags = set | clear;
struct ofono_debug_desc *start = __start___debug;
struct ofono_debug_desc *stop = __stop___debug;
if (start && stop) {
struct ofono_debug_desc *desc;
for (desc = start; desc < stop; desc++) {
const char *matched = NULL;
if (debuglog_match(desc->file, name)) {
matched = desc->file;
} else if (debuglog_match(desc->name, name)) {
matched = desc->name;
}
if (matched) {
const guint old_flags = (desc->flags & flags);
desc->flags |= set;
desc->flags &= ~clear;
if ((desc->flags & flags) != old_flags &&
desc->notify) {
desc->notify(desc);
}
}
}
}
}
static void debuglog_category_enabled(DBusLogServer* server,
const char* category, gpointer user_data)
{
debuglog_update_flags(category, OFONO_DEBUG_FLAG_PRINT, 0);
}
static void debuglog_category_disabled(DBusLogServer* server,
const char* category, gpointer user_data)
{
debuglog_update_flags(category, 0, OFONO_DEBUG_FLAG_PRINT);
}
static GHashTable *debuglog_update_flags_hash(GHashTable *hash,
@@ -77,197 +176,80 @@ static GHashTable *debuglog_update_flags_hash(GHashTable *hash,
return hash;
}
static gboolean debuglog_match(const char* name, const char* pattern)
static guint debuglog_translate_flags(unsigned int ofono_flags)
{
return name && g_pattern_match_simple(pattern, name);
guint flags = 0;
if (ofono_flags & OFONO_DEBUG_FLAG_PRINT)
flags |= DBUSLOG_CATEGORY_FLAG_ENABLED;
if (ofono_flags & OFONO_DEBUG_FLAG_HIDE_NAME)
flags |= DBUSLOG_CATEGORY_FLAG_HIDE_NAME;
return flags;
}
static void debuglog_update(DBusConnection *conn, const char* pattern,
guint set_flags, guint clear_flags)
{
const guint flags = set_flags | clear_flags;
struct ofono_debug_desc *start = __start___debug;
struct ofono_debug_desc *stop = __stop___debug;
struct ofono_debug_desc *desc;
GHashTable *hash = NULL;
if (!start || !stop)
return;
for (desc = start; desc < stop; desc++) {
const char *matched = NULL;
if (debuglog_match(desc->file, pattern)) {
matched = desc->file;
} else if (debuglog_match(desc->name, pattern)) {
matched = desc->name;
}
if (matched) {
const guint old_flags = (desc->flags & flags);
desc->flags |= set_flags;
desc->flags &= ~clear_flags;
if ((desc->flags & flags) != old_flags) {
hash = debuglog_update_flags_hash(hash,
matched, desc->flags);
if (desc->notify) {
desc->notify(desc);
}
}
}
}
if (hash) {
GList *entry, *names = g_hash_table_get_keys(hash);
for (entry = names; entry; entry = entry->next) {
debuglog_signal(conn, entry->data,
GPOINTER_TO_INT(g_hash_table_lookup(
hash, entry->data)));
}
g_list_free(names);
g_hash_table_destroy(hash);
}
}
static DBusMessage *debuglog_handle(DBusConnection *conn, DBusMessage *msg,
guint set_flags, guint clear_flags)
{
const char *pattern;
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
DBUS_TYPE_INVALID)) {
debuglog_update(conn, pattern, set_flags, clear_flags);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
} else {
return __ofono_error_invalid_args(msg);
}
}
static DBusMessage *debuglog_enable(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return debuglog_handle(conn, msg, OFONO_DEBUG_FLAG_PRINT, 0);
}
static DBusMessage *debuglog_disable(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return debuglog_handle(conn, msg, 0, OFONO_DEBUG_FLAG_PRINT);
}
static gint debuglog_list_compare(gconstpointer a, gconstpointer b)
{
return strcmp(a, b);
}
static void debuglog_list_append(DBusMessageIter *iter, const char *name,
guint flags)
{
DBusMessageIter entry;
dbus_bool_t enabled = (flags & OFONO_DEBUG_FLAG_PRINT) != 0;
dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN, &enabled);
dbus_message_iter_close_container(iter, &entry);
}
static DBusMessage *debuglog_list(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
if (reply) {
struct ofono_debug_desc *start = __start___debug;
struct ofono_debug_desc *stop = __stop___debug;
DBusMessageIter iter, array;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
"(sb)", &array);
if (start && stop) {
struct ofono_debug_desc *desc;
GList *names, *entry;
GHashTable *hash = g_hash_table_new_full(g_str_hash,
g_str_equal, NULL, NULL);
for (desc = start; desc < stop; desc++) {
debuglog_update_flags_hash(hash, desc->file,
desc->flags);
debuglog_update_flags_hash(hash, desc->name,
desc->flags);
}
names = g_list_sort(g_hash_table_get_keys(hash),
debuglog_list_compare);
for (entry = names; entry; entry = entry->next) {
const char *name = entry->data;
debuglog_list_append(&array, name,
GPOINTER_TO_INT(g_hash_table_lookup(
hash, name)));
}
g_list_free(names);
g_hash_table_destroy(hash);
}
dbus_message_iter_close_container(&iter, &array);
}
return reply;
}
static const GDBusMethodTable debuglog_methods[] = {
{ GDBUS_METHOD("Enable", GDBUS_ARGS({ "pattern", "s" }), NULL,
debuglog_enable) },
{ GDBUS_METHOD("Disable", GDBUS_ARGS({ "pattern", "s" }), NULL,
debuglog_disable) },
{ GDBUS_METHOD("List", NULL, GDBUS_ARGS({ "list", "a(sb)" }),
debuglog_list) },
{ },
};
static const GDBusSignalTable debuglog_signals[] = {
{ GDBUS_SIGNAL(DEBUGLOG_CHANGED_SIGNAL,
GDBUS_ARGS({ "name", "s" }, { "enabled", "b" })) },
{ }
};
static int debuglog_init(void)
{
DBG("");
const struct ofono_debug_desc *start = __start___debug;
const struct ofono_debug_desc *stop = __stop___debug;
connection = ofono_dbus_get_connection();
if (!connection)
return -1;
debuglog_server = dbus_log_server_new(ofono_dbus_get_connection(),
DEBUGLOG_PATH);
if (!g_dbus_register_interface(connection, DEBUGLOG_PATH,
DEBUGLOG_INTERFACE, debuglog_methods, debuglog_signals,
NULL, NULL, NULL)) {
ofono_error("debuglog: failed to register "
DEBUGLOG_INTERFACE);
return -1;
if (start && stop) {
const struct ofono_debug_desc *desc;
GHashTable *hash = NULL;
for (desc = start; desc < stop; desc++) {
const guint f = debuglog_translate_flags(desc->flags);
hash = debuglog_update_flags_hash(hash, desc->file, f);
hash = debuglog_update_flags_hash(hash, desc->name, f);
}
if (hash) {
gpointer key, value;
GHashTableIter it;
g_hash_table_iter_init(&it, hash);
while (g_hash_table_iter_next(&it, &key, &value)) {
dbus_log_server_add_category(debuglog_server,
key, DBUSLOG_LEVEL_UNDEFINED,
GPOINTER_TO_INT(value));
}
g_hash_table_destroy(hash);
}
debuglog_event_id[DEBUG_EVENT_CATEGORY_ENABLED] =
dbus_log_server_add_category_enabled_handler(
debuglog_server, debuglog_category_enabled,
NULL);
debuglog_event_id[DEBUG_EVENT_CATEGORY_DISABLED] =
dbus_log_server_add_category_disabled_handler(
debuglog_server, debuglog_category_disabled,
NULL);
}
debuglog_default_log_proc = gutil_log_func2;
gutil_log_func2 = debuglog_gutil_log_func;
ofono_log_hook = debuglog_ofono_log_hook;
dbus_log_server_set_default_level(debuglog_server, DBUSLOG_LEVEL_DEBUG);
dbus_log_server_start(debuglog_server);
return 0;
}
static void debuglog_exit(void)
{
DBG("");
if (connection) {
g_dbus_unregister_interface(connection, DEBUGLOG_PATH,
DEBUGLOG_INTERFACE);
dbus_connection_unref(connection);
connection = NULL;
}
gutil_log_func2 = debuglog_default_log_proc;
dbus_log_server_remove_handlers(debuglog_server, debuglog_event_id,
G_N_ELEMENTS(debuglog_event_id));
dbus_log_server_unref(debuglog_server);
debuglog_server = NULL;
}
OFONO_PLUGIN_DEFINE(debuglog, "Debug log control interface",
OFONO_PLUGIN_DEFINE(debuglog, "Debug log interface",
VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
debuglog_init, debuglog_exit)

View File

@@ -44,6 +44,16 @@
#include "mbpi.h"
const char *mbpi_database = MBPI_DATABASE;
/*
* Use IPv4 for MMS contexts because gprs.c assumes that MMS proxy
* address is IPv4.
*/
enum ofono_gprs_proto mbpi_default_internet_proto = OFONO_GPRS_PROTO_IPV4V6;
enum ofono_gprs_proto mbpi_default_mms_proto = OFONO_GPRS_PROTO_IP;
enum ofono_gprs_proto mbpi_default_proto = OFONO_GPRS_PROTO_IP;
#define _(x) case x: return (#x)
enum MBPI_ERROR {
@@ -111,7 +121,7 @@ static void mbpi_g_set_error(GMarkupParseContext *context, GError **error,
va_end(ap);
g_prefix_error(error, "%s:%d ", MBPI_DATABASE, line_number);
g_prefix_error(error, "%s:%d ", mbpi_database, line_number);
}
static void text_handler(GMarkupParseContext *context,
@@ -120,7 +130,7 @@ static void text_handler(GMarkupParseContext *context,
{
char **string = userdata;
g_free(*string);
g_free(*string);
*string = g_strndup(text, text_len);
}
@@ -166,7 +176,7 @@ static void authentication_start(GMarkupParseContext *context,
static void usage_start(GMarkupParseContext *context,
const gchar **attribute_names,
const gchar **attribute_values,
enum ofono_gprs_context_type *type, GError **error)
struct ofono_gprs_provision_data *apn, GError **error)
{
const char *text = NULL;
int i;
@@ -182,12 +192,14 @@ static void usage_start(GMarkupParseContext *context,
return;
}
if (strcmp(text, "internet") == 0)
*type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
else if (strcmp(text, "mms") == 0)
*type = OFONO_GPRS_CONTEXT_TYPE_MMS;
else if (strcmp(text, "wap") == 0)
*type = OFONO_GPRS_CONTEXT_TYPE_WAP;
if (strcmp(text, "internet") == 0) {
apn->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
apn->proto = mbpi_default_internet_proto;
} else if (strcmp(text, "mms") == 0) {
apn->type = OFONO_GPRS_CONTEXT_TYPE_MMS;
apn->proto = mbpi_default_mms_proto;
} else if (strcmp(text, "wap") == 0)
apn->type = OFONO_GPRS_CONTEXT_TYPE_WAP;
else
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
@@ -220,7 +232,7 @@ static void apn_start(GMarkupParseContext *context, const gchar *element_name,
&apn->message_proxy);
else if (g_str_equal(element_name, "usage"))
usage_start(context, attribute_names, attribute_values,
&apn->type, error);
apn, error);
}
static void apn_end(GMarkupParseContext *context, const gchar *element_name,
@@ -331,7 +343,7 @@ static void apn_handler(GMarkupParseContext *context, struct gsm_data *gsm,
ap->apn = g_strdup(apn);
ap->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
ap->proto = OFONO_GPRS_PROTO_IP;
ap->proto = mbpi_default_proto;
ap->auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
g_markup_parse_context_push(context, &apn_parser, ap);
@@ -611,11 +623,11 @@ static gboolean mbpi_parse(const GMarkupParser *parser, gpointer userdata,
GMarkupParseContext *context;
gboolean ret;
fd = open(MBPI_DATABASE, O_RDONLY);
fd = open(mbpi_database, O_RDONLY);
if (fd < 0) {
g_set_error(error, G_FILE_ERROR,
g_file_error_from_errno(errno),
"open(%s) failed: %s", MBPI_DATABASE,
"open(%s) failed: %s", mbpi_database,
g_strerror(errno));
return FALSE;
}
@@ -624,7 +636,7 @@ static gboolean mbpi_parse(const GMarkupParser *parser, gpointer userdata,
close(fd);
g_set_error(error, G_FILE_ERROR,
g_file_error_from_errno(errno),
"fstat(%s) failed: %s", MBPI_DATABASE,
"fstat(%s) failed: %s", mbpi_database,
g_strerror(errno));
return FALSE;
}
@@ -634,7 +646,7 @@ static gboolean mbpi_parse(const GMarkupParser *parser, gpointer userdata,
close(fd);
g_set_error(error, G_FILE_ERROR,
g_file_error_from_errno(errno),
"mmap(%s) failed: %s", MBPI_DATABASE,
"mmap(%s) failed: %s", mbpi_database,
g_strerror(errno));
return FALSE;
}

View File

@@ -19,6 +19,11 @@
*
*/
extern const char *mbpi_database;
extern enum ofono_gprs_proto mbpi_default_internet_proto;
extern enum ofono_gprs_proto mbpi_default_mms_proto;
extern enum ofono_gprs_proto mbpi_default_proto;
const char *mbpi_ap_type(enum ofono_gprs_context_type type);
void mbpi_ap_free(struct ofono_gprs_provision_data *data);

View File

@@ -3,7 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013 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
@@ -86,6 +86,7 @@ static gint provision_compare_ap(gconstpointer a, gconstpointer b, gpointer data
/* Picks best ap, deletes the rest. Creates one if necessary */
static GSList *provision_pick_best_ap(GSList *list, const char* spn,
const enum ofono_gprs_proto default_proto,
const struct provision_ap_defaults *defaults)
{
/* Sort the list */
@@ -101,6 +102,7 @@ static GSList *provision_pick_best_ap(GSList *list, const char* spn,
struct ofono_gprs_provision_data *ap =
g_new0(struct ofono_gprs_provision_data, 1);
ap->proto = default_proto;
ap->type = defaults->type;
ap->name = g_strdup(defaults->name);
ap->apn = g_strdup(defaults->apn);
@@ -136,8 +138,10 @@ static GSList *provision_normalize_apn_list(GSList *apns, const char* spn)
/* Pick the best ap of each type and concatenate them */
return g_slist_concat(
provision_pick_best_ap(internet_apns, spn, &internet_defaults),
provision_pick_best_ap(mms_apns, spn, &mms_defaults));
provision_pick_best_ap(internet_apns, spn,
mbpi_default_internet_proto, &internet_defaults),
provision_pick_best_ap(mms_apns, spn,
mbpi_default_mms_proto, &mms_defaults));
}
int provision_get_settings(const char *mcc, const char *mnc,

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

@@ -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

@@ -57,20 +57,6 @@
#define MAX_MESSAGE_CENTER_LENGTH 255
#define MAX_CONTEXTS 256
#define SUSPEND_TIMEOUT 8
#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;
@@ -802,31 +788,6 @@ static void pri_reset_context_settings(struct pri_context *ctx)
g_free(interface);
}
static void pri_limit_mtu(const char *interface, int max_mtu)
{
struct ifreq ifr;
int sk;
if (interface == NULL)
return;
sk = socket(PF_INET, SOCK_DGRAM, 0);
if (sk < 0)
return;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, interface, IFNAMSIZ);
if (ioctl(sk, SIOCGIFMTU, &ifr) < 0 || ifr.ifr_mtu > max_mtu) {
ifr.ifr_mtu = max_mtu;
if (ioctl(sk, SIOCSIFMTU, &ifr) < 0)
ofono_error("Failed to set MTU");
}
close(sk);
}
static void pri_update_mms_context_settings(struct pri_context *ctx)
{
struct ofono_gprs_context *gc = ctx->context_driver;
@@ -844,8 +805,6 @@ static void pri_update_mms_context_settings(struct pri_context *ctx)
if (ctx->proxy_host)
pri_setproxy(settings->interface, ctx->proxy_host);
pri_limit_mtu(settings->interface, MAX_MMS_MTU);
}
static gboolean pri_str_changed(const char *val, const char *newval)
@@ -856,8 +815,6 @@ static gboolean pri_str_changed(const char *val, const char *newval)
static gboolean pri_str_update(char *val, const char *newval,
const int maxlen)
{
DBG("oldval: %s, newval: %s, mmaxlen: %d", val, newval, maxlen);
if (newval) {
if (strcmp(val, newval)) {
strncpy(val, newval, maxlen);
@@ -1144,9 +1101,6 @@ static void pri_activate_callback(const struct ofono_error *error, void *data)
pri_context_signal_settings(ctx, gc->settings->ipv4 != NULL,
gc->settings->ipv6 != NULL);
if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET)
pri_limit_mtu(gc->settings->interface, MAX_GPRS_MTU);
}
value = ctx->active;
@@ -1901,8 +1855,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,
@@ -2635,7 +2589,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" })) },
{ }
};
@@ -2923,6 +2877,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)
{
@@ -3518,6 +3478,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);
@@ -3553,11 +3518,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

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -37,6 +38,9 @@
#include "ofono.h"
ofono_log_hook_cb_t ofono_log_hook;
static GString *ofono_debug_str;
static const char *program_exec;
static const char *program_path;
@@ -56,6 +60,12 @@ void ofono_info(const char *format, ...)
vsyslog(LOG_INFO, format, ap);
va_end(ap);
if (ofono_log_hook) {
va_start(ap, format);
ofono_log_hook(NULL, LOG_INFO, format, ap);
va_end(ap);
}
}
/**
@@ -74,6 +84,12 @@ void ofono_warn(const char *format, ...)
vsyslog(LOG_WARNING, format, ap);
va_end(ap);
if (ofono_log_hook) {
va_start(ap, format);
ofono_log_hook(NULL, LOG_WARNING, format, ap);
va_end(ap);
}
}
/**
@@ -92,6 +108,12 @@ void ofono_error(const char *format, ...)
vsyslog(LOG_ERR, format, ap);
va_end(ap);
if (ofono_log_hook) {
va_start(ap, format);
ofono_log_hook(NULL, LOG_ERR, format, ap);
va_end(ap);
}
}
/**
@@ -113,6 +135,37 @@ void ofono_debug(const char *format, ...)
vsyslog(LOG_DEBUG, format, ap);
va_end(ap);
if (ofono_log_hook) {
va_start(ap, format);
ofono_log_hook(NULL, LOG_DEBUG, format, ap);
va_end(ap);
}
}
void __ofono_dbg(const struct ofono_debug_desc *desc, const char *format, ...)
{
va_list ap;
if (!(desc->flags & OFONO_DEBUG_FLAG_PRINT))
return;
va_start(ap, format);
if (ofono_debug_str) {
g_string_vprintf(ofono_debug_str, format, ap);
syslog(LOG_DEBUG, "%s:%s", desc->file, ofono_debug_str->str);
} else {
vsyslog(LOG_DEBUG, format, ap);
}
va_end(ap);
if (ofono_log_hook) {
va_start(ap, format);
ofono_log_hook(desc, LOG_DEBUG, format, ap);
va_end(ap);
}
}
#ifdef __GLIBC__
@@ -306,6 +359,7 @@ int __ofono_log_init(const char *program, const char *debug,
program_exec = program;
program_path = getcwd(path, sizeof(path));
ofono_debug_str = g_string_sized_new(127);
if (debug != NULL)
enabled = g_strsplit_set(debug, ":, ", 0);
@@ -339,4 +393,6 @@ void __ofono_log_cleanup(ofono_bool_t backtrace)
#endif
g_strfreev(enabled);
g_string_free(ofono_debug_str, TRUE);
ofono_debug_str = NULL;
}

View File

@@ -1326,7 +1326,7 @@ void ofono_modem_remove_interface(struct ofono_modem *modem,
found = g_slist_find_custom(modem->interface_list, interface,
(GCompareFunc) strcmp);
if (found == NULL) {
ofono_error("Interface %s not found on the interface_list",
DBG("Interface %s not found on the interface_list",
interface);
return;
}
@@ -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;
@@ -70,6 +62,8 @@ struct ofono_netreg {
struct ofono_network_registration_ops *ops;
int flags;
DBusMessage *pending;
GSList *pending_auto;
GSList *pending_list;
int signal_strength;
struct sim_spdi *spdi;
struct sim_eons *eons;
@@ -607,7 +601,7 @@ static DBusMessage *network_operator_register(DBusConnection *conn,
if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
return __ofono_error_access_denied(msg);
if (netreg->pending)
if (netreg->pending || netreg->pending_auto || netreg->pending_list)
return __ofono_error_busy(msg);
if (netreg->driver->register_manual == NULL)
@@ -718,6 +712,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 +757,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);
@@ -850,6 +856,44 @@ static DBusMessage *network_get_properties(DBusConnection *conn,
return reply;
}
static void network_reply_ok(gpointer data)
{
DBusMessage *msg = data;
__ofono_dbus_pending_reply(&msg, dbus_message_new_method_return(msg));
}
static void network_reply_failed(gpointer data)
{
DBusMessage *msg = data;
__ofono_dbus_pending_reply(&msg, __ofono_error_failed(msg));
}
static void network_reply_canceled(gpointer data)
{
DBusMessage *msg = data;
__ofono_dbus_pending_reply(&msg, __ofono_error_canceled(msg));
}
static void register_auto_callback(const struct ofono_error *error, void *data)
{
struct ofono_netreg *netreg = data;
if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
g_slist_free_full(netreg->pending_auto, network_reply_ok);
else
g_slist_free_full(netreg->pending_auto, network_reply_failed);
netreg->pending_auto = NULL;
if (netreg->driver->registration_status)
netreg->driver->registration_status(netreg,
registration_status_callback,
netreg);
}
static DBusMessage *network_register(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -858,17 +902,19 @@ static DBusMessage *network_register(DBusConnection *conn,
if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
return __ofono_error_access_denied(msg);
if (netreg->pending)
if (netreg->pending || netreg->pending_list)
return __ofono_error_busy(msg);
if (netreg->driver->register_auto == NULL)
return __ofono_error_not_implemented(msg);
netreg->pending = dbus_message_ref(msg);
netreg->driver->register_auto(netreg, register_callback, netreg);
set_registration_mode(netreg, NETWORK_REGISTRATION_MODE_AUTO);
netreg->pending_auto = g_slist_append(netreg->pending_auto,
dbus_message_ref(msg));
if (!netreg->pending_auto->next) {
netreg->driver->register_auto(netreg, register_auto_callback,
netreg);
set_registration_mode(netreg, NETWORK_REGISTRATION_MODE_AUTO);
}
return NULL;
}
@@ -968,26 +1014,15 @@ static void network_signal_operators_changed(struct ofono_netreg *netreg)
g_dbus_send_message(conn, signal);
}
static void operator_list_callback(const struct ofono_error *error, int total,
const struct ofono_network_operator *list,
void *data)
static void operator_list_reply(gpointer data, gpointer user_data)
{
struct ofono_netreg *netreg = data;
struct ofono_netreg *netreg = user_data;
DBusMessage *msg = data;
DBusMessage *reply;
DBusMessageIter iter;
DBusMessageIter array;
gboolean changed;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error occurred during operator list");
__ofono_dbus_pending_reply(&netreg->pending,
__ofono_error_failed(netreg->pending));
return;
}
changed = update_operator_list(netreg, total, list);
reply = dbus_message_new_method_return(netreg->pending);
reply = dbus_message_new_method_return(msg);
dbus_message_iter_init_append(reply, &iter);
@@ -1004,12 +1039,31 @@ static void operator_list_callback(const struct ofono_error *error, int total,
append_operator_struct_list(netreg, &array);
dbus_message_iter_close_container(&iter, &array);
__ofono_dbus_pending_reply(&netreg->pending, reply);
__ofono_dbus_pending_reply(&msg, reply);
}
DBG("operator list %schanged", changed ? "" : "not ");
static void operator_list_callback(const struct ofono_error *error, int total,
const struct ofono_network_operator *list,
void *data)
{
struct ofono_netreg *netreg = data;
if (changed)
network_signal_operators_changed(netreg);
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error occurred during operator list");
g_slist_free_full(netreg->pending_list, network_reply_failed);
} else {
gboolean changed = update_operator_list(netreg, total, list);
g_slist_foreach(netreg->pending_list, operator_list_reply,
netreg);
g_slist_free(netreg->pending_list);
DBG("operator list %schanged", changed ? "" : "not ");
if (changed)
network_signal_operators_changed(netreg);
}
netreg->pending_list = NULL;
}
static DBusMessage *network_scan(DBusConnection *conn,
@@ -1020,16 +1074,17 @@ static DBusMessage *network_scan(DBusConnection *conn,
if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
return __ofono_error_access_denied(msg);
if (netreg->pending)
if (netreg->pending || netreg->pending_auto)
return __ofono_error_busy(msg);
if (netreg->driver->list_operators == NULL)
return __ofono_error_not_implemented(msg);
netreg->pending = dbus_message_ref(msg);
netreg->driver->list_operators(netreg, operator_list_callback, netreg);
netreg->pending_list = g_slist_append(netreg->pending_list,
dbus_message_ref(msg));
if (!netreg->pending_list->next)
netreg->driver->list_operators(netreg, operator_list_callback,
netreg);
return NULL;
}
@@ -1894,6 +1949,15 @@ static void netreg_remove(struct ofono_atom *atom)
if (netreg->driver != NULL && netreg->driver->remove != NULL)
netreg->driver->remove(netreg);
if (netreg->pending) {
__ofono_dbus_pending_reply(&netreg->pending,
__ofono_error_canceled(netreg->pending));
} else if (netreg->pending_auto) {
g_slist_free_full(netreg->pending_auto, network_reply_canceled);
} else if (netreg->pending_list) {
g_slist_free_full(netreg->pending_list, network_reply_canceled);
}
sim_eons_free(netreg->eons);
sim_spdi_free(netreg->spdi);

View File

@@ -1,265 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2013 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <errno.h>
#include <glib.h>
#include <gdbus.h>
#include <dbus/dbus.h>
#include "ofono.h"
#include "common.h"
#include "ofono/oemraw.h"
static GSList *g_drivers;
struct ofono_oem_raw {
struct ofono_atom *atom;
const struct ofono_oem_raw_driver *driver;
void *driver_data;
};
static void ofono_oem_raw_query_cb(const struct ofono_error *error,
const struct ofono_oem_raw_results *res, void *data)
{
char *ptr;
char byte;
int i;
DBusMessage *reply;
DBusMessageIter iter;
DBusMessageIter subiter;
struct ofono_oem_raw_request *req = data;
if (error && error->type == OFONO_ERROR_TYPE_NO_ERROR) {
reply = dbus_message_new_method_return(req->pending);
} else {
/*
* Log error messages in driver when completing a request,
* logging here provides no extra information.
*/
goto error;
}
dbus_message_iter_init_append(reply, &iter);
if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
"y", &subiter)) {
DBG("Failed to open a dbus iterator");
goto error;
}
ptr = (char *)res->data;
for (i = 0; i < res->length; i++) {
byte = ptr[i];
dbus_message_iter_append_basic(&subiter, DBUS_TYPE_BYTE,
&byte);
}
dbus_message_iter_close_container(&iter, &subiter);
goto end;
error:
reply = __ofono_error_failed(req->pending);
end:
__ofono_dbus_pending_reply(&req->pending, reply);
g_free(req);
return;
}
static DBusMessage *oem_raw_make_request(DBusConnection *conn,
DBusMessage *msg, void *data)
{
char *array; /* Byte array containing client request*/
int array_len; /* Length of request byte array */
DBusMessageIter iter;
DBusMessageIter subiter;
struct ofono_oem_raw_request *req;
struct ofono_oem_raw *raw;
raw = data;
req = 0;
if (raw && raw->driver->request == NULL)
return __ofono_error_not_implemented(msg);
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
goto error_arg;
if (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE) {
DBG("Ignoring request because dbus request element type=%c",
dbus_message_iter_get_element_type(&iter));
goto error_arg;
}
dbus_message_iter_recurse(&iter, &subiter);
dbus_message_iter_get_fixed_array(&subiter, &array, &array_len);
req = g_new0(struct ofono_oem_raw_request, 1);
req->data = array;
req->length = array_len;
/* Store msg to request struct to allow multiple parallel requests */
req->pending = dbus_message_ref(msg);
raw->driver->request(raw, req, ofono_oem_raw_query_cb, req);
return NULL;
error_arg:
DBG("DBus arg type=%c, msg signature: %s",
dbus_message_iter_get_arg_type(&iter),
dbus_message_get_signature(msg));
return __ofono_error_invalid_args(msg);
}
static const GDBusMethodTable oem_raw_methods[] = {
{ GDBUS_ASYNC_METHOD("Send",
GDBUS_ARGS({ "req", "ay" }),
GDBUS_ARGS({ "response", "ay"}),
oem_raw_make_request) },
{ }
};
static const GDBusSignalTable oem_raw_signals[] = {
{ }
};
static void oem_raw_dbus_unregister(struct ofono_atom *atom)
{
DBG("");
struct ofono_oem_raw *oemraw = __ofono_atom_get_data(atom);
const char *path = __ofono_atom_get_path(oemraw->atom);
DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = __ofono_atom_get_modem(oemraw->atom);
ofono_modem_remove_interface(modem, OFONO_OEM_RAW_INTERFACE);
if (!g_dbus_unregister_interface(conn, path, OFONO_OEM_RAW_INTERFACE))
ofono_error("Failed to unregister interface %s",
OFONO_OEM_RAW_INTERFACE);
}
void ofono_oem_raw_dbus_register(struct ofono_oem_raw *oemraw)
{
DBusConnection *conn;
DBG("");
conn = ofono_dbus_get_connection();
struct ofono_modem *modem = __ofono_atom_get_modem(oemraw->atom);
const char *path = __ofono_atom_get_path(oemraw->atom);
if (!g_dbus_register_interface(conn, path,
OFONO_OEM_RAW_INTERFACE,
oem_raw_methods,
oem_raw_signals,
NULL, oemraw, NULL)) {
ofono_error("Could not create interface %s",
OFONO_OEM_RAW_INTERFACE);
return;
}
ofono_modem_add_interface(modem, OFONO_OEM_RAW_INTERFACE);
__ofono_atom_register(oemraw->atom, oem_raw_dbus_unregister);
}
int ofono_oem_raw_driver_register(struct ofono_oem_raw_driver *driver)
{
if (driver->probe == NULL)
return -EINVAL;
g_drivers = g_slist_prepend(g_drivers, (void *) driver);
return 0;
}
void ofono_oem_raw_driver_unregister(struct ofono_oem_raw_driver *driver)
{
g_drivers = g_slist_remove(g_drivers, (void *) driver);
}
void ofono_oem_raw_remove(struct ofono_oem_raw *oemraw)
{
__ofono_atom_free(oemraw->atom);
}
void *ofono_oem_raw_get_data(struct ofono_oem_raw *raw)
{
return raw->driver_data;
}
void ofono_oem_raw_set_data(struct ofono_oem_raw *raw, void *cid)
{
raw->driver_data = cid;
}
static void oem_raw_remove(struct ofono_atom *atom)
{
struct ofono_oem_raw *oemraw = __ofono_atom_get_data(atom);
if (oemraw == NULL)
return;
if (oemraw->driver && oemraw->driver->remove)
oemraw->driver->remove(oemraw);
g_free(oemraw);
}
struct ofono_oem_raw *ofono_oem_raw_create(struct ofono_modem *modem,
unsigned int vendor,
const char *driver,
void *data)
{
struct ofono_oem_raw *oemraw = 0;
GSList *l;
if (driver == NULL)
return NULL;
oemraw = g_try_new0(struct ofono_oem_raw, 1);
if (oemraw == NULL)
return NULL;
oemraw->atom = __ofono_modem_add_atom(modem,
OFONO_ATOM_TYPE_OEM_RAW,
oem_raw_remove, oemraw);
for (l = g_drivers; l; l = l->next) {
const struct ofono_oem_raw_driver *drv = l->data;
if (g_strcmp0(drv->name, driver))
continue;
if (drv->probe(oemraw, vendor, data) < 0)
continue;
oemraw->driver = drv;
break;
}
return oemraw;
}

View File

@@ -152,7 +152,6 @@ enum ofono_atom_type {
OFONO_ATOM_TYPE_CDMA_SMS,
OFONO_ATOM_TYPE_CDMA_NETREG,
OFONO_ATOM_TYPE_HANDSFREE,
OFONO_ATOM_TYPE_OEM_RAW,
OFONO_ATOM_TYPE_SIRI,
};

View File

@@ -53,7 +53,7 @@ enum phonebook_number_type {
};
struct ofono_phonebook {
DBusMessage *pending;
GSList *pending;
int storage_index; /* go through all supported storage */
int flags;
GString *vcards; /* entries with vcard 3.0 format */
@@ -431,9 +431,24 @@ static void export_phonebook_cb(const struct ofono_error *error, void *data)
return;
}
static void phonebook_reply(gpointer data, gpointer user_data)
{
DBusMessage *msg = data;
struct ofono_phonebook *phonebook = user_data;
DBusMessage *reply = generate_export_entries_reply(phonebook, msg);
__ofono_dbus_pending_reply(&msg, reply);
}
static void phonebook_cancel(gpointer data)
{
DBusMessage *msg = data;
__ofono_dbus_pending_reply(&msg, __ofono_error_canceled(msg));
}
static void export_phonebook(struct ofono_phonebook *phonebook)
{
DBusMessage *reply;
const char *pb = storage_support[phonebook->storage_index];
if (pb) {
@@ -442,13 +457,9 @@ static void export_phonebook(struct ofono_phonebook *phonebook)
return;
}
reply = generate_export_entries_reply(phonebook, phonebook->pending);
if (reply == NULL) {
dbus_message_unref(phonebook->pending);
return;
}
__ofono_dbus_pending_reply(&phonebook->pending, reply);
g_slist_foreach(phonebook->pending, phonebook_reply, phonebook);
g_slist_free(phonebook->pending);
phonebook->pending = NULL;
phonebook->flags |= PHONEBOOK_FLAG_CACHED;
}
@@ -458,23 +469,22 @@ static DBusMessage *import_entries(DBusConnection *conn, DBusMessage *msg,
struct ofono_phonebook *phonebook = data;
DBusMessage *reply;
if (phonebook->pending) {
reply = __ofono_error_busy(phonebook->pending);
g_dbus_send_message(conn, reply);
return NULL;
}
if (phonebook->flags & PHONEBOOK_FLAG_CACHED) {
reply = generate_export_entries_reply(phonebook, msg);
g_dbus_send_message(conn, reply);
return NULL;
}
g_string_set_size(phonebook->vcards, 0);
phonebook->storage_index = 0;
phonebook->pending = dbus_message_ref(msg);
export_phonebook(phonebook);
if (phonebook->pending) {
phonebook->pending = g_slist_append(phonebook->pending,
dbus_message_ref(msg));
} else {
phonebook->pending = g_slist_append(NULL,
dbus_message_ref(msg));
g_string_set_size(phonebook->vcards, 0);
phonebook->storage_index = 0;
export_phonebook(phonebook);
}
return NULL;
}
@@ -516,6 +526,11 @@ static void phonebook_unregister(struct ofono_atom *atom)
DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = __ofono_atom_get_modem(pb->atom);
if (pb->pending) {
g_slist_free_full(pb->pending, phonebook_cancel);
pb->pending = NULL;
}
ofono_modem_remove_interface(modem, OFONO_PHONEBOOK_INTERFACE);
g_dbus_unregister_interface(conn, path, OFONO_PHONEBOOK_INTERFACE);
}

View File

@@ -56,7 +56,7 @@ struct ofono_radio_settings {
struct ofono_atom *atom;
};
static const char *radio_access_mode_to_string(enum ofono_radio_access_mode m)
const char *ofono_radio_access_mode_to_string(enum ofono_radio_access_mode m)
{
switch (m) {
case OFONO_RADIO_ACCESS_MODE_ANY:
@@ -72,11 +72,13 @@ static const char *radio_access_mode_to_string(enum ofono_radio_access_mode m)
}
}
static gboolean radio_access_mode_from_string(const char *str,
ofono_bool_t ofono_radio_access_mode_from_string(const char *str,
enum ofono_radio_access_mode *mode)
{
if (g_str_equal(str, "any")) {
if (!str) {
return FALSE;
} else if (g_str_equal(str, "any")) {
*mode = OFONO_RADIO_ACCESS_MODE_ANY;
return TRUE;
} else if (g_str_equal(str, "gsm")) {
@@ -192,7 +194,7 @@ static DBusMessage *radio_get_properties_reply(DBusMessage *msg,
DBusMessageIter iter;
DBusMessageIter dict;
const char *mode = radio_access_mode_to_string(rs->mode);
const char *mode = ofono_radio_access_mode_to_string(rs->mode);
reply = dbus_message_new_method_return(msg);
if (reply == NULL)
@@ -237,7 +239,7 @@ static DBusMessage *radio_get_properties_reply(DBusMessage *msg,
if (!(rs->available_rats & tech))
continue;
rats[n++] = radio_access_mode_to_string(tech);
rats[n++] = ofono_radio_access_mode_to_string(tech);
}
rats[n] = NULL;
@@ -358,7 +360,7 @@ static void radio_set_rat_mode(struct ofono_radio_settings *rs,
rs->mode = mode;
path = __ofono_atom_get_path(rs->atom);
str_mode = radio_access_mode_to_string(rs->mode);
str_mode = ofono_radio_access_mode_to_string(rs->mode);
ofono_dbus_signal_property_changed(conn, path,
OFONO_RADIO_SETTINGS_INTERFACE,
@@ -580,7 +582,7 @@ static DBusMessage *radio_set_property(DBusConnection *conn, DBusMessage *msg,
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &value);
if (radio_access_mode_from_string(value, &mode) == FALSE)
if (ofono_radio_access_mode_from_string(value, &mode) == FALSE)
return __ofono_error_invalid_args(msg);
if (rs->mode == mode)
@@ -815,3 +817,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

@@ -53,6 +53,7 @@ struct ofono_sim {
/* Contents of the SIM file system, in rough initialization order */
char *iccid;
struct ofono_watchlist *iccid_watches;
char **language_prefs;
unsigned char *efli;
@@ -80,6 +81,7 @@ struct ofono_sim {
char *imsi;
char mcc[OFONO_MAX_MCC_LENGTH + 1];
char mnc[OFONO_MAX_MNC_LENGTH + 1];
struct ofono_watchlist *imsi_watches;
GSList *own_numbers;
GSList *new_numbers;
@@ -340,6 +342,94 @@ static void call_state_watches(struct ofono_sim *sim)
}
}
static unsigned int add_watch_item(struct ofono_watchlist *watchlist,
void *notify, void *notify_data,
ofono_destroy_func destroy)
{
struct ofono_watchlist_item *item;
item = g_new0(struct ofono_watchlist_item, 1);
item->notify = notify;
item->notify_data = notify_data;
item->destroy = destroy;
return __ofono_watchlist_add_item(watchlist, item);
}
static void iccid_watch_cb(gpointer data, gpointer user_data)
{
struct ofono_watchlist_item *item = data;
struct ofono_sim *sim = user_data;
ofono_sim_iccid_event_cb_t cb = item->notify;
cb(sim->iccid, item->notify_data);
}
static inline void iccid_watches_notify(struct ofono_sim *sim)
{
g_slist_foreach(sim->iccid_watches->items, iccid_watch_cb, sim);
}
unsigned int ofono_sim_add_iccid_watch(struct ofono_sim *sim,
ofono_sim_iccid_event_cb_t cb, void *data,
ofono_destroy_func destroy)
{
unsigned int watch_id;
DBG("%p", sim);
if (sim == NULL)
return 0;
watch_id = add_watch_item(sim->iccid_watches, cb, data, destroy);
if (sim->iccid)
cb(sim->iccid, data);
return watch_id;
}
void ofono_sim_remove_iccid_watch(struct ofono_sim *sim, unsigned int id)
{
__ofono_watchlist_remove_item(sim->iccid_watches, id);
}
static void imsi_watch_cb(gpointer data, gpointer user_data)
{
struct ofono_watchlist_item *item = data;
struct ofono_sim *sim = user_data;
ofono_sim_imsi_event_cb_t cb = item->notify;
cb(sim->imsi, item->notify_data);
}
static inline void imsi_watches_notify(struct ofono_sim *sim)
{
g_slist_foreach(sim->imsi_watches->items, imsi_watch_cb, sim);
}
unsigned int ofono_sim_add_imsi_watch(struct ofono_sim *sim,
ofono_sim_imsi_event_cb_t cb, void *data,
ofono_destroy_func destroy)
{
unsigned int watch_id;
DBG("%p", sim);
if (sim == NULL)
return 0;
watch_id = add_watch_item(sim->imsi_watches, cb, data, destroy);
if (sim->imsi)
cb(sim->imsi, data);
return watch_id;
}
void ofono_sim_remove_imsi_watch(struct ofono_sim *sim, unsigned int id)
{
__ofono_watchlist_remove_item(sim->imsi_watches, id);
}
static DBusMessage *sim_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -380,6 +470,10 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
ofono_dbus_dict_append(&dict, "SubscriberIdentity",
DBUS_TYPE_STRING, &sim->imsi);
if (sim->spn)
ofono_dbus_dict_append(&dict, "ServiceProviderName",
DBUS_TYPE_STRING, &sim->spn);
fdn = sim->fixed_dialing;
ofono_dbus_dict_append(&dict, "FixedDialing", DBUS_TYPE_BOOLEAN, &fdn);
@@ -1483,6 +1577,7 @@ static void sim_imsi_obtained(struct ofono_sim *sim, const char *imsi)
DBUS_TYPE_STRING, &str);
}
imsi_watches_notify(sim);
sim_set_ready(sim);
}
@@ -1615,7 +1710,7 @@ static gboolean check_bdn_status(struct ofono_sim *sim)
if (sim_sst_is_active(sim->efsst, sim->efsst_length,
SIM_SST_SERVICE_BDN)) {
sim_fs_read_info(sim->context, SIM_EFBDN_FILEID,
OFONO_SIM_FILE_STRUCTURE_FIXED,
OFONO_SIM_FILE_STRUCTURE_FIXED, NULL, 0,
sim_efbdn_info_read_cb, sim);
return TRUE;
}
@@ -1669,7 +1764,7 @@ static void sim_efsst_read_cb(int ok, int length, int record,
if (sim_sst_is_active(sim->efsst, sim->efsst_length,
SIM_SST_SERVICE_FDN)) {
sim_fs_read_info(sim->context, SIM_EFADN_FILEID,
OFONO_SIM_FILE_STRUCTURE_FIXED,
OFONO_SIM_FILE_STRUCTURE_FIXED, NULL, 0,
sim_efadn_info_read_cb, sim);
return;
}
@@ -1856,6 +1951,7 @@ static void sim_initialize_after_pin(struct ofono_sim *sim)
{
sim->context = ofono_sim_context_create(sim);
sim->spn_watches = __ofono_watchlist_new(g_free);
sim->imsi_watches = __ofono_watchlist_new(g_free);
ofono_sim_read(sim->context, SIM_EFPHASE_FILEID,
OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
@@ -2085,6 +2181,7 @@ static void sim_iccid_read_cb(int ok, int length, int record,
"CardIdentifier",
DBUS_TYPE_STRING,
&sim->iccid);
iccid_watches_notify(sim);
}
static void sim_iccid_changed(int id, void *userdata)
@@ -2217,6 +2314,34 @@ int ofono_sim_read(struct ofono_sim_context *context, int id,
return sim_fs_read(context, id, expected_type, 0, 0, NULL, 0, cb, data);
}
int ofono_sim_read_path(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
const unsigned char *path, unsigned int path_len,
ofono_sim_file_read_cb_t cb, void *data)
{
return sim_fs_read(context, id, expected_type, 0, 0,
path, path_len, cb, data);
}
int ofono_sim_read_info(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
const unsigned char *path, unsigned int pth_len,
ofono_sim_read_info_cb_t cb, void *data)
{
return sim_fs_read_info(context, id, expected_type, path, pth_len,
cb, data);
}
int ofono_sim_read_record(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
int record, int record_length,
const unsigned char *path, unsigned int pth_len,
ofono_sim_file_read_cb_t cb, void *data)
{
return sim_fs_read_record(context, id, expected_type, record,
record_length, path, pth_len, cb, data);
}
int ofono_sim_write(struct ofono_sim_context *context, int id,
ofono_sim_file_write_cb_t cb,
enum ofono_sim_file_structure structure, int record,
@@ -2467,6 +2592,11 @@ static void sim_free_main_state(struct ofono_sim *sim)
sim_spn_close(sim);
if (sim->imsi_watches) {
__ofono_watchlist_free(sim->imsi_watches);
sim->imsi_watches = NULL;
}
if (sim->context) {
ofono_sim_context_free(sim->context);
sim->context = NULL;
@@ -2570,6 +2700,9 @@ static inline void spn_watches_notify(struct ofono_sim *sim)
static void sim_spn_set(struct ofono_sim *sim, const void *data, int length,
const unsigned char *dc)
{
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = __ofono_atom_get_path(sim->atom);
g_free(sim->spn);
sim->spn = NULL;
@@ -2611,6 +2744,12 @@ static void sim_spn_set(struct ofono_sim *sim, const void *data, int length,
sim->spn_dc = g_memdup(dc, 1);
notify:
if (sim->spn)
ofono_dbus_signal_property_changed(conn, path,
OFONO_SIM_MANAGER_INTERFACE,
"ServiceProviderName",
DBUS_TYPE_STRING, &sim->spn);
spn_watches_notify(sim);
}
@@ -2885,6 +3024,9 @@ static void sim_unregister(struct ofono_atom *atom)
__ofono_modem_remove_atom_watch(modem, sim->hfp_watch);
__ofono_watchlist_free(sim->iccid_watches);
sim->iccid_watches = NULL;
__ofono_watchlist_free(sim->state_watches);
sim->state_watches = NULL;
@@ -3017,6 +3159,7 @@ void ofono_sim_register(struct ofono_sim *sim)
ofono_modem_add_interface(modem, OFONO_SIM_MANAGER_INTERFACE);
sim->state_watches = __ofono_watchlist_new(g_free);
sim->iccid_watches = __ofono_watchlist_new(g_free);
sim->simfs = sim_fs_new(sim, sim->driver);
__ofono_atom_register(sim->atom, sim_unregister);

View File

@@ -264,7 +264,7 @@ static void sim_fs_op_error(struct sim_fs *fs)
}
if (op->info_only == TRUE)
((sim_fs_read_info_cb_t) op->cb)
((ofono_sim_read_info_cb_t) op->cb)
(0, 0, 0, 0, op->userdata);
else if (op->is_read == TRUE)
((ofono_sim_file_read_cb_t) op->cb)
@@ -335,6 +335,27 @@ static void sim_fs_op_write_cb(const struct ofono_error *error, void *data)
sim_fs_end_current(fs);
}
static void sim_fs_op_read_record_cb(const struct ofono_error *error,
const unsigned char *sdata, int length,
void *data)
{
struct sim_fs *fs = data;
struct sim_fs_op *op = g_queue_peek_head(fs->op_q);
ofono_sim_file_read_cb_t cb = op->cb;
if (cb == NULL) {
sim_fs_end_current(fs);
return;
}
if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
cb(1, -1, op->current, sdata, length, op->userdata);
else
cb(0, -1, op->current, NULL, 0, op->userdata);
sim_fs_end_current(fs);
}
static void sim_fs_op_read_block_cb(const struct ofono_error *error,
const unsigned char *data, int len,
void *user)
@@ -565,7 +586,8 @@ static gboolean sim_fs_op_read_record(gpointer user)
driver->read_file_linear(fs->sim, op->id, op->current,
op->record_length,
NULL, 0,
op->path_len ? op->path : NULL,
op->path_len,
sim_fs_op_retrieve_cb, fs);
break;
case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
@@ -576,7 +598,8 @@ static gboolean sim_fs_op_read_record(gpointer user)
driver->read_file_cyclic(fs->sim, op->id, op->current,
op->record_length,
NULL, 0,
op->path_len ? op->path : NULL,
op->path_len,
sim_fs_op_retrieve_cb, fs);
break;
default:
@@ -700,7 +723,7 @@ static void sim_fs_op_info_cb(const struct ofono_error *error, int length,
* It's an info-only request, so there is no need to request
* actual contents of the EF. Just return the EF-info.
*/
sim_fs_read_info_cb_t cb = op->cb;
ofono_sim_read_info_cb_t cb = op->cb;
cb(1, file_status, op->length,
op->record_length, op->userdata);
@@ -778,7 +801,7 @@ static gboolean sim_fs_op_check_cached(struct sim_fs *fs)
* It's an info-only request, so there is no need to request
* actual contents of the EF. Just return the EF-info.
*/
sim_fs_read_info_cb_t cb = op->cb;
ofono_sim_read_info_cb_t cb = op->cb;
cb(1, file_status, op->length,
op->record_length, op->userdata);
@@ -820,7 +843,28 @@ static gboolean sim_fs_op_next(gpointer user_data)
return FALSE;
}
if (op->is_read == TRUE) {
if (op->is_read == TRUE && op->current > 0) {
switch (op->structure) {
case OFONO_SIM_FILE_STRUCTURE_FIXED:
driver->read_file_linear(fs->sim, op->id,
op->current, op->record_length,
op->path_len ? op->path : NULL,
op->path_len,
sim_fs_op_read_record_cb, fs);
break;
case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
driver->read_file_cyclic(fs->sim, op->id,
op->current, op->record_length,
op->path_len ? op->path : NULL,
op->path_len,
sim_fs_op_read_record_cb, fs);
break;
case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
default:
ofono_error("Wrong file structure for reading record");
break;
}
} else if (op->is_read == TRUE) {
if (sim_fs_op_check_cached(fs))
return FALSE;
@@ -859,7 +903,8 @@ static gboolean sim_fs_op_next(gpointer user_data)
int sim_fs_read_info(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
sim_fs_read_info_cb_t cb, void *data)
const unsigned char *path, unsigned int pth_len,
ofono_sim_read_info_cb_t cb, void *data)
{
struct sim_fs *fs = context->fs;
struct sim_fs_op *op;
@@ -887,6 +932,8 @@ int sim_fs_read_info(struct ofono_sim_context *context, int id,
op->is_read = TRUE;
op->info_only = TRUE;
op->context = context;
memcpy(op->path, path, pth_len);
op->path_len = pth_len;
g_queue_push_tail(fs->op_q, op);
@@ -943,6 +990,59 @@ int sim_fs_read(struct ofono_sim_context *context, int id,
return 0;
}
int sim_fs_read_record(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
int record, int record_length,
const unsigned char *path, unsigned int path_len,
ofono_sim_file_read_cb_t cb, void *data)
{
struct sim_fs *fs = context->fs;
struct sim_fs_op *op;
if (cb == NULL)
return -EINVAL;
if (fs->driver == NULL)
return -EINVAL;
if (record < 1)
return -EINVAL;
if ((expected_type == OFONO_SIM_FILE_STRUCTURE_FIXED &&
fs->driver->read_file_linear == NULL) ||
(expected_type == OFONO_SIM_FILE_STRUCTURE_CYCLIC &&
fs->driver->read_file_cyclic == NULL)) {
cb(0, 0, 0, NULL, 0, data);
return -ENOSYS;
}
if (fs->op_q == NULL)
fs->op_q = g_queue_new();
op = g_try_new0(struct sim_fs_op, 1);
if (op == NULL)
return -ENOMEM;
op->id = id;
op->structure = expected_type;
op->cb = cb;
op->userdata = data;
op->is_read = TRUE;
op->info_only = FALSE;
op->context = context;
op->record_length = record_length;
op->current = record;
memcpy(op->path, path, path_len);
op->path_len = path_len;
g_queue_push_tail(fs->op_q, op);
if (g_queue_get_length(fs->op_q) == 1)
fs->op_source = g_idle_add(sim_fs_op_next, fs);
return 0;
}
int sim_fs_write(struct ofono_sim_context *context, int id,
ofono_sim_file_write_cb_t cb,
enum ofono_sim_file_structure structure, int record,

View File

@@ -21,10 +21,6 @@
struct sim_fs;
typedef void (*sim_fs_read_info_cb_t)(int ok, unsigned char file_status,
int total_length, int record_length,
void *userdata);
struct sim_fs *sim_fs_new(struct ofono_sim *sim,
const struct ofono_sim_driver *driver);
struct ofono_sim_context *sim_fs_context_new(struct sim_fs *fs);
@@ -45,9 +41,16 @@ int sim_fs_read(struct ofono_sim_context *context, int id,
const unsigned char *path, unsigned int len,
ofono_sim_file_read_cb_t cb, void *data);
int sim_fs_read_record(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
int record, int record_length,
const unsigned char *path, unsigned int len,
ofono_sim_file_read_cb_t cb, void *data);
int sim_fs_read_info(struct ofono_sim_context *context, int id,
enum ofono_sim_file_structure expected_type,
sim_fs_read_info_cb_t cb, void *data);
const unsigned char *path, unsigned int pth_len,
ofono_sim_read_info_cb_t cb, void *data);
void sim_fs_check_version(struct sim_fs *fs);

View File

@@ -2780,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,

View File

@@ -41,6 +41,9 @@ unsigned int __ofono_watchlist_add_item(struct ofono_watchlist *watchlist,
{
item->id = ++watchlist->next_id;
if (item->id == 0)
item->id = ++watchlist->next_id;
watchlist->items = g_slist_prepend(watchlist->items, item);
return item->id;

View File

@@ -1,16 +1,17 @@
Name: ofono
Summary: Open Source Telephony
Version: 1.16
Version: 1.17
Release: 1
Group: Communications/Connectivity Adaptation
License: GPLv2
URL: http://ofono.org
Source0: http://www.kernel.org/pub/linux/network/ofono/ofono-%{version}.tar.xz
URL: https://git.merproject.org/mer-core/ofono
Source: %{name}-%{version}.tar.bz2
Requires: dbus
Requires: systemd
Requires: ofono-configs
Requires: libgrilio >= 1.0.6
Requires: libgrilio >= 1.0.10
Requires: libglibutil >= 1.0.10
Requires(preun): systemd
Requires(post): systemd
Requires(postun): systemd
@@ -20,8 +21,9 @@ BuildRequires: pkgconfig(libudev) >= 145
BuildRequires: pkgconfig(bluez) >= 4.85
BuildRequires: pkgconfig(mobile-broadband-provider-info)
BuildRequires: pkgconfig(libwspcodec) >= 2.0
BuildRequires: pkgconfig(libglibutil)
BuildRequires: pkgconfig(libgrilio) >= 1.0.6
BuildRequires: pkgconfig(libgrilio) >= 1.0.10
BuildRequires: pkgconfig(libglibutil) >= 1.0.10
BuildRequires: pkgconfig(libdbuslogserver-dbus)
BuildRequires: libtool
BuildRequires: automake
BuildRequires: autoconf
@@ -68,7 +70,7 @@ autoreconf --force --install
%configure --disable-static \
--enable-test \
--enable-logcontrol \
--enable-debuglog \
--enable-jolla-rilmodem \
--with-systemdunitdir="/%{_lib}/systemd/system"
@@ -85,6 +87,7 @@ rm -rf %{buildroot}
mkdir -p %{buildroot}/%{_sysconfdir}/ofono/push_forwarder.d
mkdir -p %{buildroot}/%{_lib}/systemd/system/network.target.wants
mkdir -p %{buildroot}/var/lib/ofono
ln -s ../ofono.service %{buildroot}/%{_lib}/systemd/system/network.target.wants/ofono.service
%preun