Compare commits

...

793 Commits

Author SHA1 Message Date
Slava Monich
40ce8f7185 Merge branch 'sim_write' into 'master'
SIM write support

If it's done right, quite a few things (those that have to do with
writing stuff to SIM card) should start working.

See merge request !76
2016-07-25 09:19:54 +00:00
Slava Monich
f68585a784 [ril] Implemented SIM write I/O support. Fixes MER#1199 2016-07-25 12:15:06 +03:00
Slava Monich
16105b8ace [ril] Cleaned up call forwarding code. JB#20921 2016-07-25 12:13:22 +03:00
Slava Monich
c52471132a Merge branch 'pin_retries' into 'master'
Query number of retries left with empty pin

This works with some Qualcomm RILs. Those RILs that don't support
it will fail this request with no harm done. In case if it turns
out to be harmful with some RILs, it can be turned off with
emptyPinQuery=false in ril_subscription.conf

See merge request !75
2016-07-15 14:07:17 +00:00
Slava Monich
a8e7b86733 Merge branch 'band-mode' into 'master'
Query available band modes at startup

With some RIL implementations, RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE
causes some magic Android properties to appear. Otherwise it's
harmless and fairly useless.

See merge request !72
2016-07-15 14:07:00 +00:00
Slava Monich
8829682fad [ril] Query number of retries left with empty pin. MER#1089
This works with some Qualcomm RILs. Those RILs that don't support it
will fail this request with no harm done.

In case if turns out to be harmful with some RILs, it can be turned off
with emptyPinQuery=false in ril_subscription.conf
2016-07-07 11:37:54 +03:00
Slava Monich
246e30d1a5 Merge branch 'locked_pins' into 'master'
Implement SC facility lock query

Otherwise `org.ofono.SimManager` `LockedPins` state gets lost after
ofono is restarted. A few cherry-picks from upstream were required.

See merge request !73
2016-07-07 08:34:25 +00:00
Slava Monich
83267e1fa5 Merge branch 'ril_phonebook' into 'master'
Free phonebook state if export hasn't finished

Fixes memory leaks like these:

==21616== 56 (8 direct, 48 indirect) bytes in 1 blocks are definitely lost in loss record 437 of 520
==21616==    at 0x483F380: malloc (vg_replace_malloc.c:296)
==21616==    by 0x4AEB26F: g_malloc (gmem.c:94)
==21616==    by 0x4B010D9: g_slice_alloc (gslice.c:1025)
==21616==    by 0x4B01FC7: g_slist_append (gslist.c:213)
==21616==    by 0x32553: start_sim_app_read (ril_phonebook.c:860)
==21616==    by 0x3276B: pb_reference_data_cb (ril_phonebook.c:903)
==21616==    by 0x153EB3: sim_fs_op_error (simfs.c:271)
==21616==    by 0x1552BB: sim_fs_op_info_cb (simfs.c:682)
==21616==    by 0x3BBA3: ril_sim_file_info_cb (ril_sim.c:358)
==21616==    by 0x489F679: grilio_channel_handle_packet (grilio_channel.c:711)
==21616==    by 0x489F679: grilio_channel_read (grilio_channel.c:811)
==21616==    by 0x489F679: grilio_channel_read_callback (grilio_channel.c:824)
==21616==    by 0x4AE621B: g_main_dispatch (gmain.c:3154)
==21616==    by 0x4AE621B: g_main_context_dispatch (gmain.c:3769)
==21616==    by 0x4AE64C9: g_main_context_iterate.isra.4 (gmain.c:3840)
==21616== 
==21616== 366 (28 direct, 338 indirect) bytes in 1 blocks are definitely lost in loss record 503 of 520
==21616==    at 0x483F380: malloc (vg_replace_malloc.c:296)
==21616==    by 0x4AEB26F: g_malloc (gmem.c:94)
==21616==    by 0x4B010D9: g_slice_alloc (gslice.c:1025)
==21616==    by 0x4B1076B: g_tree_new_full (gtree.c:217)
==21616==    by 0x324CF: start_sim_app_read (ril_phonebook.c:846)
==21616==    by 0x3276B: pb_reference_data_cb (ril_phonebook.c:903)
==21616==    by 0x153EB3: sim_fs_op_error (simfs.c:271)
==21616==    by 0x1552BB: sim_fs_op_info_cb (simfs.c:682)
==21616==    by 0x3BBA3: ril_sim_file_info_cb (ril_sim.c:358)
==21616==    by 0x489F679: grilio_channel_handle_packet (grilio_channel.c:711)
==21616==    by 0x489F679: grilio_channel_read (grilio_channel.c:811)
==21616==    by 0x489F679: grilio_channel_read_callback (grilio_channel.c:824)
==21616==    by 0x4AE621B: g_main_dispatch (gmain.c:3154)
==21616==    by 0x4AE621B: g_main_context_dispatch (gmain.c:3769)
==21616==    by 0x4AE64C9: g_main_context_iterate.isra.4 (gmain.c:3840)

Those occur if SIM card is removed before phonebook export is finished

See merge request !74
2016-07-07 08:33:47 +00:00
Slava Monich
e1ab11ad25 Merge branch 'configs-mer' into 'master'
configs-mer doesn't need to require ofono

The dependency goes the other way around.

See merge request !71
2016-07-07 08:32:36 +00:00
Slava Monich
a9193282d5 [ril] Fixed another memory leak in RIL phonebook. Fixes to MER#1615 2016-07-07 00:11:27 +03:00
Slava Monich
f80bb5c5bb [ril] Implement facility lock query. Fixes MER#1614 2016-07-06 19:27:34 +03:00
Slava Monich
66eb87777f sim: Query the status of SC facility lock 2016-07-06 19:27:00 +03:00
Denis Kenzior
e5291006fd include: Remove unused query_locked method 2016-07-06 19:27:00 +03:00
Denis Kenzior
c609d7cc07 isi: Change query_locked to query_facility_lock 2016-07-06 19:27:00 +03:00
Denis Kenzior
0de562b019 isimodem: Remove unimplemented query_locked method 2016-07-06 19:27:00 +03:00
Denis Kenzior
60b11f712c atmodem: Change query_locked to query_facility_lock 2016-07-06 19:27:00 +03:00
Samrat Guha Niyogi
80d347b964 sim: Query the status of PS and PN facility locks 2016-07-06 19:27:00 +03:00
Samrat Guha Niyogi
97abd10984 include: Add query_facility_lock method 2016-07-06 19:27:00 +03:00
Slava Monich
5201fc0183 [ril] Free phonebook state if export hasn't finished. Contributes to MER#1615 2016-07-06 12:37:21 +03:00
Slava Monich
14e4ef8e07 [ril] Query available band modes at startup. Contributes to JB#35461 2016-07-04 23:21:23 +03:00
Slava Monich
22bc6d526e [rpm] configs-mer doesn't need to require ofono
The dependency goes the other way around.
2016-07-04 21:20:28 +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
Slava Monich
c5b3357000 Merge branch 'merge-1.17' into 'master'
Upgrade to ofono 1.17

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Requires libgrilio 1.0.4 (already merged)

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

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

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

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

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

This commit introduces the list of pending GetProperties requests
which all get completed after the initial query is done.
2015-12-09 14:03:24 +03:00
Slava Monich
26398c769f Merge branch 'PrefixLength' into 'master'
Provide PrefixLength for IPv6 address

`PrefixLength` property was absent from ConnectionContext IPv6.Settings even if it's provided by RIL.

See merge request !12
2015-12-02 15:33:27 +00:00
Slava Monich
60c53428f0 [ril] Provide PrefixLength for IPv6 address. Contributes to JB#31859 2015-12-02 15:05:21 +02:00
Slava Monich
90824a8906 Merge branch 'jb33531' into 'master'
Queue org.ofono.MessageManager.GetProperties requests while waiting for sca_query

Just after the modem is added and `org.ofono.MessageManager` interface is registered, ofono receives a bunch of `GetProperties` calls for this interface. The first one would wait for `driver->sca_query` completion and all others would fail until `driver->sca_query` completes. I guess it was expected that clients would retry the call later but in practice pretty much all clients treat any D-Bus error as a permanent failure.

This commit introduces the list of pending `GetProperties` requests which all get completed when `driver->sca_query` is done.

See merge request !11
2015-11-30 14:16:47 +00:00
Slava Monich
b85b8f0019 [ofono] sms: Queue GetProperties requests while waiting for sca_query. Fixes JB#33531
Just after the modem is added and org.ofono.MessageManager interface
is registered, ofono receives a bunch of GetProperties calls for this
interface. The first one would wait for driver->sca_query completion
and all others would fail until driver->sca_query completes.

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

This commit introduces the list of pending GetProperties requests
which all get completed when driver->sca_query is done.
2015-11-30 16:11:54 +02:00
Slava Monich
29069fd152 Merge branch 'imei' into 'master'
Add GetIMEI method to ModemManager

This allows to query IMEI of all available modems without having to register them with ofono.

See merge request !10
2015-11-13 16:09:28 +00:00
Slava Monich
8e4e88e4fc [ril] Added GetIMEI method to ModemManager. Contributes to JB#33484
This allows to query IMEI of all available modems without having
to register them with ofono.
2015-11-12 17:59:05 +02:00
Slava Monich
40f148c134 [ril] Fixed memory leak on ofono_modem_register() failure 2015-11-12 17:51:35 +02:00
Slava Monich
730d5ff9b5 [ofono] modem: Destroy modem->properties in ofono_modem_remove()
Since it's created in ofono_modem_create(), it has to be destroyed
in ofono_modem_remove() to avoid memory leaks if ofono_modem_register()
fails.
2015-11-12 17:49:13 +02:00
Slava Monich
c6000fd909 Merge branch 'jb33441' into 'master'
Fix double free on self-deactivation of GPRS context



See merge request !9
2015-11-12 08:12:01 +00:00
Slava Monich
f2edab4ed8 Merge branch 'jb33265' into 'master'
Add GetPresentSims to ModemManager interface

Only a simple boolean (presence/absence) is reported. `PresentSimsChanged` signal is emitted when SIM is inserted or removed (if RIL supports it).

See merge request !8
2015-11-12 08:11:38 +00:00
Slava Monich
9915ccb3ba [ril] Fixed double free on self-deactivation of GPRS context. Fixes JB#33441 2015-11-11 19:20:24 +02:00
Slava Monich
b5be8420ab [ril] Add GetPresentSims to ModemManager interface. Contributes to JB#33265
Only a simple boolean (presence/absence) is reported. PresentSimsChanged
signal is emitted when SIM is inserted or removed (if RIL supports it).
2015-11-11 17:14:32 +02:00
Slava Monich
5498e22839 Merge branch 'jb33299' into 'master'
Fix manual operator selection for L500D

Seems to work on both Jolla1 and L500D

See merge request !7
2015-11-10 09:43:10 +00:00
Slava Monich
802d351ab0 Merge branch 'mer1394' into 'master'
Fix memory leaks

Memory was leaking every time a new SIM is inserted or "Reset to default" is done from AP settings page. Also refactored `provision_normalize_apn_list()` to eliminate duplicate code and clearly separate AP selection criteria into the sorting callback function.

See merge request !6
2015-11-10 09:42:52 +00:00
Slava Monich
3d62d57d20 [ril] Append +0 to MCCMNC in network selection request. Fixes JB#33299
Some RILs report MCCMNC in MCCMNC+TECH format and seem to expect it
in a similar way in SET_NETWORK_SELECTION_MANUAL request. Older RILs
don't require it but don't have a problem with that sort of syntax
either, at least one particular QCRIL vesion 6 that I tried. So the
solution seems to be quite portable.
2015-11-09 16:29:12 +02:00
Slava Monich
3b1b272967 [ril] Eliminated unnecessary debug print 2015-11-09 16:28:44 +02:00
Slava Monich
5e2a7afabd [ril] Fixed conversion of RIL to ofono registration status 2015-11-09 16:25:14 +02:00
Slava Monich
f7fa1c81f3 [provision] Fixed memory leak. Contributes to MER#1394
According to valgrind:

543 (8 direct, 535 indirect) bytes in 1 blocks are definitely lost in loss record 413 of 428
   at 0x483F380: malloc (vg_replace_malloc.c:296)
   by 0x4AB6083: g_malloc (gmem.c:104)
   by 0x4ACC9B5: g_slice_alloc (gslice.c:1016)
   by 0x4ACD8A3: g_slist_append (gslist.c:224)
   by 0xCE6BF: gsm_end (mbpi.c:423)
   by 0x4AB470D: g_markup_parse_context_parse (gmarkup.c:1602)
   by 0xCEE03: mbpi_parse (mbpi.c:646)
   by 0xCEEF3: mbpi_lookup_apn (mbpi.c:669)
   by 0xCF453: provision_get_settings (provision.c:184)
   by 0x145E87: __ofono_gprs_provision_get_settings (gprs-provision.c:68)
   by 0x12A983: provision_contexts (gprs.c:3327)
   by 0x12AD1B: spn_read_cb (gprs.c:3413)
2015-11-04 16:41:44 +03:00
Slava Monich
62a0b3518b [provision] Fixed memory leak. Contributes to MER#1394
According to valgrind:

14 bytes in 2 blocks are definitely lost in loss record 155 of 428
   at 0x483F380: malloc (vg_replace_malloc.c:296)
   by 0x4AB6083: g_malloc (gmem.c:104)
   by 0x4ACDAA9: g_strdup (gstrfuncs.c:364)
   by 0xCE383: apn_handler (mbpi.c:329)
   by 0xCE5B3: gsm_start (mbpi.c:386)
   by 0x4AB333B: emit_start_element (gmarkup.c:1029)
   by 0x4AB4685: g_markup_parse_context_parse (gmarkup.c:1366)
   by 0xCEE03: mbpi_parse (mbpi.c:646)
   by 0xCEEF3: mbpi_lookup_apn (mbpi.c:669)
   by 0xCF453: provision_get_settings (provision.c:184)
   by 0x145E87: __ofono_gprs_provision_get_settings (gprs-provision.c:68)
   by 0x12A983: provision_contexts (gprs.c:3327)
2015-11-04 10:58:34 +03:00
Slava Monich
d7cbedc0e9 Merge branch 'jb32969' into 'master'
Don't rely on DATA_CALL_LIST_CHANGED too much

Some RILs don't send `RIL_UNSOL_DATA_CALL_LIST_CHANGED` event after data call gets deactivated, only after activation. Some RILs send it in either case.

Ofono RIL plugin should consider data call disconnected after either `RIL_REQUEST_DEACTIVATE_DATA_CALL` successfully completes or data call disappears from the list reported by `RIL_UNSOL_DATA_CALL_LIST_CHANGED`, whichever happens first. That would work with both kinds of RILs.

See merge request !5
2015-11-04 07:41:21 +00:00
Slava Monich
1e75448127 Merge branch 'addremove' into 'master'
Always fire ModemRemoved first then ModemAdded

When switching from `/ril_1` to `/ril_0` we used to fire `ModemAdded("/ril_0")` followed by `ModemRemoved("/ril_1")` which may confuse D-Bus clients that are not so good at handling multiple modems. To well-behaved clients the order doesn't matter.

See merge request !4
2015-11-04 07:41:03 +00:00
Slava Monich
7ab4da0c91 [ril] Don't rely on DATA_CALL_LIST_CHANGED too much. Fixes JB#32969
Some RILs don't send RIL_UNSOL_DATA_CALL_LIST_CHANGED event after
data call gets deactivated, only after activation. Some RILs send
it in either case.

Ofono RIL plugin should consider data call disconnected after either
RIL_REQUEST_DEACTIVATE_DATA_CALL successfully completes or data call
disappears from the list reported by RIL_UNSOL_DATA_CALL_LIST_CHANGED,
whichever happens first. That would work with both kinds of RILs.
2015-11-03 19:06:48 +03:00
Slava Monich
f13991d04e [ril] Always fire ModemRemoved first then ModemAdded. Contributes to MER#1110
When switching from /ril_1 to /ril_0 we used to fire ModemAdded("/ril_0")
followed by ModemRemoved("/ril_1") which may confuse D-Bus clients that are
not so good at handling multiple modems. To well-bahaved clients the order
doesn't matter.
2015-11-03 16:06:52 +03:00
Slava Monich
c451110c39 [ril] Elimitated dependency on mce-headers. MER#1110
It's just a few defines, not worth the trouble.
2015-11-02 12:08:23 +03:00
Slava Monich
cb9183f3ff Merge branch 'multisim' into 'master'
New RIL plugin supporting multiple modems

Enabled by --enable-jolla-rilmodem configure option. Old plugin is preserved as a reference and for debugging regressions on Jolla1.

See merge request !2
2015-11-02 08:53:27 +00:00
Slava Monich
c1a9d7a578 [ril] New RIL plugin supporting multiple modems. Fixes MER#1110
Enabled by --enable-jolla-rilmodem configure option.
2015-10-30 18:01:37 +03:00
Slava Monich
9aee7ccadd [ofono] Added ofono_gprs_get_roaming_allowed() function
It's required by the RIL modem.
2015-10-25 19:12:17 +03:00
Slava Monich
0777b2853a Merge branch 'log' into 'master'
Allow to specify a function to be called when debug flags change

This allows to pass log level modifications to the external libraries that don't use ofono DBG mechanism.

See merge request !1
2015-10-25 16:09:11 +00:00
Slava Monich
b7bd9ca425 [ofono] Allow to specify a function to be called when debug flags change
This allows to pass log level modifications to the external libraries that
don't use ofono's DBG mechanism.
2015-10-25 18:47:10 +03:00
Marcel Holtmann
8929d131a3 Release 1.17 2015-09-13 17:08:07 +02:00
Slava Monich
97e34cc851 Merge pull request #302 from monich/nettime
Updated nettime plugin to support more than one modem
2015-09-11 17:03:28 +03:00
Slava Monich
e558d48b6f [ofono] Updated nettime plugin to support more than one modem. MER#1110 2015-09-08 22:23:20 +03:00
Alfonso Sanchez-Beato
51fc828c5e sms: Add trace when datagram is not delivered 2015-09-08 09:14:03 -05:00
Alfonso Sanchez-Beato
ac14de37ca smsutil: Do not check the origin port
Do not check if the origin port is reserved, as some operators use that
range of values.
2015-09-08 09:14:03 -05:00
Alfonso Sanchez-Beato
665c053803 push-notification: Accept push from any origin
Accept push notifications regardless of the origin port, as some
operators do not insert there the WAP connectionless session service
port, and use random values instead.
2015-09-08 09:14:03 -05:00
Slava Monich
aca873a5c4 [spec] Fixed configure option. MER#531
Configure option that enables org.ofono.DebugLog interface was misspelled.
2015-08-27 20:59:38 +03:00
Slava Monich
a12e10e36f Merge pull request #301 from monich/uicc_subscription
SET_UICC_SUBSCRIPTION
2015-08-26 12:50:58 +03:00
Slava Monich
7cd3fb74d4 [rilmodem] Simplified RIL initialization code
Requesting SIM status from RIL_REQUEST_SET_UICC_SUBSCRIPTION error handler
smells like a potential infinite loop. And it doesn't seem to be necessary.
Without that, the whole RIL_REQUEST_SET_UICC_SUBSCRIPTION completion
callback becomes unnecessary.

Simplified the algorithm of finding GSM/UMTS app index. It was a bit strange.
2015-08-25 16:37:30 +03:00
Slava Monich
84289d83fd [rilmodem] If error or request code is unknown, print the number
Also added string for RIL_REQUEST_SET_UICC_SUBSCRIPTION
2015-08-25 16:37:02 +03:00
Carsten Munk
f826abdbc7 Implement SET_UICC_SUBSCRIPTION. Fixes MER#1263
This is based on bd4677ee20
and 6b757515bf by Ratchanan Srirattanamet.
Any missing credit, let us know.
2015-08-25 11:28:31 +02:00
Kuba Pawlak
4e9cbcdb89 hfp: Handle extra CCWA event
When a call is waitng, CCWA event is sent and call object
in state WAITING is created. on ReleaseAndAnswer it is
promoted to INCOMING and later to ACTIVE.
iPhones send an extra CCWA event when active call is ended.
This extra event is creating a second call object in state
WAITING. It is not possible to have two WAITING calls, but
previously waiting call was already promoted to INCOMING.
For a brief time we have two calls from the same number,
one INCOMING and one WAITING. Later WAITING one is removed.
As we cannot have a waiting and incoming call at the same
time, ignore CCWA when there is already an INCOMING call.

< \r\n+CIEV: 3,3\r\n
< \r\n+CIEV: 2,1\r\n
< \r\n+CIEV: 3,0\r\n
< \r\n+CCWA: "01234567890",129,1,"Me"\r\n
< \r\n+CIEV: 3,1\r\n
> AT+CLCC\r
< \r\n+CLCC: 1,0,0,0,0,"09876543210",129,"Me"\r\n
< \r\n+CLCC: 2,1,5,0,0,"01234567890",129,"Me"\r\n
< \r\nOK\r\n
< \r\n+CIEV: 2,0\r\n
< \r\n+CCWA: "01234567890",129,1,"Me"\r\n
< \r\n+CIEV: 2,1\r\n
< \r\n+CIEV: 3,0\r\n
> AT+CLCC\r
< \r\n+CLCC: 2,1,0,0,0,"01234567890",129,"Me"\r\n
< \r\nOK\r\n
2015-08-24 16:29:29 -05:00
Slava Monich
f6ac328110 Merge pull request #298 from monich/debuglog
Add org.ofono.DebugLog interface
2015-08-24 14:36:14 +03:00
Slava Monich
8d46ababee [ofono] Added org.ofono.DebugLog interface. MER#531
It provides the following methods:

  array(string,boolean) List()
  void Enable(string pattern)
  void Disable(string pattern)

Enable and Disable methods allow to modify ofono logging settings
without restarting it. The List method returns the list of modules
for which logging can be changed at runtime and their current settings.
2015-08-19 16:33:07 +03:00
Denis Kenzior
9ec8d03c7c voicecall: Don't accept USSD strings in Dial() 2015-08-06 17:16:03 -05:00
Kuba Pawlak
3e6bbc676f hfp: Synchronize call state in case of +CHUP error
It is possible for the phone to accept Dial request
but not actually dial. This leaves a voicecall object
in state 'dialling' that cannot be removed.
Proposed workaround is to trigger AT+CLCC when an error
is returned for Hangup. As the call is not on the list,
this would remove this hanging object and signal CallRemoved.

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

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

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

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

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

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

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

Reported by: blanca.e.sabas.rosales@intel.com
2015-06-30 16:58:36 -05:00
Slava Monich
0073dc7bfc [sms] Don't drop SMS datagrams with unknown ports. Fixes MER#1137 2015-06-26 15:52:35 +03:00
Tommi Kenakkala
297bdaba0f Merge pull request #293 from tkenakka/cherrypick-pin-upstr
[sim] Improve Emit LockedPins after pin_type is queried. MER#1082
2015-06-23 15:12:46 +03:00
Tommi Kenakkala
f14db3b2a6 Merge pull request #292 from tkenakka/sockpath
Read RILD command socket path from a conf file. MER#1107
2015-06-23 14:44:31 +03:00
Tommi Kenakkala
4a0182616d [ril] Read RILD socket path from a file at startup. MER#1107
This allows configuring at startup the socket path to which ril plugin
will connect to.
2015-06-23 11:44:48 +03:00
Tommi Kenakkala
bbdfc8f46d [sim] Improve Emit LockedPins after pin_type is queried. MER#1082
Merge additional upstreaming changes from upstream commit eebe2f3
to previous nemomobile ofono commit 10328e6
2015-06-23 11:38:10 +03:00
Tommi Kenakkala
fbd59a8dc9 [gril] Change oFono gril to take a socket path. MER#1107
This allows configuring at startup the socket path to which gril
will connect to.
2015-06-22 11:16:00 +03:00
Denis Kenzior
48da783732 sim: Fix up whitespace issues 2015-06-18 14:59:06 -05:00
Tommi Kenakkala
eebe2f3ac2 Emit LockedPins after pin_type is queried
Fixes property change not being emited when hot-swapping a
PIN-enabled card.
2015-06-18 14:56:05 -05:00
Tommi Kenakkala
7eb6d5559a Merge pull request #291 from tkenakka/pin
[sim] Reset ofono pin state to none when card removed
2015-06-18 12:14:18 +03:00
Tommi Kenakkala
9a47510eb5 [sim] Coding conventions improvements for sim.c
Improves 10328e626d
2015-06-18 12:11:03 +03:00
Tommi Kenakkala
8fc7ae836f [sim] Reset pin state to none when card removed
Improves d88af05dc3
sim_get_properties would have problems with OFONO_SIM_PASSWORD_INVALID.
2015-06-18 12:11:03 +03:00
Tommi Kenakkala
4677729502 sim: Reset pin_type on card remove
Fixes PinRequired not being emitted when a card is inserted
2015-06-17 23:09:03 -05:00
Tommi Kenakkala
8c0f4f27eb Merge pull request #290 from tkenakka/pin
Refactor rilmodem SIM PIN handling
2015-06-10 15:09:53 +03:00
Tommi Kenakkala
b932bed519 Merge pull request #288 from monich/features
Don't unnecessarily emit "Features" PropertyChanged signal
2015-06-10 15:08:34 +03:00
Tommi Kenakkala
db83ac369b Merge pull request #287 from monich/leak
Fix memory leak
2015-06-10 15:02:54 +03:00
Tommi Kenakkala
e26df8a645 [rilmodem] Minor sim related logging updates 2015-06-09 16:19:01 +03:00
Tommi Kenakkala
5144f3fa14 [rilmodem] Remove ofono_set_pin_lock_state. Contributes MER#1082
Core sets LockedPins when driver returns that a PIN query is
required.
2015-06-09 16:17:55 +03:00
Tommi Kenakkala
0d6459b9b0 [sim] Remove ofono_set_pin_lock_state. Contributes MER#1082 2015-06-09 16:17:44 +03:00
Tommi Kenakkala
10328e626d [sim] Emit LockedPins changed. Contributes MER#1082
org.ofono.SimManager "Present" is signalled by ofono_sim_inserted_notify,
but LockedPins and PinRequired are updated later by sim_pin_query_cb.
Without signalling a client does not know when LockedPins
becomes available.
2015-06-09 16:05:43 +03:00
Tommi Kenakkala
5b407d654a [rilmodem] Reset retry count on PIN state change
After this rilmodem driver reports retries only for the required PIN type
and does not remember counts for previous password types.
2015-06-09 16:05:43 +03:00
Tommi Kenakkala
d88af05dc3 [sim] Reset pin_type on card removal. Contributes MER#1083
With this the variable behind org.ofono.SimManager "PinRequired"
is reset when card is removed, allowing signalling property change
in sim_pin_query_cb when card is inserted back.
2015-06-09 16:05:43 +03:00
Tommi Kenakkala
99cae6876f [rilmodem] Reset rilmodem driver's PIN type on card removal. Contributes MER#1083
Getting the PIN state for a freshly inserted card takes a while,
without this change driver uses the old state until the new state
is known.
2015-06-09 16:05:43 +03:00
Tommi Kenakkala
89e6593f9c [rilmodem] Delay signalling SIM inserted until PIN state available
Delay ofono_sim_inserted_notify call to core until PIN state is parsed
from gsmumts application by rilmodem driver.
2015-06-09 16:05:43 +03:00
Kuba Pawlak
93ccb84761 hfpmodem: Fix connecting to AG with existing mpty
If there is more then one active or held call, we are in mpty calls.
We won't get indicator update if any of them is released by CHLD=1x.
So we have to poll it.
2015-06-04 16:18:08 -05:00
Alfonso Sanchez-Beato
e70afdd9dc gprs: Add comment to gprs_reset_contexts 2015-05-18 12:13:04 -05:00
Denis Kenzior
1edb6eec9b test: Fix file mode for reset-contexts 2015-05-18 10:02:10 -05:00
Alfonso Sanchez-Beato
946b568f43 gprs: Refactor to remove forward declaration 2015-05-18 09:08:33 -05:00
Alfonso Sanchez-Beato
f3f3dabfac test: Add script for resetting contexts 2015-05-18 09:08:28 -05:00
Alfonso Sanchez-Beato
4c0f783f5c doc: Add description for ResetContexts method 2015-05-18 09:08:20 -05:00
Alfonso Sanchez-Beato
444611c086 gprs: Add DBus method to reset contexts
Add DBus method that removes the current contexts and re-provisions
using the APN database.
2015-05-18 09:08:13 -05:00
Tommi Kenakkala
8e9085f5ab Merge pull request #289 from tkenakka/simmgr
[rilmodem] Fix simmanager removal handling. Contributes to MER#928
2015-05-15 12:47:15 +03:00
Tommi Kenakkala
c33a48ea0c [rilmodem] Fix simmanager removal handling. Contributes to MER#928
Improves 7d0d72a.
2015-05-15 11:38:21 +03:00
Alex J Lennon
f8d9485dc2 cinterion: Correct use of freed structure
On error struct cb_data *cbd was used after in cinterion_set_online
after already being freed.
2015-05-13 15:56:34 -05:00
Denis Kenzior
23c45abd57 ste: Fix out-of-order free
CALLBACK_WITH_FAILURE used data structure freed just beforehand
2015-05-13 15:55:00 -05:00
Denis Kenzior
a371f46735 dundee: Fix out-of-order free
CALLBACK_WITH_FAILURE used data structure freed just beforehand
2015-05-13 15:44:39 -05:00
Denis Kenzior
ce0529fcf6 AUTHORS: Mention Alex's contributions 2015-05-13 09:57:53 -05:00
Alex J Lennon
fc3f937a67 udev: Add support for ehs6 name
As with tc65, ehs6 makes use of cinterion plugin
2015-05-13 09:57:53 -05:00
Alex J Lennon
7d4a19b114 cinterion: Register as OFONO_VENDOR_CINTERION
This enables us to take advantage of vendor specific quirks
(e.g. signal strength handling specifics for tc65)
2015-05-13 09:57:53 -05:00
Alex J Lennon
4242f6ee72 atmodem: Add Cinterion quirk for signal strength
Implement OFONO_VENDOR_CINTERION specific vendor support to register
textual +CIEV indications for signal strength using AT^SIND command.
2015-05-13 09:57:53 -05:00
Alex J Lennon
b31a3c2390 tc65: Replace tc65 plugin with cinterion plugin
On the basis that tc6x and other Cinterion devices will likely
have similar firmware requirements, provide a generic Cinterion
plugin which is functionally identical to the replaced tc65 plugin.

The udev implementation retains support for "tc65" name for
backwards compatibility, and adds support for the new "cinterion"
name.
2015-05-13 09:57:53 -05:00
Denis Kenzior
8d47f97106 hfp_hf_bluez5: Implement sco_connected_hint 2015-05-13 09:57:53 -05:00
Denis Kenzior
fdba39b8ed handsfree-audio: Call sco_connected_hint 2015-05-13 09:57:52 -05:00
Denis Kenzior
288364295c include: Add sco_connected_hint to handsfree-audio 2015-05-13 09:57:52 -05:00
Denis Kenzior
bce5d9579c gatchat: Introduce g_at_chat_get_userdata 2015-05-13 09:57:52 -05:00
Denis Kenzior
1c2987670d handsfree-audio: Add additional debugs 2015-05-13 09:57:52 -05:00
Tommi Kenakkala
44585697c3 Merge pull request #286 from tkenakka/simmgr
Register SimManager interface always and simplify logic
2015-05-06 10:06:29 +03:00
Slava Monich
3860230644 [modem] Don't unnecessarily emit "Features" PropertyChanged signal
Not all interfaces have corresponding features, meaning that not every
interface addition or removal actually updates the feature list.
If nothing else, this reduces the number of D-Bus signals emitted.
2015-05-05 16:11:06 +03:00
Tommi Kenakkala
07da2f3fa7 [rilmodem] Minor updates to error debug logging
Added function name prefix printing.
2015-05-05 15:52:35 +03:00
Tommi Kenakkala
7d0d72a4a9 [rilmodem] Register SimManager always and simplify logic. MER#928
Register org.ofono.SimManager always, without this the dbus
interface does not exist when starting without a SIM card.
Simplified rilmodem SIM status handling.
Moved some debug logging from sim.c to rilutil.c.
2015-05-05 15:52:35 +03:00
Tommi Kenakkala
f9ee2ae9b8 [rilmodem] Remove rilplugin sim inserted notification. MER#928
Functionality combined in rilmodem/sim.c.
No need to notify from both ril.c and sim.c.
2015-05-05 15:52:35 +03:00
Slava Monich
063234a433 [rilmodem] Fixed memory leak in handle_sne() 2015-05-05 15:51:12 +03:00
Tommi Kenakkala
c006d822f1 [rilmodem] Improve rilutil debug logging
Move some logs from rilmodem/sim.c to rilmodem/rilutil.c
and do some additional improvements.
2015-04-30 16:17:12 +03:00
Luiz Augusto von Dentz
a5b040b781 gdbus: Close private connection if setup fails
Private connection should be properly closed with dbus_connection_close
otherwise libdbus exits with the following error:

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

Nov 30 00:00:19 ofonod[938]: > AT+BCC\r
Nov 30 00:00:28 ofonod[938]: < \r\n+CIEV: 2,0\r\n
2015-03-24 09:12:58 -05:00
Tommi Kenakkala
7331c88b41 Merge pull request #285 from tkenakka/merge1.16
Merge oFono upstream release 1.16
2015-03-04 13:48:08 +02:00
Tommi Kenakkala
063eefbac1 [ofono] Disable build time he910 modem 2015-03-03 15:27:45 +02:00
Tommi Kenakkala
12b510b4e7 [ofono] Update version to 1.16 2015-03-03 15:27:38 +02:00
Tommi Kenakkala
c04f5df8ec [ofono] Merge upstream release 1.16 2015-02-27 15:56:55 +02:00
Tommi Kenakkala
011bc0741a Merge pull request #284 from tkenakka/master
[gprs] Fix pri_reset_context_properties crashes
2015-02-27 11:36:09 +02:00
Tommi Kenakkala
773834c5a3 [gprs] Fix pri_reset_context_properties crashes
Fixes issues of ff63e9b0
2015-02-27 11:08:03 +02:00
Tommi Kenakkala
14acafc581 Merge pull request #283 from tkenakka/norild
Rild comms socket detection and monitoring for oFono rilmodem plugin
2015-02-26 13:29:32 +02:00
Tommi Kenakkala
b4df40608b [gril] Minor updates to ofono gril logging 2015-02-26 11:52:24 +02:00
Tommi Kenakkala
26f750fe4f [plugins] Improved ofono rilmodem socket handling
- Fix rildev.c's rild socket inotify handling
- Fix gril creation fail handling
- Improve logic logging and add __func__ arg for some ofono_XXX log prints
- Same style for rildev plugin name descriptor as what rilmodem plugin has
2015-02-26 11:52:23 +02:00
Jarko Poutiainen
51f6837545 [plugins] rildev.c remove unnecessary modem reset
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-02-25 15:18:52 +02:00
Jarko Poutiainen
6919c43ff6 [plugins] rildev.c add error handling
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-02-25 15:18:52 +02:00
Jarko Poutiainen
621614e518 [Makefile] add rildev as builtin
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-02-25 15:18:52 +02:00
Jarko Poutiainen
8e820dfdd3 [gril] gril.h remove current_passwd
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-02-25 15:18:51 +02:00
Jarko Poutiainen
04cc2e9fd2 [gril] gril.c remove current_passwd
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-02-25 15:18:51 +02:00
Jarko Poutiainen
ae5c8e6e3a [rilmodem] remove current_passwd support from sim driver
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-02-25 15:18:51 +02:00
Jarko Poutiainen
1509cb811a [plugins] ril to support rild socket detection
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-02-25 15:18:51 +02:00
Jarko Poutiainen
5682df6d82 [plugins] rildev to detect rild socket
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-02-25 15:18:51 +02:00
Jarko Poutiainen
3e38512e2f [plugins] add rildev.h
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-02-25 15:18:51 +02:00
Alfonso Sanchez-Beato
dc5157c5d0 plugins: Add rildev for creation of ril modems
This new plugin will create ril modems, providing the same
functionality as udev/udevng does for USB-based modems.
2015-02-25 15:18:51 +02:00
Tommi Kenakkala
59449f74a1 Merge pull request #282 from monich/provision
Add ProvisionContext method to ConnectionContext interface
2015-02-25 15:16:31 +02:00
Slava Monich
ff63e9b057 [ofono] Added ProvisionContext method to ConnectionContext interface
Allows to reset connection context properties back to default.
2015-02-25 12:36:04 +02:00
Szymon Janc
d8edd49535 gdbus: Fix not calling disconnect function
If daemon gets disconnected from D-Bus sender is NULL. Watches that
was explicitly added with NULL sender (ie disconnected_signal in
g_dbus_set_disconnect_function) should be called anyway.
2015-02-24 18:24:42 +01:00
Pasi Sjöholm
7b73f569eb Merge pull request #280 from tigeli/master
[rilmodem] fix issue with only one nameserver being provided
2015-02-23 10:03:55 +01:00
Arman Uguray
8660527b11 gdbus: Don't refresh objects/props if disconnected
If g_dbus_client_set_proxy_handlers gets called from within a
proxy_removed callback, the code may end up refreshing the proxy's
properties and incorrectly access the client's proxy_list as it gets
freed. This patch fixes this, so that get_managed_objects does nothing
if it gets called during a service disconnect.
2015-02-22 19:42:25 +01:00
Pasi Sjöholm
5672f7248d [rilmodem] fix issue with only one nameserver being provided
No need to check if we have multiple nameserver provided
by the context, single one is enough.
2015-02-20 22:21:26 +02:00
Denis Kenzior
d6bc91ebfc hfpmodem: Make sure to use none_prefix
ofonod[253]: > AT+CCWA=1\r
ofonod[253]: < \r\n+BCS:2\r\n
ofonod[253]: < \r\nOK\r\n
2015-02-20 10:30:21 -06:00
Denis Kenzior
3d592d7d46 hfpmodem: Make sure to set the prefix properly
ofonod[1239]: > AT+COPS=3,0\r
ofonod[1239]: < \r\n+BCS:2\r\n
ofonod[1239]: < \r\nOK\r\n
2015-02-20 10:28:24 -06:00
Tommi Kenakkala
2ed0073bd1 Merge pull request #279 from tkenakka/log
[ofono] Add ril disconnect logging
2015-02-17 12:29:19 +02:00
Tommi Kenakkala
f6ade48648 Merge pull request #278 from tkenakka/sms-tp-oa
Fix received SMS alphanumeric TP-OA handling
2015-02-17 12:28:55 +02:00
Tommi Kenakkala
73ba48c9fb [ofono] Add ril disconnect logging 2015-02-17 11:12:18 +02:00
Tommi Kenakkala
f3611cef21 [ofono] unit: Add test to encode / decode 11 char SMS TP-OA 2015-02-16 10:31:16 +02:00
Tommi Kenakkala
15d682e62a [ofono] sms: Fix alphanumeric TP-OA handling
This fixes the issue of ofono ignoring received SMS if originator address
is a 11-character long alphanumeric string (with ext. ASCII).

TP-OA max length comparisons were incorrect because TP-OA's 7-bit coded
octets transport eleven 8-bit chars. The current code assumed only 10 chars
were possible.
- increases the array size to 23, (max 22 bytes for UTF8 + null terminator)
- Updates the sanity check to account for the correct maximum
- For encoding, checks the maximum length in UTF8 characters instead of bytes
- Make sure after the UTF8 -> GSM conversion that the number of GSM bytes is
not > 11, which is the maximum payload.
2015-02-16 10:30:18 +02:00
Denis Kenzior
e2398b4dfa smsutil: Add additional sanity check
We make sure that after performing the UTF8 -> GSM conversion, the
number of GSM bytes is not greater than 11, which is the maximum
payload.
2015-02-13 09:59:59 -06:00
Tommi Kenakkala
42deee76a1 unit: Add test to encode / decode 11 char TP-OA 2015-02-13 09:55:16 -06:00
Tommi Kenakkala
2af3c733b7 sms: Fix alphanumeric TP-OA handling
TP-OA max length comparisons were incorrect because TP-OA's 7-bit
coded octets transport eleven 8-bit chars.  The current code assumed
only 10 chars were possible.

The patch
- increases the array size to 23, (maximum of 22 bytes for UTF8
  encoding + null terminator)
- Updates the sanity check to account for the correct maximum
- For encoding, checks the maximum length in UTF8 characters instead of
  bytes
2015-02-13 09:49:39 -06:00
Denis Kenzior
604fa223f4 AUTHORS: Mention Tommi's contributions 2015-02-02 09:29:46 -06:00
Tommi Kenakkala
04218d3a86 handsfree-audio: Refactor manager init / cleanup 2015-02-02 09:28:34 -06:00
Tommi Kenakkala
41fadd3787 main: Remove handsfree_audio_manager init/cleanup
Init allocates a SCO audio socket always. oFono should do that
with bluez5 but not with bluez4.  This patch starts the refactoring of
the handsfree_audio_manager init/cleanup functionality.
2015-02-02 09:26:58 -06:00
Cedric Jehasse
d539ed19f3 atmodem: fix retries reporting from AT+CPINR
The retries array was not correctly filled in.
2015-02-02 09:22:21 -06:00
Cedric Jehasse
25f926c733 atmodem: Sierra modems should be polled after CPIN
Sierra modem will return "CME ERROR: 14" when polled right after pin has
been entered. Use the existing vendor quirk to handle this.
2015-02-02 09:21:10 -06:00
Cedric Jehasse
151b837428 sierra: add sim state polling after CFUN enable
When pin is queried shortly after a Siera dongle is plugged in,
"AT+CPIN?" responds with "CME ERROR 14: SIM".
Poll the sim, as already done by several other vendor plugins.
2015-01-31 10:20:18 -06:00
Tommi Kenakkala
0c23ed90b7 Merge pull request #276 from tkenakka/sco-sock
[ofono] hfp_hf_bluez5 typo fix
2015-01-27 10:44:12 +02:00
Tommi Kenakkala
54854c44a2 [ofono] hfp_hf_bluez5 typo fix 2015-01-27 10:41:00 +02:00
Tommi Kenakkala
da297d5722 Merge pull request #275 from tkenakka/sco-sock
[ofono] Move handsfree audio manager cleanup to hfp_hf_bluez5 plugin
2015-01-27 10:34:12 +02:00
Tommi Kenakkala
aba76cec73 [ofono] Move handsfree audio manager cleanup to hfp_hf_bluez5 plugin 2015-01-27 10:02:40 +02:00
Tommi Kenakkala
3cdc8f775d Merge pull request #274 from tkenakka/sco-sock
[ofono] Move SCO socket allocation to hfp_hf_bluez5 plugin
2015-01-27 09:02:20 +02:00
Tommi Kenakkala
bee03f8b56 [ofono] Move SCO socket allocation to hfp_hf_bluez5 plugin
SCO socket is handled by Bluez4 and conflicts with ofono's socket
allocation.
2015-01-27 08:58:48 +02:00
Tommi Kenakkala
7f4da6d59f Merge pull request #273 from jpoutiai/signal-context
Emit signal when context changed
2015-01-13 09:17:30 +02:00
Tommi Kenakkala
5754fff800 Merge pull request #272 from monich/noproxy
Setup route for mmsc if there's no mms proxy
2015-01-07 16:05:02 +02:00
Jarko Poutiainen
fff6952703 [rilmodem] if data call changed emit signal
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-01-07 09:44:06 +02:00
Jarko Poutiainen
96ff96ab1a [gril] compare data call lists based on cid
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-01-07 09:43:43 +02:00
Jarko Poutiainen
986ac50b9e [gril] publish g_ril_unsol_cmp_dcl
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-01-07 09:43:10 +02:00
Jarko Poutiainen
8600d8d293 [gprs] implement ofono_gprs_context_signal_change
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-01-07 09:42:52 +02:00
Jarko Poutiainen
369af1b401 [gprs] define ofono_gprs_context_signal_change
Signed-off-by: Jarko Poutiainen <jarko.poutiainen@oss.tieto.com>
2015-01-06 13:08:28 +02:00
Slava Monich
500b5234b2 [gprs] Setup route for mmsc if there's no mms proxy 2015-01-05 15:56:12 +03:00
Slava Monich
93eb292b75 Merge pull request #271 from monich/OperatorsChanged
Add NetworkRegistration.OperatorsChanged signal
2014-12-31 12:47:57 +03:00
Slava Monich
3cc42fb087 [network] Added NetworkRegistration.OperatorsChanged signal
This signal gets emitted when operator list has changed.
It contains the current list of operators.
2014-12-22 09:12:18 +01:00
Marcel Holtmann
c9e426ecd7 Release 1.16 2014-12-13 02:56:19 +01:00
Alfonso Sanchez-Beato
10f173981c radio-settings: Show all available technologies
Not all possible futures technologies were being showed on the DBus
interface.
2014-12-12 08:54:14 -06:00
Jarko Poutiainen
782f2327fd Merge pull request #270 from jpoutiai/ipv6
[RILMODEM] fix same gateway for ipv4 and ipv6 issue
2014-12-12 12:38:26 +02:00
Tommi Kenakkala
8bda4032ca Merge pull request #269 from tkenakka/master
[rilmodem] Log ril version
2014-12-12 10:40:53 +02:00
Tommi Kenakkala
b2f4bd7603 [rilmodem] Log ril version 2014-12-12 10:22:11 +02:00
Jarko Poutiainen
33bb6d829c [RILMODEM] fix same gateway for ipv4 and ipv6 issue
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-12-12 08:32:38 +02:00
Denis Kenzior
bb71141d79 phonesim: Instantiate radio-settings in post_sim 2014-12-10 11:03:17 -06:00
Denis Kenzior
4e466f6fec phonesim: Add minimal radio-settings functionality 2014-12-10 11:03:17 -06:00
Denis Kenzior
a89f8cd56d phonesim: Add skeleton of radio settings driver 2014-12-10 11:03:16 -06:00
Denis Kenzior
95482cb84a radio-settings: Always query available rats
If fast dormancy query is not implemented the available rats are not
queried.
2014-12-10 11:03:16 -06:00
Denis Kenzior
fce95b767a radio-settings: Add additional sanity check 2014-12-10 11:03:16 -06:00
Denis Kenzior
44049f064a radio-settings: rework AvailableTechnologies logic
Take advantage of the new enum structure to future proof and simplify
the logic of generating the AvailableTechnologies property
2014-12-10 11:03:16 -06:00
Denis Kenzior
b899f4aca2 include: No need for OFONO_FLAG* defines 2014-12-10 11:03:16 -06:00
Alfonso Sanchez-Beato
e1cbc5c5ea test: Add AvailableTechnologies to list-modems 2014-12-10 11:03:16 -06:00
Alfonso Sanchez-Beato
5210b85c22 src: Implement RAT list property 2014-12-10 11:03:16 -06:00
Alfonso Sanchez-Beato
e6048f1dc1 include: Add method to list RATs to radio-settings 2014-12-10 11:03:16 -06:00
Tommi Kenakkala
1bea99ac56 Merge pull request #267 from jpoutiai/ipv6
Ipv6
2014-12-10 13:46:16 +02:00
Alfonso Sanchez-Beato
6bdc109ec0 doc: Add AvailableTechnologies property
This new property in org.ofono.RadioSettings interface will hold the
possible values for radio access technology for the modem.
2014-12-09 22:29:21 -06:00
Jarko Poutiainen
aab24b3f24 Merge pull request #268 from hedayat/master
Re-enable CBS in n900 plugin and fix CBS related crash in N9
2014-12-09 07:47:42 +02:00
Jarko Poutiainen
65eea56efe [RILMODEM] use glib to split string to array and some style fixes
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-12-08 15:54:55 +02:00
Jarko Poutiainen
8ac7e502b7 [GRIL] use glib to split string to array
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-12-08 15:53:06 +02:00
Hedayat Vatankhah
9e8bdf0d64 [packaging] Fix error in changelog date format preventing mb2 builds 2014-12-08 01:46:41 +03:30
Hedayat Vatankhah
70e99152a3 Fix cbs related n900/isimodem crash
Don't remove cbs data during shutdown sequence in isimodem driver, since
it is already being removed.

[n900] Fix cbs related crash
2014-12-08 01:46:41 +03:30
Hedayat Vatankhah
a90fc92665 Revert "Remove the cbs creation for n900 plugin, this lead to crashes on n9 ofono init."
This reverts commit 804bef98ad.
2014-12-08 01:46:41 +03:30
Denis Kenzior
7dca0a7315 sim: Fix pin retries bogus values on some arch-es
On some architectures the SimManager.Retries property was getting bogus
values.  This is because we were sending an array which pointed to int
values instead of the expected unsigned char values.

This fix allocates a temporary array of unsigned chars to hold the
actual D-Bus values being sent.  Additionally, the dictionary array is
changed to point to the temporary unsigned char based values instead of
the raw 'int' based retry values.
2014-12-04 08:57:48 -06:00
Jarko Poutiainen
1d23793eb0 Merge pull request #266 from locusf/master
Remove the cbs creation for n900 plugin, this lead to crashes on n9 ofon...
2014-12-01 07:58:33 +02:00
Aleksi Suomalainen
804bef98ad Remove the cbs creation for n900 plugin, this lead to crashes on n9 ofono init.
For the latest release of ofono for Nemo Mobile, the modem fails to initialize
with the isimodem driver enabled. This is due to a segmentation fault occurring
in the flush of the atoms of the modem in cbs_assembly_free function. This
resulted in a segmentation fault when using n900 driver.

[n900] Remove cbs creation.
2014-11-30 16:06:58 +00:00
Jarko Poutiainen
1fdde8fecb [RILMODEM] gprs dual mode support
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-11-26 14:38:06 +02:00
Jarko Poutiainen
1c484a6d04 [GRIL] in reply parse all datacall settings
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-11-26 13:55:13 +02:00
Neil Jerram
19519b2132 test: Support receiving SMS with non-ASCII chars
Without this I get the following Python traceback, for an SMS that
contains the UK pound sign.

ERROR:dbus.connection:Exception in handler for D-Bus signal:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/dbus/connection.py", line 230, in maybe_handle_message
    self._handler(*args, **kwargs)
  File "./receive-sms", line 9, in incoming_message
    print("%s" % (message))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 51: ordinal not in range(128)
2014-11-24 12:29:45 -06:00
Jarko Poutiainen
64e888ef04 [RILMODEM] ipv6 support
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-11-20 09:54:33 +02:00
Jarko Poutiainen
b33e0061d0 Merge pull request #263 from jpoutiai/sim-fix
[RILMODEM] fix hotswap regression
2014-11-18 15:27:29 +02:00
Jarko Poutiainen
2babf82823 [RILMODEM] fix hotswap regression
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-11-18 14:10:20 +02:00
Jarko Poutiainen
87a35d5d83 Merge pull request #262 from nemomobile-packages/no-fake
No fake
2014-11-17 15:48:17 +02:00
Jarko Poutiainen
3d264276de [RILMODEM] style fixes
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-11-17 15:31:51 +02:00
Jarko Poutiainen
d6bd24add3 [RILMODEM] remove gprs state faking
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-11-13 10:33:55 +02:00
Jarko Poutiainen
9624eb9ace [gprs] publish ofono_gprs_get_modem
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-31 14:55:08 +02:00
Jarko Poutiainen
14672319d2 [gprs] implement ofono_gprs_get_modem
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-31 14:54:39 +02:00
Jarko Poutiainen
0d8b576ab6 Merge pull request #261 from jpoutiai/sim-fix
[RILMODEM] query password state and prevent double sim initialisation
2014-10-30 13:59:09 +02:00
Jarko Poutiainen
c16121469b [RILMODEM] query password state and prevent double sim initialisation
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-29 10:04:06 +02:00
Jarko Poutiainen
812f552ace Merge pull request #260 from jpoutiai/vc-delay-nro-storing
[voicecall] src/voicecall.c MO call delay storing number
2014-10-28 10:38:24 +02:00
Kuba Pawlak
42ebb69384 he910: Update copyright 2014-10-22 21:23:25 -05:00
Kuba Pawlak
45478b17cf he910: enable location raporting atom 2014-10-22 21:22:33 -05:00
Kuba Pawlak
88f46a9b01 udev: add GPS port definition for HE910 2014-10-22 21:22:24 -05:00
Denis Kenzior
2abcb85809 telitmodem: Fix a few coding style violations 2014-10-22 21:21:49 -05:00
Denis Kenzior
331700a697 AUTHORS: Mention Kuba's contributions 2014-10-22 21:21:18 -05:00
Kuba Pawlak
a753d6c012 telitmodem: location reporting driver 2014-10-22 21:15:35 -05:00
Kuba Pawlak
d39007c948 doc: new file doc/telit-modem.txt 2014-10-22 21:10:50 -05:00
Jarko Poutiainen
fe52d1dc53 [voicecall] src/voicecall.c MO call delay storing number
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-22 11:43:14 +03:00
Jarko Poutiainen
8be724836e Merge pull request #259 from jpoutiai/gprs
rilmodem gprs fixes
2014-10-22 10:58:42 +03:00
Jarko Poutiainen
8c96a7e091 Merge pull request #258 from jpoutiai/roaming-fix
Roaming fix
2014-10-22 10:13:01 +03:00
Jarko Poutiainen
f9bd555dc0 [RILMODEM] style fix
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-22 09:16:18 +03:00
Denis Kenzior
6c4ac05fbc emulator: Refine +BIND support 2014-10-20 13:40:29 -05:00
Denis Kenzior
934ea9a9fe hfp_ag_bluez5: Bump HFP version to 1.7 2014-10-20 13:40:28 -05:00
Denis Kenzior
cf90f1505d emulator_fuzz: Add test plugin
This plugin creates an org.ofono.test.EmulatorFuzz interface on path
/test.  Currently only one method is implemented, SetIndicatorActive.

SetIndicatorActive("DistractedDrivingReduction", True|False) allows to
activate / deactivate the HF indicator via +BIND unsolicited
notification.
2014-10-20 13:40:28 -05:00
Denis Kenzior
f9d5ee5fa9 emulator: Implement new API 2014-10-20 13:40:28 -05:00
Denis Kenzior
e2785b1865 include: Add API to (de)activate HF indicators 2014-10-20 13:40:28 -05:00
Denis Kenzior
fb1b213e22 test: Add test/set-ddr
Script to set DistractedDrivingReduction property
2014-10-20 13:40:28 -05:00
Denis Kenzior
d3560b3784 handsfree: Be extra pedantic with booleans 2014-10-20 13:40:28 -05:00
Denis Kenzior
017c1161d4 hfp_hf_bluez5: Use latest HFP version 2014-10-20 13:40:28 -05:00
Denis Kenzior
de02f68a2e handsfree: Don't try to send a method return
When we are simply updating the AG of HF indicator changes, do not try
to send a method return message.
2014-10-20 13:40:28 -05:00
Denis Kenzior
0f28d9206d slc: Make sure to initialize variables 2014-10-20 13:40:28 -05:00
Denis Kenzior
eef67018b6 hfp: Implement +BIND notifications 2014-10-20 13:40:28 -05:00
Denis Kenzior
299ffc9620 hfp: Notify core of HF indicators supported by AG
This information was obtained from SLC negotiation
2014-10-20 13:40:28 -05:00
Denis Kenzior
39f08a5e1c hfp: Track supported / active indicators
This information is obtained during SLC establishment
2014-10-20 13:40:28 -05:00
Denis Kenzior
6c0f90fc1b handsfree: Implement new HF indicators API 2014-10-20 13:40:28 -05:00
Denis Kenzior
33537adb9f include: Add HF Indicators related API 2014-10-20 13:40:28 -05:00
Denis Kenzior
e176a9019f hfp: Add implementation of +BIEV 2014-10-20 13:40:28 -05:00
Denis Kenzior
7166aebd51 emulator: Refactor data types 2014-10-20 13:40:28 -05:00
Denis Kenzior
debb0d2d3e hfp: Add HF Indicators BRSF feature for 1.7
If HFP 1.7 client is used, enable the right BRSF feature
2014-10-20 13:40:28 -05:00
Denis Kenzior
ab5b6d1217 handsfree: Skeleton implementation of DDR
Distracted Driving Reduction or Enhanced Safety is implemented using HF
indicator 0x0001
2014-10-20 13:40:28 -05:00
Denis Kenzior
7e3a6628fa handsfree: Add new driver method for HF indicators 2014-10-20 13:40:28 -05:00
Denis Kenzior
fa105c4ba6 hfp: Add initial SLC negotiation for HFP 1.7 2014-10-20 13:40:28 -05:00
Denis Kenzior
99c03292ad doc: Add Distracted Driving Reduction to Handsfree 2014-10-20 13:40:28 -05:00
Denis Kenzior
66cf2a30fa handsfree: Implement new Features property value 2014-10-20 13:40:28 -05:00
Denis Kenzior
a4fa356b16 doc: Add 'hf-indicators' feature to Handsfree API 2014-10-20 13:40:28 -05:00
Denis Kenzior
43e83852dc emulator: Enable HF Indicator feature 2014-10-20 13:40:28 -05:00
Denis Kenzior
36a21da227 emulator: Extend BRSF bitmap
The current check of 8 bits is not enough with HFP 1.7
2014-10-20 13:40:28 -05:00
Denis Kenzior
bef4d610a3 emulator: Add +BIEV implementation 2014-10-20 13:40:28 -05:00
Denis Kenzior
2d158167c2 emulator: Add +BIND implementation 2014-10-20 13:40:27 -05:00
Denis Kenzior
02c5b73f6e emulator: Fix CHLD=? not treated as part of SLC 2014-10-20 13:40:27 -05:00
Denis Kenzior
0727da1d5b emulator: Improve SLC establishment logic 2014-10-20 13:40:27 -05:00
Denis Kenzior
d292e0e0ed hfp: Add enum for known HF Indicators 2014-10-20 13:40:27 -05:00
Denis Kenzior
881207ce18 hfp: Update for new HFP 1.7 values 2014-10-20 13:40:27 -05:00
Denis Kenzior
0f0733c348 doc: Fixup Handsfree API 2014-10-20 13:40:27 -05:00
Jarko Poutiainen
71fd5c148a [RILMODEM] recheck status also in ril_data_probe_reg_cb
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-20 10:29:18 +03:00
Jarko Poutiainen
476e440f47 [RILMODEM] recheck status value before using it
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-20 10:26:54 +03:00
Jarko Poutiainen
35440277d1 [RILMODEM] prevent datacall slipping through when roaming disabled
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-20 09:56:07 +03:00
Jarko Poutiainen
4f67e6743e [RILMODEM]publish get_current_network_status
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-20 09:55:40 +03:00
Jarko Poutiainen
c9ba23ae3d [RILMODEM] get network status from core
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-20 09:50:15 +03:00
Jarko Poutiainen
dcdddee5c5 [RILMODEM] introduce ril_roaming_allowed
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-14 09:31:37 +03:00
Jarko Poutiainen
195c2c6a1e [RILMODEM] prepare ril_roaming_allowed to be published
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-14 09:30:53 +03:00
Jarko Poutiainen
51cf33c206 Merge pull request #257 from jpoutiai/master
[RILMODEM] free before calling g_strdup to avoid mem leak
2014-10-10 11:08:50 +03:00
Jarko Poutiainen
08ddddc8d2 [RILMODEM] free before calling g_strdup to avoid mem leak
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-10-10 10:51:02 +03:00
Tommi Kenakkala
dc5eed9c24 Merge pull request #256 from tkenakka/log-gprs
[rilmodem] Logging improvements to gprs
2014-10-09 15:29:08 +03:00
Tommi Kenakkala
72e656e1fb [rilmodem] Logging improvements to gprs
Rilmodem gprs logic slightly touched to store latest reg status
always to gprs_data struct. Reg status logged only when it changes
instead of always.
2014-10-08 15:26:00 +03:00
Marcel Holtmann
8ebb17977b handsfree-audio: Fix broken coding style in switch statement 2014-09-20 16:13:45 +02:00
Tommi Kenakkala
af1717977d Merge pull request #255 from tkenakka/loggingnetreg
[rilmodem] Logging updates to netreg
2014-09-19 11:48:55 +03:00
Tommi Kenakkala
cb48cfa9c3 [rilmodem] Logging updates to netreg 2014-09-18 08:22:38 +03:00
Tommi Kenakkala
759c0bbde4 Merge pull request #253 from tkenakka/logging2
Minor logging improvements to rilmodem
2014-09-18 08:18:27 +03:00
Tommi Kenakkala
300695d069 Merge pull request #254 from tkenakka/ussdnotifycrash
[rilmodem] Fix ussd notify ofono crash
2014-09-18 08:02:31 +03:00
Tommi Kenakkala
f88c1c3ab2 [rilmodem] Fix ussd notify ofono crash
Fixup e23e6ac
2014-09-18 07:56:09 +03:00
Jarko Poutiainen
7415ef7418 Merge pull request #252 from mkuukkane/fix_ofono_cleanup
[ofono] Fix ofono cleanup
2014-09-17 10:11:18 +03:00
Tommi Kenakkala
887d9cf5d1 [rilmodem] Logging updates to radiosettings 2014-09-16 14:06:05 +03:00
Tommi Kenakkala
6231d5cc1c [rilmodem] Minor logging update to voicecall 2014-09-16 14:06:05 +03:00
Tommi Kenakkala
5b1f978a5c [rilmodem] Minor logging update to ussd 2014-09-16 14:06:05 +03:00
Marko Kuukkanen
1d1b9df844 [ofono] Fix ofono cleanup 2014-09-16 10:14:42 +03:00
Alban Crequy
7fb4899970 gdbus: Fix match rule for NameOwnerChanged
When subscribing to the D-Bus signal NameOwnerChanged from the bus driver,
specify the object path and the sender in the match rule. Otherwise, random
connections on the bus could impersonate the bus driver.
2014-09-15 18:03:46 +02:00
Luiz Augusto von Dentz
1e0c41889f gdbus: Fix crash when watch is toggled or disconnected
This partially reverts 510b32b7156625b9df737c916b7a7a5c6fb285b9 since it
still necessary to take a reference before calling dbus_watch_handle
since internally it can call watch_info_free as in the following trace:

 Invalid read of size 8
   at 0x121085: watch_func (mainloop.c:105)
   by 0x4C72694: g_main_context_dispatch (gmain.c:2539)
   by 0x4C729C7: g_main_context_iterate.isra.23 (gmain.c:3146)
   by 0x4C72DC1: g_main_loop_run (gmain.c:3340)
   by 0x120541: main (main.c:551)
 Address 0x5bbcd90 is 16 bytes inside a block of size 24 free'd
   at 0x4A079AE: free (vg_replace_malloc.c:427)
   by 0x4C7837E: g_free (gmem.c:252)
   by 0x4F708BF: dbus_watch_set_data (dbus-watch.c:614)
   by 0x4F70938: _dbus_watch_unref (dbus-watch.c:132)
   by 0x4F6E9A7: _dbus_transport_handle_watch (dbus-transport.c:884)
   by 0x4F59AFB: _dbus_connection_handle_watch (dbus-connection.c:1497)
   by 0x4F70AF9: dbus_watch_handle (dbus-watch.c:683)
   by 0x121084: watch_func (mainloop.c:103)
   by 0x4C72694: g_main_context_dispatch (gmain.c:2539)
   by 0x4C729C7: g_main_context_iterate.isra.23 (gmain.c:3146)
   by 0x4C72DC1: g_main_loop_run (gmain.c:3340)
   by 0x120541: main (main.c:551)
2014-09-08 05:48:48 +02:00
Luiz Augusto von Dentz
08e673050a gdbus: Fix crash when calling g_dbus_add_service_watch
If g_dbus_add_service_watch is called for service which bus name is
already known the following crash can happen:

invalid read of size 1
  at 0x4C2A2F2: strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
  by 0x4E97722: g_strdup (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x405B0C: update_name_cache (watch.c:435)
  by 0x405C37: update_service (watch.c:593)
  by 0x4E7A2A5: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E7A627: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E7AA39: g_main_loop_run (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4038EA: client_ready (test-gdbus-client.c:1014)
  by 0x4E9E5E0: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E9E7A5: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E9EB1A: g_test_run_suite (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x403614: main (test-gdbus-client.c:1058)
Address 0x5dbe5d0 is 0 bytes inside a block of size 7 free'd
  at 0x4C28577: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
  by 0x4E7FF7E: g_free (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x405B04: update_name_cache (watch.c:434)
  by 0x405C37: update_service (watch.c:593)
  by 0x4E7A2A5: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E7A627: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E7AA39: g_main_loop_run (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4038EA: client_ready (test-gdbus-client.c:1014)
  by 0x4E9E5E0: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E9E7A5: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E9EB1A: g_test_run_suite (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x403614: main (test-gdbus-client.c:1058)
2014-09-08 05:48:48 +02:00
Luiz Augusto von Dentz
1b1b1861ab Revert "gdbus: Don't include just added interfaces in GetManagedObjects"
This actually creates a problem since the code now does flush any pending
message on the queue any signal will be send right away before the
actual reply to GetManagedObjects which will not contain those interfaces.
2014-09-08 05:48:48 +02:00
Andrei Emeltchenko
8a4c29ca74 gdbus: Fix use after free
Refactor filter_data_remove_callback so that we do not iterate over
freed pointer.
2014-09-08 05:48:48 +02:00
Claudio Takahasi
9aeea028ed gdbus: Avoid reporting GDBusClient disconnect twice
No matter if disconnection was reported previously, g_dbus_client_unref()
was always calling service disconnect callback. This patch fix the
following scenario:
1) service disconnects from the bus
2) disconnect callback gets called
3) client calls g_dbus_client_unref(), disconnect callback is called
   again.
2014-09-08 05:48:48 +02:00
Tommi Kenakkala
0adfefa0c4 Merge pull request #250 from tkenakka/gprs
[rilmodem] Gprs fake timer fixes
2014-09-05 12:22:21 +03:00
Tommi Kenakkala
7c8db19341 Merge pull request #249 from jpoutiai/master
[RILMODEM] fix sim mem leak and code cleaning
2014-09-02 13:35:16 +03:00
Jarko Poutiainen
37ec5f9221 [RILMODEM] fix sim mem leak and code cleaning
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-09-02 13:31:45 +03:00
Tommi Kenakkala
d2d6f57b5f [rilmodem] Gprs fake timer fixes
Fixes timer cancelation logic and a mem leak on timer
callback data cleanup.
2014-09-02 13:23:42 +03:00
Tommi Kenakkala
6a272bf700 Merge pull request #248 from tkenakka/leakfixes
Mem leak fixes
2014-09-01 14:15:43 +03:00
Tommi Kenakkala
e1c8e2e2dc [rilmodem] Call fwd mem leak fix
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-09-01 13:10:54 +03:00
Tommi Kenakkala
5fb138dc13 [rilmodem] Nw selection mem leak fix
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-09-01 12:14:48 +03:00
Tommi Kenakkala
e2790ae176 Merge pull request #247 from tkenakka/leak
Fix rilmodem memory leaks
2014-08-29 10:10:01 +03:00
Tommi Kenakkala
516700c84c [rilmodem] Fix supplementary service mem leak
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-08-28 14:32:42 +03:00
Tommi Kenakkala
e23e6aceae [rilmodem] Fix ussd mem leaks
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-08-28 14:31:34 +03:00
Tommi Kenakkala
0532e2a6ea [rilmodem] Fix stk mem leaks 2014-08-28 14:31:11 +03:00
Tommi Kenakkala
ce2f0f3642 Merge pull request #246 from tkenakka/leaksms
[rilmodem] Mem leak fixes to sms sending and receiving
2014-08-27 14:34:52 +03:00
Tommi Kenakkala
0400b250c9 [rilmodem] Mem leak fixes to sms sending and receiving
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-08-27 12:39:37 +03:00
Tommi Kenakkala
bfcad4f346 Merge pull request #245 from tkenakka/master
Minor code cleanup
2014-08-27 09:32:30 +03:00
Tommi Kenakkala
9d49e2cee1 [rilmodem] Updated devinfo comments
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-08-26 11:05:15 +03:00
Tommi Kenakkala
c99e70f97a [rilmodem] Minor phonebook code cleanup
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-08-26 11:05:06 +03:00
Tommi Kenakkala
edc0035d18 Merge pull request #244 from jpoutiai/master
Fix memory leaks in sms and phonebook
2014-08-25 14:19:08 +03:00
Jarko Poutiainen
121f308cdb [RILMODEM] fix memory leak in sms sca query
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-08-25 10:58:26 +03:00
Jarko Poutiainen
2fcf1aee03 [RILMODEM] fix phonebook memory leaks
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-08-25 10:57:08 +03:00
Tommi Kenakkala
a14ebf50e0 Merge pull request #243 from jpoutiai/master
[RILMODEM] return failure to manufacturer and model queries
2014-08-25 10:24:59 +03:00
Jarko Poutiainen
1b0d419355 [RILMODEM] return failure to manufacturer and model queries
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-08-21 09:25:36 +03:00
Tommi Kenakkala
43f444db00 Merge pull request #242 from tigeli/master
[gprs] limit internet interface MTU by 1280
2014-08-14 09:42:10 +03:00
Pasi Sjöholm
1eb6243bc9 [gprs] limit internet interface MTU by 1280 2014-08-14 09:30:46 +03:00
Tommi Kenakkala
6ed50ecab7 Merge pull request #241 from jpoutiai/master
[RILMODEM] PB crash fix
2014-08-08 15:38:05 +03:00
Jarko Poutiainen
17ddc04788 [RILMODEM] PB crash fix add logging
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-08-08 10:26:27 +03:00
Jarko Poutiainen
4fd3c6386a [RILMODEM] PB crash fix
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-08-07 15:13:37 +03:00
Jarko Poutiainen
a069557b27 Merge pull request #240 from monich/data_calls
Fixed a problem with multiple data calls
2014-08-05 12:49:49 +03:00
Tommi Kenakkala
da81a85578 Merge pull request #239 from monich/warnings
Fixed compilation warnings
2014-08-04 15:17:11 +03:00
Denis Kenzior
22e892a22e build: Avoid warnings about _FORTIFY_SOURCE
Gentoo (and others) define _FORTIFY_SOURCE=2 by default.  We redefine
it, resulting in an error / configure failure.
2014-08-01 09:29:40 -05:00
Slava Monich
79e18f9d77 [ofono] Fixed a problem with multiple data calls
When two contexts were active simultaneously, deactivating one of them
would mark the second one as disconnected although its data call would
actually remain active.
2014-07-21 13:46:49 +03:00
Slava Monich
38f4886a97 Fixed compilation warnings 2014-07-21 13:43:50 +03:00
Denis Kenzior
361eed7b9a ublox: Minor style cleanup 2014-07-08 08:58:48 -05:00
Denis Kenzior
864efe1add ublox: Remove unneeded VENDOR flags
devinfo and netreg atoms don't use vendor specific behavior
2014-07-08 08:56:55 -05:00
Philip Paeps
0d8a06af30 plugins: new driver for u-blox SARA-U270 modems
This driver may also work (perhaps with more or less trivial changes)
with other u-blox modems (SARA, LISA, LEON) but this hasn't been tested.
2014-07-08 08:53:13 -05:00
Philip Paeps
293c701e25 atmodem: set the auth method for u-blox modems 2014-07-08 08:52:25 -05:00
Philip Paeps
cca3e085b3 sim: query u-blox PIN retries with AT+UPINCNT 2014-07-08 08:51:54 -05:00
Philip Paeps
7f29608feb udevng: add detection logic for u-blox modems 2014-07-08 08:50:20 -05:00
Denis Kenzior
1f3e30f1ba quectel: Minor style cleanup 2014-07-08 08:44:21 -05:00
Denis Kenzior
7ab4034bf4 quectel: Remove unneeded VENDOR flags
Only the sim atom has QUECTEL specific code
2014-07-08 08:43:01 -05:00
Philip Paeps
bb1984cabb plugins: add a new driver for Quectel UC15 modems 2014-07-08 08:42:05 -05:00
Philip Paeps
6df64cd1a9 gprs: add support for u-blox +UREG URCs 2014-06-30 14:03:08 -05:00
Philip Paeps
4a0831bc80 atmodem: add vendor u-blox 2014-06-30 13:59:46 -05:00
Denis Kenzior
b2bfdd69d2 atmodem: Minor style fixups 2014-06-30 13:44:40 -05:00
Philip Paeps
1588e7c082 sim: query Quectel UC15 PIN retries with AT+QPINC? 2014-06-30 13:35:19 -05:00
Philip Paeps
5cffd8af95 udevng: add detection logic for Quectel modems 2014-06-30 13:26:51 -05:00
Philip Paeps
d2f6ffc18d atmodem: add vendor Quectel 2014-06-30 13:26:25 -05:00
Sergio Checa Blanco
6369cc902c hfpmodem: Fix crash with more than two calls
A periodic CLCC polling is started when there is an ongoing multiparty
call and a new call appears in the system. A simple way to reproduce
the crashing scenario is:

1. Place a call.
2. Place a second call.
3. Create a multiparty call with both calls.
4. Place a third call (incoming or outgoing does not matter).
5. Disconnect HFP from the modem.

Within the function ciev_callheld_notify, the AT+CLCC command is also
invoked, thus a new cyclic CLCC polling is started, and it overwrites
the timer resource identifier stored in voicecall_data.clcc_source.
This means that there are several timers doing the CLCC polling, but
only one of those is under control, i.e. it can be removed through its
source identifier, hence a timer source leak.

This has a fatal consequence when the HFP modem is disconnected. The
function hfp_voicecall_remove stops the timer that is under control
before freeing the voicecall_data struct. However there are other timers
that are still active and will execute its handler poll_clcc afterwards.
Inside poll_clcc the driver_data is accessed, which is already NULL.

A solution for this is to avoid starting a CLCC polling if there is
already one active, i.e. clcc_source is not 0. By doing this the
uncontrolled timers will not cycle forever.
2014-06-30 13:22:10 -05:00
Marcel Holtmann
d05b718cc0 Release 1.15 2014-06-29 22:20:08 +02:00
Tommi Kenakkala
b154268fd9 Merge pull request #238 from tkenakka/merge1.14part
Merge upstream ofono 1.14 changes up to 9bbc986
2014-06-26 16:41:59 +03:00
Tommi Kenakkala
cb3a89a702 Merge remote-tracking branch 'martti/merge1.14' into merge1.14part 2014-06-26 13:58:35 +03:00
Tommi Kenakkala
133d92f265 Merge pull request #236 from special/master
[ofono] Encode SMS as UTF-16 instead of UCS-2
2014-06-26 08:56:29 +03:00
Philip Paeps
c144fadca6 gprs: provision the authentication method 2014-06-24 12:46:18 -05:00
Philip Paeps
532e8020e5 mbpi: add support for provisioning the auth method
Use the authentication method from the mobile-broadband-provider-info
database if it is specified and supported (we support CHAP and PAP).
Default to CHAP if the database does not specify a method (i.e.: the
previous behaviour).
2014-06-24 12:46:18 -05:00
Philip Paeps
310915429b include: add auth method to the provisioning API 2014-06-24 12:46:18 -05:00
Tommi Kenakkala
ad6fd49dbc Merge pull request #237 from martinjones/cfu_change
[ofono] Fix call forwarding unconditional change signal emission.
Wrong property names signalled for conditional call forwarding types when status of unconditional type changed.
2014-06-24 14:01:06 +03:00
Denis Kenzior
9285ec0d89 AUTHORS: Mention Philip's contributions 2014-06-21 12:05:43 -05:00
Philip Paeps
8cbe061c3b atmodem: set the PPP authentication method to use 2014-06-21 12:02:51 -05:00
Denis Kenzior
3e13676766 gprs: Make the code a bit easier to read 2014-06-21 12:02:05 -05:00
Philip Paeps
73831c3d76 gprs: make PPP authentication method configurable
Add a new "AuthenticationMethod" property to select between "pap"
and "chap" PPP authentication, defaulting to "chap" (i.e.: previous
behaviour).
2014-06-21 11:58:03 -05:00
Philip Paeps
7011dcdf2f include: add auth method to the gprs context API 2014-06-21 11:55:30 -05:00
Philip Paeps
f6341502c8 doc: describe the AuthenticationMethod property 2014-06-21 11:55:03 -05:00
Denis Kenzior
8edaaaf210 gatchat: Fix up minor coding style issues 2014-06-21 11:54:26 -05:00
Philip Paeps
a88662d23c gatchat: implement PAP authentication
Make the authentication method configurable, CHAP or PAP, defaulting to
CHAP (i.e.: previous behaviour).

Implementation details:

 o If PAP is configured, we NAK the CHAP authentication protocol option
   in LCP configuration requests and suggest PAP instead.  This works
   around the amusing requirement of 3GPP TS 29.061 that modems must
   send a forced positive acknowledgement of the authentication method
   tried (i.e.: the modem will successfully accept any CHAP handshake,
   but if the network only supports PAP, the modem will hang up
   when it tries and fails to activate the PDP context)

 o The PAP Authenticate-Request is resent a hard-coded three times at
   ten-second intervals.  This may be a bit too persistent.  Chances
   are if it doesn't work the first time, it'll never work, but the
   RFC insists that we MUST retry.
2014-06-21 11:50:34 -05:00
Denis Kenzior
1dd8580930 AUTHORS: Mention Sergio's contributions 2014-06-21 11:46:28 -05:00
Sergio Checa Blanco
65be2b344c hfpmodem: Split AT+VTS command into multiple +VTS
According to the standard "3GPP 27.007 v6.8.0" Appendix C.2.11,
when sending multiple DTMF characters, these must go in individual
+VTS commands for each tone. This adopts the AT modem approach.

Before: AT+VTS=1234\r
After:  AT+VTS=1;+VTS=2;+VTS=3;+VTS=4\r
2014-06-21 11:45:44 -05:00
Martin Jones
888e857779 [ofono] Fix call forwarding unconditional change signal emission.
When toggling cfu the change signals for the other types didn't have the
prefix applied.
2014-06-20 02:01:37 +00:00
Tommi Kenakkala
e189cd138b Merge pull request #235 from jpoutiai/sms-on-sim
[RILMODEM] initial support to read and delete sms from sim (class2, voicemail mwi)
2014-06-18 16:21:14 +03:00
John Brooks
6b8b5d29a1 [ofono] Encode SMS as UTF-16 instead of UCS-2
UCS-2 is an older 16-bit encoding compatible with the unicode BMP.
UTF-16 extends UCS-2 to add support for surrogate pairs and the rest of
the unicode set. All valid UCS-2 text is also valid UTF-16 text, and all
UTF-16 text not containing surrogate pairs is valid UCS-2.

We decode incoming SMS as UTF-16 instead of UCS-2 to add support for
these extended characters. We should do the same for encoding outgoing
SMS messages.
2014-06-18 06:04:38 -06:00
Jarko Poutiainen
960ef29014 [RILMODEM] removing unnecessary empty lines and null check
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-06-17 15:14:10 +03:00
Jarko Poutiainen
30f3dd2c53 [RILMODEM] change cb_data_new2 to abort in failure
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-06-17 15:13:49 +03:00
Jarko Poutiainen
feb1126123 [RILMODEM] initial support to read and delete sms from sim
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-06-17 11:57:44 +03:00
Tommi Kenakkala
420651829a Merge pull request #234 from mkuukkane/remove-dundee
Remove dundee from ofono compilation.
2014-06-16 12:32:05 +03:00
Jarko Poutiainen
0835875b65 Merge pull request #233 from tkenakka/netregfix
[rilmodem] Null netreg pointer on netreg remove
2014-06-13 15:00:28 +03:00
Tommi Kenakkala
153599eb70 [rilmodem] Null netreg pointer on netreg remove
Netreg driver has a static copy of the netreg pointer.
Missing NULLing may cause problems on corner cases after
netreg is freed (when core atom is flushed).

Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-06-13 10:52:24 +03:00
Marko Kuukkanen
fafef8bfd3 [ofono] Remove dundee (service) 2014-06-12 10:40:27 +03:00
Alfonso Sanchez-Beato
62c34467a2 test: Adapt data test scripts to multi-modem
Some tests scripts were not ready to handle situations with more than
one modem present. This change fixes the data context scripts.
2014-06-10 23:36:09 -05:00
Alfonso Sanchez-Beato
d9f252fb61 test: Adapt voice call test scripts to multi-modem
Some tests scripts were not ready to handle situations with more than
one modem present. This change fixes the scripts that handle voice
calls.
2014-06-10 23:23:51 -05:00
Jarko Poutiainen
3bce306f6e Merge pull request #231 from jpoutiai/gprs
[RILMODEM] gprs set detach notified only for callback
2014-06-09 10:14:00 +03:00
Tommi Kenakkala
68767f6ea2 Merge pull request #232 from mkuukkane/ussd
[rilmodem] Don't send <CR> with USSD string
2014-06-06 15:05:58 +03:00
Marko Kuukkanen
a3cd7b0898 [rilmodem] Don't send <CR> with USSD string 2014-06-06 15:00:04 +03:00
Jarko Poutiainen
d0364f89cd [RILMODEM] gprs set detach notified only for callback
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-06-05 15:05:58 +03:00
Jarko Poutiainen
9aa8375233 Merge pull request #230 from martinjones/master
[voicecall] Cancel pending DTMF tones before hanging up call.
2014-06-04 12:57:54 +03:00
Martin Jones
77b3adfd60 [voicecall] Cancel pending DTMF tones before hanging up call. 2014-06-04 09:27:43 +00:00
Marko Kuukkanen
b4bb7e72d8 Merge pull request #229 from mkuukkane/transfer
Explicit call transfer rilmodem implementation
2014-06-02 14:23:45 +03:00
Marko Kuukkanen
8e20975660 [rilmodem] Explicit call transfer driver implementation 2014-06-02 08:39:55 +03:00
Marko Kuukkanen
0e8a53bdf0 [test] Add test script for explicit call transfer 2014-06-02 08:38:31 +03:00
Denis Kenzior
815d62888f hfp: Fix case where RING never arrives 2014-05-30 12:25:23 -05:00
Jarko Poutiainen
9a29fdde06 Merge pull request #228 from jpoutiai/master
Refactoring rilmodem gprs implementation
2014-05-30 14:09:37 +03:00
Jarko Poutiainen
269fa3db0e [RILMODEM] fake also roaming
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-27 12:42:56 +03:00
Jarko Poutiainen
64dab08751 [RILMODEM] code review and checkpatch cleaning
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-27 12:39:50 +03:00
Jarko Poutiainen
7a72726d9a [RILMODEM] code review and checkpatch cleaning
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-27 12:39:39 +03:00
Jarko Poutiainen
b6fb89c3a0 [RILMODEM] refactor gprs-context driver
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-26 11:17:34 +03:00
Jarko Poutiainen
d51d858cd6 [RILMODEM] refactor gprs driver
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-26 11:17:15 +03:00
Tommi Kenakkala
24d1be80c5 Merge pull request #227 from tkenakka/logging
[rilmodem] Improve ril.c logging
2014-05-26 09:23:03 +03:00
Tommi Kenakkala
19c2a6fc64 [rilmodem] Improve ril.c logging
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-05-23 23:58:41 +03:00
Denis Kenzior
35feae07e5 hfp: Use proper prefix
Otherwise the BCS command can consume unsolicited notifications.

ofonod[3270]: < \r\n+BCS: 2\r\n
ofonod[3270]: > AT+BCS=2\r
ofonod[3270]: < \r\n+CIEV: 1,1\r\n
ofonod[3270]: < \r\n+CIEV: 2,0\r\n
ofonod[3270]: < \r\nOK\r\n
2014-05-21 12:08:37 -05:00
Martti Piirainen
6e3236b739 Merge pull request #226 from jpoutiai/master
more default logging
2014-05-20 14:21:43 +03:00
Martti Piirainen
22b20efdc4 [test] Port remaining test scripts to Python3 2014-05-20 12:01:32 +03:00
Martti Piirainen
ce1ed053fd [rpm] Make test scripts depend on Python3 2014-05-20 11:22:13 +03:00
Martti Piirainen
e9d562e4a3 Merge branch 'ofono1.14' into merge1.14
Conflicts:
	ofono/test/test-ss-control-cb
	ofono/unit/test-simutil.c
2014-05-20 11:21:19 +03:00
Jarko Poutiainen
e5223ac8af [RILMODEM] add more logging
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-19 10:28:18 +03:00
Jarko Poutiainen
9505b6baf3 [RILMODEM] add more logging
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-19 10:28:04 +03:00
Jarko Poutiainen
4c268731b9 [RILMODEM] add more logging
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-19 10:27:50 +03:00
Martti Piirainen
5b158c3a28 Merge pull request #224 from jpoutiai/master
[RILMODEM] prevent ofono crash when sim removed while reading
2014-05-19 09:51:34 +03:00
Tommi Kenakkala
9745d202d3 Merge pull request #225 from marttipiirainen/nettime
Fix crash in network time plugin
2014-05-15 14:15:10 +03:00
Martti Piirainen
2329468e25 [nettime] Prevent crash if MNC or MCC is missing 2014-05-15 07:36:07 +03:00
Martti Piirainen
2b352aedb4 [nettime] Export test script to .rpm 2014-05-15 07:21:07 +03:00
Jarko Poutiainen
b319c77bcc [RILMODEM] prevent ofono crash when sim removed while reading
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-14 14:08:21 +03:00
Martti Piirainen
4b95656d72 Merge pull request #223 from jpoutiai/master
[RILMODEM] hardening phonebook driver implementation
2014-05-14 13:57:51 +03:00
Jarko Poutiainen
b3dc0d0146 [RILMODEM] hardening phonebook driver implementation
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-05-12 15:08:28 +03:00
Martti Piirainen
319866c450 Merge pull request #222 from marttipiirainen/mbpi_primary
Use "primary provider" information from MBPI
2014-05-12 09:21:26 +03:00
Martti Piirainen
2847cfcd03 [provision] Prioritize "primary" providers (MNOs) over MVNOs 2014-05-11 11:04:58 +03:00
Martti Piirainen
65501536d3 [mbpi] Parse provider's "primary" property 2014-05-11 11:01:56 +03:00
Martti Piirainen
eef58998c0 [gprs-provision] Add field to distinguish primary MNO from MVNO 2014-05-11 10:32:05 +03:00
Tommi Kenakkala
571d440c14 Merge pull request #220 from jpoutiai/master
[SRC] fix incorrect CF state after CFU erasure
2014-05-05 08:17:19 +03:00
Jarko Poutiainen
25fc82a073 [SRC] fix incorrect CF state after CFU erasure
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-04-30 14:41:45 +03:00
Tommi Kenakkala
e50518effa Merge pull request #219 from tkenakka/conffix
[rilmodem] Fix ratmode bad conf file handling
2014-04-30 09:44:16 +03:00
Tommi Kenakkala
84e1386978 [rilmodem] Fix ratmode bad conf file handling
g_key_file_load_from_file loads also dirs, if a bad file/dir was
picked up first then logic deduced wrong the need for ratmode reconfig.

Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-04-30 09:35:52 +03:00
Slava Monich
0cdd483894 Merge pull request #218 from monich/leaks
[rilmodem] Plugged a few memory leaks
2014-04-29 16:14:44 +03:00
Slava Monich
7dbeba0e83 Merge pull request #217 from monich/simsms
[push-forwarder] Fixed sim/sms watch id mixup
2014-04-29 16:14:01 +03:00
Slava Monich
d7cf952a16 [rilmodem] Plugged a few memory leaks 2014-04-29 15:37:14 +03:00
Slava Monich
e8379285b3 [push-forwarder] Fixed sim/sms watch id mixup 2014-04-29 14:55:01 +03:00
Tommi Kenakkala
f9a91c8453 Merge pull request #216 from jpoutiai/master
Disable stack trace from command line
2014-04-28 15:54:20 +03:00
Jarko Poutiainen
882f75b500 [SRC] Disable stack trace from command line ofono.service.in
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-04-28 15:32:33 +03:00
Jarko Poutiainen
5b6ddee098 [SRC] Disable stack trace from command line ofono.h
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-04-28 12:57:05 +03:00
Jarko Poutiainen
5cbf0de041 [SRC] Disable stack trace from command line main.c
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-04-28 12:56:45 +03:00
Jarko Poutiainen
8ce12b2232 [SRC] Disable stack trace from command line log.c
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-04-28 12:56:21 +03:00
Jarko Poutiainen
62d42e0407 Merge pull request #215 from lpotter/master
[rilmodem] Fix gprs state after offline mode.
2014-04-28 11:09:52 +03:00
Lorn Potter
5053a342e7 [rilmodem] Fix gprs state after offline mode. 2014-04-23 10:54:57 +10:00
Andrew Earl
9bbc98651f handsfree: correct crash on connect of hfp 2014-04-22 13:10:32 -05:00
Martti Piirainen
5c53260938 Merge pull request #213 from marttipiirainen/mbpi3
Take Service Provider Name into account in MBPI provisioning
2014-04-22 15:11:36 +03:00
Martti Piirainen
e3e691fb48 Merge pull request #214 from marttipiirainen/ringback
[voicecall] Inform client when local ringback tone is needed
2014-04-22 13:54:13 +03:00
Martti Piirainen
8fa99a07e8 [provision] Take SPN into account when finding APNs 2014-04-17 08:14:08 +03:00
Slava Monich
23f92a5b3e [mbpi] Parse gsm provider name 2014-04-17 07:32:36 +03:00
Slava Monich
94494f3a63 [provision] Fixed memory leak 2014-04-16 16:07:40 +03:00
Martti Piirainen
098b3d4a64 [unit] Add provisioning tests 2014-04-16 16:07:29 +03:00
Martti Piirainen
cfeb58f2a8 [provision] Expose provision_get_settings() in header (for testability) 2014-04-16 16:07:21 +03:00
Martti Piirainen
5f821b4a9a [voicecall] Inform client when local ringback tone is needed
In some networks, MO calls do not get the "alerting" tone in-band, so the device needs to play one locally.

This commit adds a "voice call agent" API. It currently contains only the ringback tone notification, but can be extended later.
2014-04-16 15:31:45 +03:00
Denis Kenzior
516165c311 handsfree: Rename driver function
To be more consistent with others in the same file
2014-04-10 10:04:36 -05:00
Denis Kenzior
b37f5e842d handsfree: Simplify logic 2014-04-10 10:04:12 -05:00
Andrew Earl
e7f055385f hfp: Add CNUM query to handsfree interface for subscriber number 2014-04-10 09:52:11 -05:00
Denis Kenzior
8cfcfa4519 handsfree: Rename variable 2014-04-10 09:43:47 -05:00
Denis Kenzior
ca3ae87d0a handsfree: Reflow logic 2014-04-10 09:43:44 -05:00
Denis Kenzior
02138901d3 handsfree: Remove function
No need for one line functions that are only used once
2014-04-10 09:43:41 -05:00
Denis Kenzior
24e87d2580 handsfree: Rename function
No need for the ofono_ prefix here
2014-04-10 09:31:58 -05:00
Denis Kenzior
057c4d788f handsfree: Remove unneeded variable 2014-04-10 09:29:32 -05:00
Denis Kenzior
805c3068be handsfree: Remove unneeded variable i 2014-04-10 09:29:11 -05:00
Denis Kenzior
eb4fd9f5aa handsfree: style fixes for previous commit 2014-04-10 09:25:30 -05:00
Andrew Earl
8327d528a9 hfp: Add subscriber number to handsfree properties 2014-04-10 09:21:23 -05:00
Andrew Earl
7420d327e3 include: Add subscriber number to handsfree API 2014-04-10 09:18:15 -05:00
Andrew Earl
e589094113 doc: Add subscriber number to handsfree-api 2014-04-10 09:17:47 -05:00
Martti Piirainen
533d248288 Merge pull request #210 from nemomobile-packages/next
Merge various improvements from 'next' to 'master'
2014-04-08 10:54:18 +03:00
Martti Piirainen
4f512b6e56 Merge pull request #209 from jpoutiai/next
[RILMODEM] fix cf query callback list handling
2014-04-07 10:18:48 +03:00
Martti Piirainen
ce3a5e5a0b Merge pull request #204 from monich/ril_delayed_register
[rilmodem] Actually remove delayed register timer
2014-04-07 10:13:28 +03:00
Martti Piirainen
c97ef76c93 Merge pull request #205 from monich/ril_oemraw_delayed_register
[rilmodem] Remove delayed register timer in ril_oemraw_remove
2014-04-07 10:13:11 +03:00
Jarko Poutiainen
95659d7c49 [RILMODEM] fix cf query callback list handling
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-04-04 15:03:08 +03:00
Tommi Kenakkala
eb986f49e4 Merge pull request #208 from tkenakka/next
[ofono][dundee] At startup order dundee after dbus instead of syslog.
2014-04-01 15:27:26 +03:00
Tommi Kenakkala
4691d385c0 [ofono][dundee] At startup order dundee after dbus instead of syslog.
According to systemd documentation
"Newer systemd versions (v35+) do not support non-socket-activated syslog
daemons anymore and we do no longer recommend people to order their units
after syslog.target."

Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-04-01 13:15:53 +03:00
Martti Piirainen
0ddebfea70 Merge pull request #207 from tkenakka/nwlock
[rilmodem] Network lock depersonalisation support
2014-03-31 07:12:49 +03:00
Tommi Kenakkala
2d1f2b0650 [rilmodem] Network lock depersonalisation support
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-03-28 13:52:56 +02:00
Martti Piirainen
0ca5c87999 Merge pull request #206 from marttipiirainen/voice_busy
[rilmodem] Fine-tune disconnect reasons for MO calls
2014-03-28 12:33:58 +02:00
Martti Piirainen
e3dcd67a1b [rilmodem] Fine-tune disconnect reasons for MO calls 2014-03-28 08:04:23 +02:00
Denis Kenzior
ca5b269002 AUTHORS: Mention Jussi's contributions 2014-03-27 09:51:49 -05:00
Denis Kenzior
910ec60927 phonesim: Fixup whitespace 2014-03-27 09:51:49 -05:00
Jussi Pakkanen
5f76525961 phonesim: Add conf file override
OFONO_PHONESIM_CONFIG allows the configuration file location to be
overriden from the default $CONFIGDIR/phonesim.conf (typically /etc)
2014-03-27 09:51:49 -05:00
Slava Monich
99b9099082 [rilmodem] Remove delayed register timer in ril_oemraw_remove 2014-03-27 16:42:22 +02:00
Slava Monich
ec74da107d [rilmodem] Actually remove delayed register timer in ril_call_barring_remove 2014-03-27 16:33:47 +02:00
Jarko Poutiainen
50f146939f Merge pull request #203 from tkenakka/next
[rilmodem] Minor rilmodem/sim.c mem leak fix
2014-03-27 11:06:56 +02:00
Tommi Kenakkala
e7a07b4694 [rilmodem] Minor rilmodem/sim.c mem leak fix
Signed-off-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
2014-03-27 10:58:32 +02:00
Martti Piirainen
461d18f4a3 Merge pull request #195 from marttipiirainen/unit
Unit test improvements
2014-03-26 13:07:47 +02:00
Jussi Kangas
16ea57247d [rilmodem] Check if really network registration status is really searching
If connection drops to searching and only voice call registration
status changes to roaming, with current implementation it is possible
to get through roaming allowed check in core. This prevents it.

Signed-off-by: Jussi Kangas <jussi.kangas@oss.tieto.com>
2014-03-26 10:56:22 +02:00
Jarko Poutiainen
837fa1f8f1 Merge pull request #202 from monich/mms-pdu
[gprs] Limit MMS interface MTU by 1280
2014-03-25 15:11:34 +02:00
Slava Monich
1469b52db9 [gprs] Limit MMS interface MTU by 1280
This improves interoperability with certain operators, notably Saunalahti.
The limit of 1280 was chosen because it's the minimum MTU required from
IPv6 capable networks.
2014-03-25 15:05:55 +02:00
Claudio Takahasi
6fdcfc309c gdbus: Add g_dbus_proxy_set_property_array
This patch adds a new gdbus utility function to allow setting a property
of fixed, and non-fixed values array.
2014-03-24 14:27:51 -07:00
Denis Kenzior
4585969568 he910: Fix unused variable warning
plugins/he910.c: In function ‘qss_query_cb’:
plugins/he910.c:174:21: error: unused variable ‘data’
[-Werror=unused-variable]
2014-03-20 12:55:20 -05:00
Denis Kenzior
f8819b588b he910: Switch to permissive parser
Seems the CCFC implementation on Telit firmware is not v.250 compliant:
ofonod[445]: Aux: > AT+CCFC=0,2\r
ofonod[445]: Aux: < \r\n\r\n+CCFC:0,7\r\n\r\nOK\r\n
2014-03-19 10:30:10 -05:00
Denis Kenzior
c3f528908d he910: Fixup SIM detection
In certain cases the #QSS notification is never sent, or sent too early.
Make sure that we enable #QSS notification only after the modem has been
set as powered.  Also make sure that we explicitly query #QSS in case we
missed the earlier #QSS notification.
2014-03-19 10:30:05 -05:00
Denis Kenzior
29fefe6450 hfp: Use enum from hfp.h 2014-03-19 10:24:57 -05:00
Denis Kenzior
65e6df8e50 hfp: Fixup variable names 2014-03-19 10:20:28 -05:00
Krzysztof Wilk
8a7b8b0521 hfp: Add CHLD features to drver data 2014-03-19 10:19:53 -05:00
Denis Kenzior
5705a0078e handsfree: Fixup variable names 2014-03-19 10:19:35 -05:00
Krzysztof Wilk
b2b3943717 hfp: extend Features to three way calling and CHLD 2014-03-19 10:15:55 -05:00
Krzysztof Wilk
6b8f46a916 include: Declaration function to set CHLD features 2014-03-19 10:13:15 -05:00
Krzysztof Wilk
2e78ea1830 hfp: Define hfp_ag_chld_feature 2014-03-19 10:12:16 -05:00
Krzysztof Wilk
dafbd0da25 doc: Extend Features property 2014-03-19 10:11:40 -05:00
Martti Piirainen
c156bbf14b Merge pull request #200 from jkangas/master
Request for pulling prevention of modem data reseting if modem is not registered to master branch
2014-03-18 07:58:12 +02:00
Slava Monich
a724d6bc9d Merge pull request #199 from monich/push-length
Fix for push data length
2014-03-17 11:09:07 +02:00
Slava Monich
21b7c9bc97 [push-forwarder] Fixed push data length
Push handlers were receiving a few extra bytes beyond the end of valid data.
2014-03-16 16:11:10 +02:00
Denis Kenzior
13ce99e360 AUTHORS: Mention Alfonso's contributions 2014-03-14 12:24:54 -05:00
Alfonso Sanchez-Beato
352e3ebb76 unit: Fix test to use valid EF_PNN
test-simutil was not using EF_PNN files with a valid format.
2014-03-14 12:24:26 -05:00
Alfonso Sanchez-Beato
46de4df677 simutil: Fix EF_PNN access
EF_PNN was not being read properly (see TS 24.008, section 10.5.3.5a,
for network names format), which affected the displayed PLMN name for
some MVNOs. Some modems already read the file and return the right
string: these do not show the problem.
2014-03-14 12:24:26 -05:00
Denis Kenzior
6a96eea978 stktest: Remove some unneeded output 2014-03-14 10:32:32 -05:00
Denis Kenzior
ebe25412a4 test: Make sure test-stk-menu works with python3 2014-03-14 10:32:06 -05:00
Jussi Kangas
fc04b4cef2 [rilmodem] Do not remove unexisting modem data
If ril connection fails when called from reattempt, timer interval
should not be reset. In that case method called by timer does not
return false and that leads to double timer. If modem data does
not exist in the core it should not be removed.

Signed-off-by: Jussi Kangas <jussi.kangas@oss.tieto.com>
2014-03-14 15:16:42 +02:00
Martti Piirainen
88f42f44c1 [unit] SMS decoding tests for Unicode 2014-03-14 09:05:22 +02:00
Martti Piirainen
2aed3c3f66 [unit] Fix EF_PNN unit test
Correct the encoding of the existing test case, and add a second test (the latter is based on Canonical rilmodem code).
2014-03-14 09:05:22 +02:00
Martti Piirainen
9c9028b164 [rpm] Run unit tests before creating .rpm 2014-03-14 09:05:22 +02:00
Martti Piirainen
6d35002f11 Merge pull request #197 from nemomobile-packages/next
Merge quite a many things from 'next' to 'master'
2014-03-13 17:23:44 +02:00
Tommi Kenakkala
803dda81ea Merge pull request #196 from marttipiirainen/next
Merge latest upstream oFono up to commit 278dba2ec8.
2014-03-13 13:19:33 +02:00
Slava Monich
31f8abf851 mbpi: Pop subparser stack after mmsc and mmsproxy 2014-03-13 13:19:33 +02:00
Marcel Holtmann
8f4aefa945 gatchat: Fix handling of WRITE_SCHEDULER_DEBUG 2014-03-13 13:19:33 +02:00
Tommi Kenakkala
58e133cbf5 Merge pull request #186 from ptakalok/call_forw
[rilmodem] Change call forwarding default service class per RIL design
2014-03-13 13:19:32 +02:00
Slava Monich
6c3992aa86 include: Be more const-correct in ofono_dbus_* 2014-03-13 13:19:32 +02:00
Jarko Poutiainen
c3352608c6 Merge pull request #192 from jkangas/next
Request for pulling direct SPDI reading without service table check to next branch
2014-03-13 13:19:32 +02:00
Petri Takalokastari
5da34324ca [rilmodem] Change call forwarding default service class per RIL design
RIL expects service class BEARER_CLASS_VOICE in
RIL_REQUEST_SET_CALL_FORWARD and SERVICE_CLASS_NONE in
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS.

Signed-off-by: Petri Takalokastari <petri.takalokastari@oss.tieto.com>
2014-03-13 13:19:32 +02:00
Miia Leinonen
b64a5c2655 Merge pull request #191 from jkangas/next
Request for pulling cbs disabling and handling of non-existent response fix to next branch
2014-03-13 13:19:32 +02:00
Jussi Kangas
e11c1afdd3 [network] Do not check the service table before reading SPDI
Although it is correct to check support for service provider display
info from service table before reading, operators don't necessarily
care about such details. Direct reading is the surest way to find out
if the info is present or not. If it is not, ofono will just get
failure from modem.

Signed-off-by: Jussi Kangas <jussi.kangas@oss.tieto.com>
2014-03-13 13:19:32 +02:00
Jussi Kangas
9834debe92 Merge pull request #190 from leinomii/next
[rilmodem] Enable SIM operations in expired SIM cards
2014-03-13 13:19:31 +02:00
Jussi Kangas
2d75463ae2 [rilmodem] Do not handle unexisting response
Running disable-modem test case seems to cause assert triggering
in gril in developer mode. Since method seems to survive just fine
from handling of zero length command queue, removing the assert
helps testing in developer mode.

Signed-off-by: Jussi Kangas <jussi.kangas@oss.tieto.com>
2014-03-13 13:19:31 +02:00
Miia Leinonen
95b95f9af9 Merge pull request #189 from jkangas/next
Request for pulling usage of preset paths when reading ADN records to next branch
2014-03-13 13:19:31 +02:00
Miia Leinonen
d43ec9e0ed [rilmodem] Enable SIM operations also in outdated SIM cards
Following Android example for interpreting RIL_APPSTATE_ILLEGAL
as RIL_APPSTATE_READY. E.g. SIM cards that are expired can go to
this state. By mapping the state to READY we are still able to
use the SIM features such as reading phonebook. Network access
will not be permitted with such SIM card regardless or READY
state.

Signed-off-by: Miia Leinonen <miia.leinonen@oss.tieto.com>
2014-03-13 13:19:31 +02:00
Jussi Kangas
8bc1e0a300 [rilmodem] Disable cbs support
We don't know for sure if registering to listen CBS messages
causes unnecessary power consumption with our modem but since we are
not really supporting it it's better to disable the feature for now.

Signed-off-by: Jussi Kangas <jussi.kangas@oss.tieto.com>
2014-03-13 13:19:31 +02:00
Martti Piirainen
b489dc995b Merge pull request #188 from jkangas/next
Request for pulling EFPNN 7-bit unpacking before trying convert it to UTF8 to next branch
2014-03-13 13:19:31 +02:00
Jussi Kangas
d25fd17f09 [rilmodem] Set the path for all ADN record readings
Core does not list EFpbr to it's EF list so we cannot trust
sim_ef_db_get_path_3g or sim_ef_db_get_path_2g to find the
correct path. In order to read the 2nd and later phonebook
records we have to define the path in rilmodem level.

Signed-off-by: Jussi Kangas <jussi.kangas@oss.tieto.com>
2014-03-13 13:19:31 +02:00
Alfonso Sanchez-Beato
73a794e9f6 [src] Fix EF_PNN access
EF_PNN was not being read properly, which affected the displayed PLMN
name for some MVNOs. Some modems already read the file and return the
right string: these do not show the problem.
2014-03-13 13:19:31 +02:00
Martti Piirainen
df0e72c780 Merge pull request #180 from monich/split_wsp_payload
[push-forwarder] Split WSP payload
2014-03-13 13:19:30 +02:00
Jarko Poutiainen
7cdaa7cd13 Merge pull request #185 from marttipiirainen/next
Make libwspcodec dependency conditional
2014-03-13 13:19:30 +02:00
Slava Monich
558a6639d6 [push-forwarder] Split WSP payload
Instead of sending the whole WSP datagram to the handler we now send
content type string and WSP payload data. This way push handler won't
have to parse WSP headers just to extract the payload.
2014-03-13 13:19:30 +02:00
Jarko Poutiainen
5f2e8e24f0 Merge pull request #182 from jkangas/next
Request for pulling tech pref config possibility based on mobile country code to next branch
2014-03-13 13:19:30 +02:00
Martti Piirainen
31f85495dc [configure] Make libwspcodec dependency conditional
Signed-off-by: Martti Piirainen <martti.piirainen@oss.tieto.com>
2014-03-13 13:19:30 +02:00
Tommi Kenakkala
689d7358ba Merge pull request #183 from marttipiirainen/next
Make the push-forwarder plugin configurable
2014-03-13 13:19:30 +02:00
Jussi Kangas
b3ca644f1d [rilmodem] Mobile country code configuration
Enable limiting radio technology based on mobile country code found
from ICC.

Signed-off-by: Jussi Kangas <jussi.kangas@oss.tieto.com>
2014-03-13 13:19:30 +02:00
Martti Piirainen
1e811dd49a [configure] Make the push-forwarder plugin configurable
Signed-off-by: Martti Piirainen <martti.piirainen@oss.tieto.com>
2014-03-13 13:19:30 +02:00
Tommi Kenakkala
9a520a7825 Merge pull request #179 from ptakalok/mosms
[rilmodem] Refine SMS sending response value handling
2014-03-13 13:19:29 +02:00
Tommi Kenakkala
2f51bc9e62 Merge pull request #178 from marttipiirainen/next
[gril] Fix 'unused variable' compiler warning
2014-03-13 13:19:29 +02:00
Petri Takalokastari
d8dd65b579 [rilmodem] Refine SMS sending response value handling
By this change, the SMS is resent only  in cases it is worth of retrying.

Signed-off-by: Petri Takalokastari <petri.takalokastari@oss.tieto.com>
2014-03-13 13:19:29 +02:00
Martti Piirainen
1e139cb4c6 Merge pull request #177 from monich/create-push-forwarder-d
Create /etc/ofono/push_forwarder.d directory
2014-03-13 13:19:29 +02:00
Martti Piirainen
68c0a9f164 [gril] Fix 'unused variable' compiler warning
Signed-off-by: Martti Piirainen <martti.piirainen@oss.tieto.com>
2014-03-13 13:19:29 +02:00
Slava Monich
dfe0f280de Create /etc/ofono/push_forwarder.d directory 2014-03-13 13:19:20 +02:00
Tommi Kenakkala
5a54a71fd8 Merge pull request #171 from monich/push-forwarder-next
Push forwarder plugin
2014-03-13 13:18:27 +02:00
Tommi Kenakkala
0f39bdc9c3 Merge pull request #169 from monich/create-mms-context-after-upgrade
Create and provision MMS context if it doesn't exist
2014-03-13 13:18:27 +02:00
Slava Monich
24e8514c55 Push forwarder plugin 2014-03-13 13:18:27 +02:00
Tommi Kenakkala
f1b689ed3c Merge pull request #176 from ptakalok/language
[rilmodem] Set current UI system language to environment variable
2014-03-13 13:18:27 +02:00
Slava Monich
e5df37be4b [gprs] Create and provision MMS context if it doesn't exist
This is necessary to handle the upgrade scenario from an ofono version
that doesn't support MMS to the one that does.
2014-03-13 13:18:27 +02:00
Petri Takalokastari
a61a8cc183 [rilmodem] Set current UI system language to environment variable
Read current terminal UI language from configuration file and set it as
environment variable for provide local information proactive command.

Signed-off-by: Petri Takalokastari <petri.takalokastari@oss.tieto.com>
2014-03-13 13:18:27 +02:00
Martti Piirainen
e25b5b13f9 Merge pull request #166 from marttipiirainen/next
[build] Fix network time plugin build issues
2014-03-13 13:18:26 +02:00
Jussi Kangas
3f3375442d Merge pull request #170 from leinomii/next
Clean useless cast and improve handle_unsol_req readability
2014-03-13 13:18:26 +02:00
Jussi Kangas
782669b412 Merge pull request #164 from jkangas/next
Ensure that AP list has one INTERNET and one MMS access point
2014-03-13 13:18:26 +02:00
Martti Piirainen
5a401c8b50 [build] Fix network time plugin build issues
Link clock functions explicitly to the POSIX realtime library when using glibc version < 2.17 (otherwise, some compilation environments implicitly link libpthread, others fail). Also, there was a typo that broke the '--disable-nettime' configure option.

Signed-off-by: Martti Piirainen <martti.piirainen@oss.tieto.com>
2014-03-13 13:18:26 +02:00
Miia Leinonen
3ac41bc759 [gril] Clean useless cast and improve handle_unsol_req readability 2014-03-13 13:18:26 +02:00
Slava Monich
5af079bd03 Ensure that AP list has one INTERNET and one MMS access point
Also, minimized differences with upstream version of provision.c
2014-03-13 13:18:26 +02:00
Denis Kenzior
c94c4fad54 AUTHORS: Mention Martin's contributions 2014-03-11 19:34:45 -05:00
Martin Pitt
c027ab9fbc test: Convert to Python 3
Change raw_input() to input() and unicode to str. This is *not*
compatible with Python 2. Update the hashbangs to run with Python 3.
2014-03-11 19:34:08 -05:00
Martin Pitt
ad4f90684f test: Move from static gobject bindings to GI
Use GLib gobject-introspection bindings so that we can also use the
scripts with Python 3.
2014-03-11 19:33:16 -05:00
Martin Pitt
5bf5cf8ddd test: Replace obsolete has_key() with "in"
In order to also work with Python 3
2014-03-11 19:33:04 -05:00
Martin Pitt
0393a41e35 test: Make exceptions compatible with Python 3
Use "except Type as var" syntax to work with both Python >= 2.6
and Python 3.
2014-03-11 19:32:46 -05:00
Martin Pitt
0c1fcd2b50 test: Make print calls compatible with Python 3
Turn print calls into print() function calls and avoid using
comma-separated arguments, so that they work and look the same with
both Python 2 and 3.
2014-03-11 19:32:18 -05:00
Denis Kenzior
c54e4763f8 he910: Fix whitespace 2014-03-10 11:53:22 -05:00
Claudio Takahasi
ea2b34eacd gdbus: Add g_dbus_client_set_ready_watch()
This patch adds a new gdbus helper to notify the clients that
GetManagedObjects reply was received and the last proxy has been
informed previously by the proxy_added callback.
2014-03-06 09:36:48 -08:00
Denis Kenzior
472e6650d4 AUTHORS: Mention Tony's contributions 2014-03-05 08:51:06 -06:00
Tony Espy
201d34b0a1 idmap: use UL for bitshift literals
The current bitshift logic in idmap incorrectly uses
the literal 1 for the value to shift in idmap_alloc(),
idmap_take(), and idmap_alloc_next().  This causes the
resulting value to be an int instead of a long, which
results in the wrong bit being set once the number of
bits to shift operand exceeds sizeof(int).  Also
on some platforms, the behavior of the left bitshift
operator is undefined when this overflow occurs.
2014-03-05 08:49:50 -06:00
Pekka Lundstrom
cf6278f5cc Merge pull request #181 from plundstr/master
Packaging fixes
2014-02-19 16:48:49 +02:00
Pekka Lundstrom
dd3b0c5aca No restart on update
Signed-off-by: Pekka Lundstrom <pekka.lundstrom@jollamobile.com>
2014-02-19 15:01:31 +02:00
Pekka Lundstrom
988a759e4c [packaking] Add fail safe to post scripts
Signed-off-by: Pekka Lundstrom <pekka.lundstrom@jollamobile.com>
2014-02-19 14:08:27 +02:00
Pekka Lundstrom
555585c17f [packaking] get rid off .yaml
Signed-off-by: Pekka Lundstrom <pekka.lundstrom@jollamobile.com>
2014-02-19 14:06:25 +02:00
Luiz Augusto von Dentz
76a7f9014d gdbus: Replace g_timeout_add with g_idle_add
Passing 0 as timeout to g_timeout_add should equivalent to g_idle_add.
2014-02-18 23:13:53 -08:00
Anderson Lizardo
29401d8587 gdbus: Fix incorrect DBusConnection reference counting
Commit abfc2b0dd5c3e33abfdf1a815b16d492c1751c06 attempted to fix a crash
related to improper reference counting, but the main issue was that the
reference was taken only during the function call (which is usually
unnecessary for single thread), but still passed a pointer to
DBusConnection to a function that is called by the mainloop. This left a
window where the DBusConnection can be destroyed.

Fixes this crash on unit/test-gdbus-client:

==32642== Invalid read of size 4
==32642==    at 0x690D0A6: dbus_connection_ref (in
/lib/i386-linux-gnu/libdbus-1.so.3.7.6)
==32642==    by 0x804CEDB: message_dispatch (mainloop.c:73)
==32642==    by 0x684580E: g_timeout_dispatch (gmain.c:4450)
==32642==    by 0x6844A75: g_main_context_dispatch (gmain.c:3065)
==32642==    by 0x6844E14: g_main_context_iterate.isra.23 (gmain.c:3712)
==32642==    by 0x68452FA: g_main_loop_run (gmain.c:3906)
==32642==    by 0x804C7D3: client_connect_disconnect
(test-gdbus-client.c:188)
==32642==    by 0x6868DB2: g_test_run_suite_internal (gtestutils.c:2067)
==32642==    by 0x6868F8D: g_test_run_suite_internal (gtestutils.c:2138)
==32642==    by 0x6869320: g_test_run_suite (gtestutils.c:2189)
==32642==    by 0x686936B: g_test_run (gtestutils.c:1508)
==32642==    by 0x696D4D2: (below main) (libc-start.c:226)
==32642==  Address 0x709c6e4 is 140 bytes inside a block of size 144
free'd
==32642==    at 0x67E806C: free (in
/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==32642==    by 0x692D62E: dbus_free (in
/lib/i386-linux-gnu/libdbus-1.so.3.7.6)
==32642==    by 0x690E1C2: ??? (in
/lib/i386-linux-gnu/libdbus-1.so.3.7.6)
==32642==    by 0x804AAEC: destroy_context (test-gdbus-client.c:104)
==32642==    by 0x6868DB2: g_test_run_suite_internal (gtestutils.c:2067)
==32642==    by 0x6868F8D: g_test_run_suite_internal (gtestutils.c:2138)
==32642==    by 0x6869320: g_test_run_suite (gtestutils.c:2189)
==32642==    by 0x686936B: g_test_run (gtestutils.c:1508)
==32642==    by 0x696D4D2: (below main) (libc-start.c:226)
2014-02-18 23:13:53 -08:00
Anderson Lizardo
90abd44ead gdbus: Fix memory leak
data->conn and data->path must be destroyed before freeing "data".
2014-02-18 23:13:53 -08:00
Martti Piirainen
4b99034c3f Merge pull request #175 from ptakalok/subs_master
[rilmodem] Allow subscription of stk notifications only once
2014-02-13 08:10:08 +02:00
Petri Takalokastari
03e35b6757 [rilmodem] Allow subscription of stk notifications only once
Allow subscription of stk notifications only when simkit agent registers
for first time. This implementation fixes double subscription problems
which may happen if simkit agent has exited and restarts subscribing to
stk commands again.

Signed-off-by: Petri Takalokastari <petri.takalokastari@oss.tieto.com>
2014-02-11 11:00:01 +02:00
Pekka Lundstrom
b36fdce803 Merge pull request #173 from plundstr/master
[init] Added boot-time requirement to be started after dbus service
2014-02-10 18:06:38 +02:00
Pekka Lundstrom
34251bdba7 [init] Added boot-time requirement to be started after dbus service
Signed-off-by: Pekka Lundstrom <pekka.lundstrom@jollamobile.com>
2014-02-10 15:58:08 +02:00
Slava Monich
278dba2ec8 mbpi: Pop subparser stack after mmsc and mmsproxy 2014-02-07 08:56:44 -06:00
Martti Piirainen
530c66393a Merge pull request #168 from jkangas/master
Request for pulling EFECC reading when READY to main branch
2014-02-06 14:29:37 +02:00
Jussi Kangas
10c823d732 [voicecall] Read the EFECC also if SIM goes straigth to READY
It is possible that ofono starts so that SIM is already in
in READY state when voicecall gets the information. In that case
without this fix core never asks the emergency numbers

Signed-off-by: Jussi Kangas <jussi.kangas@oss.tieto.com>
2014-02-06 13:51:02 +02:00
Martti Piirainen
db6d4d1e8e Merge pull request #163 from marttipiirainen/next
Merge Call Barring support, SIM ATK support and SMS ACK bugfix from 'next' to 'master'
2014-02-03 00:46:01 -08:00
Jussi Kangas
5bcbc64e60 [rilmodem] Ack sms receiving also when error
According to ril api also the failed receiving of SMS should be
acked to ril.

Signed-off-by: Jussi Kangas <jussi.kangas@oss.tieto.com>
2014-02-03 10:07:52 +02:00
Petri Takalokastari
48cec5cc58 [rilmodem] Add initial SIM ATK support
Add initial SIM ATK implementation to rilmodem driver, supporting
proactive command, terminal response and envelope.

Signed-off-by: Petri Takalokastari <petri.takalokastari@oss.tieto.com>

[rilmodem] Fix proactive command and terminal response handling

Convert the proactive commands and terminal responses to correct
format

[rilmodem] Fix for envelope sending

Fix typo in envelope sending causing ofono crash

[rilmodem] stk: adjust timings

Adjust the registeration of the rilmodem stk service and usage of timer
when reporting to RIL when ready to receive proactive commands

[rilmodem] Fix for terminal response and envelope construction

Remove usage of strlen, so the terminal responses and envelopes ending
with value 0x00 are sent properly.

[rilmodem] Remove timer usage from start up sequence

Remove usage of timers in startup sequence. Report ofono readiness to
receive proactive commands only when agent has registered.

[rilmodem] Fine tuning of start up sequence

Register to listen STK specific unsolicited messages only if UI STK agent
has registered. This because RILD will send and buffer proactive commands
also if not received RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING
previously. RILD will buffer the proactive command until receiving
RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING or terminal
response to (sent) proactive command.
By this change oFono core/rilmodem will not handle proactive commands
until STK UI agent has been registered to oFono.

[rilmodem] Change envelope sending request

Changed envelope sending request from
RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS to
RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND as it seems that RILD
does not support RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS
properly.
Also cleaned up some excessive tracing.
2014-02-03 10:07:52 +02:00
Miia Leinonen
6e40473ce9 [rilmodem] Fix for Call Barring commit
Signed-off-by: Miia Leinonen <miia.leinonen@oss.tieto.com>
2014-02-03 10:07:52 +02:00
Miia Leinonen
90cae692df [rilmodem] Add Call Barring support
Signed-off-by: Miia Leinonen <miia.leinonen@oss.tieto.com>
2014-02-03 10:07:51 +02:00
Martti Piirainen
d8270409d0 Merge pull request #156 from jpoutiai/master
[rilmodem] add missing brace characters
2014-02-02 23:48:45 -08:00
Marcel Holtmann
f83233d295 gatchat: Fix handling of WRITE_SCHEDULER_DEBUG 2014-01-19 16:48:04 -08:00
Jarko Poutiainen
e644196aa3 [rilmodem] add missing brace characters
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-01-17 13:44:32 +02:00
Martti Piirainen
fed4a94862 Merge pull request #150 from jpoutiai/master
[rilmodem] fix CF to support all the service classes
2014-01-15 00:54:21 -08:00
Slava Monich
c2e58405ee include: Be more const-correct in ofono_dbus_* 2014-01-13 10:19:54 -06:00
Jarko Poutiainen
ccc8d1afd4 [rilmodem] use SERVICE_CLASS_NONE insteead of hard coded value
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-01-13 12:08:02 +02:00
Jarko Poutiainen
417f20c662 [rilmodem] define SERVICE_CLASS_NONE
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-01-13 12:07:28 +02:00
Jarko Poutiainen
304f7cc197 [rilmodem] remove comments regarding the BEARER_CLASS_DEFAULT
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-01-13 12:07:04 +02:00
Jarko Poutiainen
354285a438 [rilmodem] fix CF to support all the service classes
Signed-off-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
2014-01-13 12:06:22 +02:00
309 changed files with 29891 additions and 2883 deletions

View File

@@ -92,3 +92,15 @@ Jesper Larsen <jesper.larsen@ixonos.com>
Slava Monich <slava.monich@jolla.com>
Andrew Earl <andrewx.earl@intel.com>
Krzysztof Wilk <krzysztofx.wilk@intel.com>
Tony Espy <espy@canonical.com>
Martin Pitt <martin.pitt@ubuntu.com>
Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
Jussi Pakkanen <jussi.pakkanen@canonical.com>
Sergio Checa Blanco <sergio.checa@bmw-carit.de>
Philip Paeps <philip@paeps.cx>
Kuba Pawlak <kubax.t.pawlak@intel.com>
Tommi Kenakkala <tommi.kenakkala@tieto.com>
Alex J Lennon <ajlennon@dynamicdevices.co.uk>
Sergey Alirzaev <zl29ah@gmail.com>
Marko Sulejic <marko.sulejic@hale.at>
Johannes 'josch' Schauer <josch@mister-muffin.de>

View File

@@ -1,3 +1,33 @@
ver 1.17:
Fix issue with alphanumeric TP-OA handling.
Fix issue with push notification origin port.
Fix issue with reading of EF_MWIS records.
Fix issue with handling AT+CPINR results.
Fix issue with SIM state polling for Sierra modems.
Fix issue with HFP handling and AT command prefixes.
Fix issue with HFP and extra CCWA event handling.
Fix issue with HFP call state and +CHUP errors.
ver 1.16:
Fix issue with PIN retry handling.
Fix issue with HFP and multiple calls.
Add support for Distracted Driving Reduction.
Add support for available technologies property.
Add support for Telit location reporting driver.
Add support for u-blox SARA-U270 modems.
Add support for Quectel UC15 modems.
ver 1.15:
Fix issue with EF_PNN access affecting PLMN display.
Fix issue with SIM detection and Telit HE910 modems.
Fix issue with Mobile Provider Database provisioning.
Fix issue with bit-shifting and ID mapping allocations.
Fix issue with Handsfree and unsolicited notifications.
Fix issue with Handsfree and three way calling feature.
Add support for Handsfree subscriber number feature.
Add support for Handsfree multiple DTMF characters.
Add support for PAP authentication.
ver 1.14:
Add support for Apple Siri specific Handsfree commands.
Add support for provisioning of MMSC and Message Proxy.

View File

@@ -21,8 +21,9 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
include/cdma-connman.h include/gnss.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/siri.h
include/handsfree-audio.h \
include/sim-mnclength.h \
include/siri.h
nodist_pkginclude_HEADERS = include/version.h
@@ -118,8 +119,53 @@ builtin_sources += plugins/udevng.c
endif
if RILMODEM
if JOLLA_RILMODEM
builtin_modules += ril
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 \
drivers/ril/ril_phonebook.c \
drivers/ril/ril_plugin.c \
drivers/ril/ril_plugin_dbus.c \
drivers/ril/ril_radio.c \
drivers/ril/ril_radio_settings.c \
drivers/ril/ril_sim.c \
drivers/ril/ril_sim_card.c \
drivers/ril/ril_sim_info.c \
drivers/ril/ril_sim_info_dbus.c \
drivers/ril/ril_sim_settings.c \
drivers/ril/ril_sms.c \
drivers/ril/ril_stk.c \
drivers/ril/ril_ussd.c \
drivers/ril/ril_util.c \
drivers/ril/ril_voicecall.c
if DATAFILES
dist_conf_DATA += drivers/ril/ril_subscription.conf
endif
else
builtin_sources += $(gril_sources)
builtin_modules += rildev
builtin_sources += plugins/rildev.c
builtin_modules += ril
builtin_sources += plugins/ril.c
@@ -142,8 +188,15 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
drivers/rilmodem/call-settings.c \
drivers/rilmodem/call-forwarding.c \
drivers/rilmodem/cbs.c \
drivers/rilmodem/oemraw-messages.c
drivers/rilmodem/oemraw-messages.c \
drivers/rilmodem/call-barring.c \
drivers/rilmodem/stk.c
if DATAFILES
dist_conf_DATA += gril/ril_subscription.conf
endif
endif
endif
if ISIMODEM
@@ -307,6 +360,12 @@ builtin_sources += drivers/atmodem/atutil.h \
drivers/mbmmodem/stk.c \
drivers/mbmmodem/location-reporting.c
builtin_modules += telitmodem
builtin_sources += drivers/atmodem/atutil.h \
drivers/telitmodem/telitmodem.h \
drivers/telitmodem/telitmodem.c \
drivers/telitmodem/location-reporting.c
builtin_modules += hsomodem
builtin_sources += drivers/atmodem/atutil.h \
drivers/hsomodem/hsomodem.h \
@@ -369,9 +428,6 @@ builtin_sources += plugins/phonesim.c
if DATAFILES
dist_conf_DATA += plugins/phonesim.conf
if RILMODEM
dist_conf_DATA += gril/ril_subscription.conf
endif
endif
endif
@@ -427,8 +483,8 @@ builtin_sources += plugins/stemgr.c
builtin_modules += caif
builtin_sources += plugins/caif.c
builtin_modules += tc65
builtin_sources += plugins/tc65.c
builtin_modules += cinterion
builtin_sources += plugins/cinterion.c
builtin_modules += nokia
builtin_sources += plugins/nokia.c
@@ -456,14 +512,20 @@ builtin_sources += plugins/samsung.c
builtin_modules += sim900
builtin_sources += plugins/sim900.c
builtin_modules += quectel
builtin_sources += plugins/quectel.c
builtin_modules += ublox
builtin_sources += plugins/ublox.c
builtin_modules += he910
builtin_sources += plugins/he910.c
endif
builtin_modules += connman
builtin_sources += plugins/connman.c
builtin_modules += he910
builtin_sources += plugins/he910.c
if BLUETOOTH
if BLUEZ4
builtin_modules += bluez4
@@ -512,7 +574,7 @@ if PROVISION
builtin_sources += plugins/mbpi.h plugins/mbpi.c
builtin_modules += provision
builtin_sources += plugins/provision.c
builtin_sources += plugins/provision.h plugins/provision.c
builtin_modules += cdma_provision
builtin_sources += plugins/cdma-provision.c
@@ -539,6 +601,9 @@ builtin_sources += examples/private-network.c
builtin_modules += stktest
builtin_sources += plugins/stktest.c
builtin_modules += emulator_fuzz
builtin_sources += plugins/emulator_fuzz.c
endif
builtin_modules += smart_messaging
@@ -547,6 +612,18 @@ builtin_sources += plugins/smart-messaging.c
builtin_modules += push_notification
builtin_sources += plugins/push-notification.c
if PUSHFORWARDER
builtin_modules += push_forwarder
builtin_sources += plugins/push-forwarder.c
builtin_cflags += @WSPCODEC_CFLAGS@
builtin_libadd += @WSPCODEC_LIBS@
endif
if DEBUGLOG
builtin_modules += debuglog
builtin_sources += plugins/debuglog.c
endif
builtin_modules += sms_history
builtin_sources += plugins/smshistory.c
@@ -577,8 +654,8 @@ 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/hfp.h src/sim-mnclength.c src/oemraw.c \
src/siri.c
src/sim-mnclength.c src/voicecallagent.c \
src/hfp.h src/siri.c
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
@@ -621,9 +698,10 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
doc/sim-api.txt doc/stk-api.txt \
doc/audio-settings-api.txt doc/text-telephony-api.txt \
doc/calypso-modem.txt doc/message-api.txt \
doc/location-reporting-api.txt doc/smshistory-api.txt \
doc/oemraw-api.txt \
doc/certification.txt doc/siri-api.txt
doc/location-reporting-api.txt \
doc/smshistory-api.txt doc/oemraw-api.txt \
doc/certification.txt doc/siri-api.txt \
doc/telit-modem.txt
test_scripts = test/backtrace \
@@ -711,13 +789,17 @@ test_scripts = test/backtrace \
test/set-context-property \
test/test-gnss \
test/swap-calls \
test/transfer-call \
test/release-and-answer \
test/release-and-swap \
test/hold-and-answer \
test/hangup-multiparty \
test/hangup-call \
test/display-icon \
test/set-msisdn
test/set-msisdn \
test/test-voicecallagent \
test/get-network-time \
test/set-ddr
if TEST
testdir = $(pkglibdir)/test
@@ -738,7 +820,8 @@ unit_tests = unit/test-common unit/test-util unit/test-idmap \
unit/test-grilrequest \
unit/test-grilreply \
unit/test-grilunsol \
unit/test-sms unit/test-cdmasms
unit/test-sms unit/test-cdmasms \
unit/test-provision
noinst_PROGRAMS = $(unit_tests) \
unit/test-sms-root unit/test-mux unit/test-caif
@@ -805,6 +888,13 @@ unit_test_grilunsol_SOURCES = unit/test-grilunsol.c $(gril_sources) \
unit_test_grilunsol_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_grilunsol_OBJECTS)
unit_test_provision_SOURCES = unit/test-provision.c \
plugins/provision.h plugins/provision.c \
plugins/mbpi.c src/gprs-provision.c \
src/log.c
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_provision_OBJECTS)
TESTS = $(unit_tests)
if TOOLS

View File

@@ -12,7 +12,7 @@ AC_DEFUN([AC_PROG_CC_PIE], [
AC_DEFUN([COMPILER_FLAGS], [
if (test "${CFLAGS}" = ""); then
CFLAGS="-Wall -O2 -D_FORTIFY_SOURCE=2"
CFLAGS="-Wall -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2"
fi
if (test "$USE_MAINTAINER_MODE" = "yes"); then
CFLAGS="$CFLAGS -Werror -Wextra"

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(ofono, 1.14)
AC_INIT(ofono, 1.17)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)
@@ -42,6 +42,7 @@ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
if (test "${enableval}" = "yes" &&
test "${ac_cv_prog_cc_g}" = "yes"); then
CFLAGS="$CFLAGS -g"
CPPFLAGS="$CPPFLAGS -DDEBUG"
fi
])
@@ -166,6 +167,20 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
[enable_rilmodem=${enableval}])
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
AC_ARG_ENABLE(jolla-rilmodem,
AC_HELP_STRING([--enable-jolla-rilmodem], [enable Jolla RIL modem]),
[enable_jolla_rilmodem=${enableval}], [enable_jolla_rilmodem="no"])
AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_rilmodem}" != "no")
if (test "${enable_jolla_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.6, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.6 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.5, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.5 is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS"
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS"
fi
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
[disable Qualcomm QMI modem support]),
[enable_qmimodem=${enableval}])
@@ -192,13 +207,16 @@ AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
[disable Nettime plugin]),
[enable_nettime=${enableval}])
AM_CONDITIONAL(NETTIME, test "${enable_netttime}" != "no")
if (test "${enable_nettime}" != "no"); then
AC_SEARCH_LIBS([clock_gettime], [rt])
fi
AM_CONDITIONAL(NETTIME, test "${enable_nettime}" != "no")
AC_ARG_WITH([provisiondb], AC_HELP_STRING([--with-provisiondb=FILE],
[location of provision database]), [path_provisiondb=${withval}])
AC_ARG_ENABLE(provision, AC_HELP_STRING([--disable-provision],
[disable provisioning suport]),
[disable provisioning support]),
[enable_provision=${enableval}])
if (test "${enable_provision}" != "no"); then
if (test -n "${path_provisiondb}"); then
@@ -223,6 +241,28 @@ AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
[enable_datafiles=${enableval}])
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
AC_ARG_ENABLE(pushforwarder, AC_HELP_STRING([--disable-pushforwarder],
[disable Push Forwarder plugin]),
[enable_pushforwarder=${enableval}])
AM_CONDITIONAL(PUSHFORWARDER, test "${enable_pushforwarder}" != "no")
if (test "${enable_pushforwarder}" != "no"); then
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
AC_MSG_ERROR(WSP decoder is required))
AC_SUBST(WSPCODEC_CFLAGS)
AC_SUBST(WSPCODEC_LIBS)
fi
AC_ARG_ENABLE(debuglog,
AC_HELP_STRING([--enable-debuglog], [enable log control plugin]),
[enable_debuglog=${enableval}], [enable_debuglog="no"])
AM_CONDITIONAL(DEBUGLOG, test "${enable_debuglog}" != "no")
if (test "${enable_debuglog}" = "yes"); then
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
if (test "$localstatedir" = '${prefix}/var'); then

View File

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

View File

@@ -60,6 +60,16 @@ Methods dict GetProperties()
[service].Error.NotFound
[service].Error.Failed
void ResetContexts()
Removes all contexts and re-provisions from the APN
database. Contexts must all be deactivated for this
method to work, and the atom must not be powered.
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.NotAllowed
Signals PropertyChanged(string property, variant value)
This signal indicates a changed value of the given
@@ -155,6 +165,15 @@ Methods dict GetProperties()
[service].Error.AttachInProgress
[service].Error.NotImplemented
Methods void ProvisionContext()
Resets all properties back to default. Fails to make
any changes to the context if it is active or in the
process of being activated or deactivated.
Possible Errors: [service].Error.Failed
[service].Error.InProgress
[service].Error.NotAvailable
Signals PropertyChanged(string property, variant value)
This signal indicates a changed value of the given
@@ -180,6 +199,10 @@ Properties boolean Active [readwrite]
"wap" - Used by WAP related services
"ims" - Used by IMS related services
string AuthenticationMethod [readwrite]
Holds the PPP authentication method to use. Valid
values are "pap" and "chap". Defaults to "chap".
string Username [readwrite]
Holds the username to be used for authentication

View File

@@ -19,6 +19,8 @@ Methods dict GetProperties()
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.NotImplemented
[service].Error.NotSupported
string RequestPhoneNumber()
@@ -45,6 +47,13 @@ Properties array{string} Features [readonly]
"voice-recognition"
"attach-voice-tag"
"echo-canceling-and-noise-reduction"
"three-way-calling"
"release-all-held"
"release-specified-active-call"
"private-chat"
"create-multiparty"
"transfer"
"hf-indicators"
boolean InbandRinging [readonly]
@@ -57,7 +66,7 @@ Properties array{string} Features [readonly]
to activate or deactivate the function from the HF, or
the AG could autonomously initiate it.
boolean EchoCancelingNoiseReduction [readwrite]
boolean EchoCancelingNoiseReduction [readwrite, optional]
Non-persistent Boolean property representing whether
echo canceling and noise reduction is enabled in the
@@ -70,3 +79,14 @@ Properties array{string} Features [readonly]
The current charge level of the battery. The value
can be between 0 and 5 respectively.
array{string} SubscriberNumbers [readonly]
List of subscriber numbers provided by the AG.
boolean DistractedDrivingReduction [readwrite, optional]
Non-persistent property representing whether
distracted driving reduction mode should be enabled in
the AG. Support for this feature is optional on the
AG.

View File

@@ -57,6 +57,11 @@ Signals PropertyChanged(string property, variant value)
This signal indicates a changed value of the given
property.
OperatorsChanged(array{object,dict})
Signal that gets emitted when operator list has
changed. It contains the current list of operators.
Properties string Mode [readonly]
The current registration mode. The default of this

View File

@@ -45,6 +45,11 @@ Properties string TechnologyPreference [readwrite]
"umts" Only UMTS used for radio access.
"lte" Only LTE used for radio access.
array{string} AvailableTechnologies [readonly, optional]
List of values for TechnologyPreference property
supported by the modem.
string GsmBand [readwrite, optional]
Frequency band in which the modem is allowed to

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

19
ofono/doc/telit-modem.txt Normal file
View File

@@ -0,0 +1,19 @@
oFono - Open Source Telephony
*****************************
Purpose
=======
The purpose of this document is to identify issues and configuration
requirements with Telit's modems.
HE910
=====
GPS:
To enable location reporting on the Telit HE910 the modem needs to be
switched to Port Configuration #8. Please refer to Telit's
'HE910 UE910 Family Ports Arrangements' section 4.1.3 for rationale and
'AT Commands Reference Guide' section 3.5.7.1.96 for specific AT command.
After setting the configuration, a power cycle is required.
Port Configiuration #8 is available since firmware 12.00.004. Firmware version
can be checked using 'AT+CGMR'.

View File

@@ -198,6 +198,25 @@ Methods dict GetProperties()
[service].Error.InvalidFormat
[service].Error.Failed
void RegisterVoicecallAgent(object path)
Registers an agent which will be called whenever a
specific voice call related event requiring a client
action occurs. Currently, the only such action is
playing a ringback tone locally.
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.InvalidFormat
[service].Error.Failed
void UnregisterVoicecallAgent(object path)
Unregisters an agent.
Possible Errors: [service].Error.InvalidArguments
[service].Error.Failed
Signals CallAdded(object path, dict properties)
Signal that is sent when a new call is added. It
@@ -257,3 +276,26 @@ Properties array{string} EmergencyNumbers [readonly]
of numbers provided by the specification and any
extra numbers provisioned by the carrier on the
SIM.
VoiceCallAgent Hierarchy
========================
Service unique name
Interface org.ofono.VoiceCallAgent
Object path freely definable
Methods void RingbackTone(boolean playTone)
Requests the client to generate an alerting tone locally
(3GPP 24.008; 5.2.1.5). This can happen when an outgoing
voice call is made and network is not providing the
alerting tone. Value 0 stands for "stop playing ringback
tone" and 1 for "start playing ringback tone".
void Release() [noreply]
Agent is being released, possibly because of oFono
terminating, voicecall interface is being torn down or
modem is switched off. No UnregisterVoicecallAgent
call is needed.

View File

@@ -59,6 +59,7 @@ enum state {
struct gprs_context_data {
GAtChat *chat;
unsigned int active_context;
GAtPPPAuthMethod auth_method;
char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
GAtPPP *ppp;
@@ -154,6 +155,7 @@ static gboolean setup_ppp(struct ofono_gprs_context *gc)
if (getenv("OFONO_PPP_DEBUG"))
g_at_ppp_set_debug(gcd->ppp, ppp_debug, "PPP");
g_at_ppp_set_auth_method(gcd->ppp, gcd->auth_method);
g_at_ppp_set_credentials(gcd->ppp, gcd->username, gcd->password);
/* set connect and disconnect callbacks */
@@ -243,6 +245,18 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
memcpy(gcd->username, ctx->username, sizeof(ctx->username));
memcpy(gcd->password, ctx->password, sizeof(ctx->password));
/* We only support CHAP and PAP */
switch (ctx->auth_method) {
case OFONO_GPRS_AUTH_METHOD_CHAP:
gcd->auth_method = G_AT_PPP_AUTH_METHOD_CHAP;
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
gcd->auth_method = G_AT_PPP_AUTH_METHOD_PAP;
break;
default:
goto error;
}
gcd->state = STATE_ENABLING;
if (gcd->vendor == OFONO_VENDOR_ZTE) {
@@ -268,9 +282,34 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"", ctx->cid);
if (ctx->apn)
snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"",
ctx->apn);
if (ctx->apn) {
switch (gcd->vendor) {
case OFONO_VENDOR_UBLOX:
/*
* U-blox modems require a magic prefix to the APN to
* specify the authentication method to use in the
* network. See UBX-13002752 - R21.
*
* As the response of the read command omits this magic
* prefix, this is the least invasive place to set it.
*/
switch (ctx->auth_method) {
case OFONO_GPRS_AUTH_METHOD_CHAP:
snprintf(buf + len, sizeof(buf) - len - 3,
",\"CHAP:%s\"", ctx->apn);
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
snprintf(buf + len, sizeof(buf) - len - 3,
",\"PAP:%s\"", ctx->apn);
break;
}
break;
default:
snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"",
ctx->apn);
break;
}
}
if (g_at_chat_send(gcd->chat, buf, none_prefix,
at_cgdcont_cb, gc, NULL) > 0)

View File

@@ -282,6 +282,44 @@ static void telit_mode_notify(GAtResult *result, gpointer user_data)
ofono_gprs_bearer_notify(gprs, bearer);
}
static void ublox_ureg_notify(GAtResult *result, gpointer user_data)
{
struct ofono_gprs *gprs = user_data;
GAtResultIter iter;
gint state, bearer;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+UREG:"))
return;
if (!g_at_result_iter_next_number(&iter, &state))
return;
switch (state) {
case 4:
bearer = 5;
break;
case 5:
bearer = 4;
break;
case 7:
/* XXX: reserved - assume none. */
bearer = 0;
break;
case 8:
bearer = 1;
break;
case 9:
bearer = 2;
break;
default:
bearer = state;
}
ofono_gprs_bearer_notify(gprs, bearer);
}
static void cpsb_notify(GAtResult *result, gpointer user_data)
{
struct ofono_gprs *gprs = user_data;
@@ -316,6 +354,12 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify,
FALSE, gprs, NULL);
break;
case OFONO_VENDOR_UBLOX:
g_at_chat_register(gd->chat, "+UREG:", ublox_ureg_notify,
FALSE, gprs, NULL);
g_at_chat_send(gd->chat, "AT+UREG=1", none_prefix,
NULL, NULL, NULL);
break;
case OFONO_VENDOR_TELIT:
g_at_chat_register(gd->chat, "#PSNT:", telit_mode_notify,
FALSE, gprs, NULL);

View File

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

View File

@@ -67,6 +67,8 @@ static const char *epin_prefix[] = { "*EPIN:", NULL };
static const char *spic_prefix[] = { "+SPIC:", NULL };
static const char *pct_prefix[] = { "#PCT:", NULL };
static const char *pnnm_prefix[] = { "+PNNM:", NULL };
static const char *qpinc_prefix[] = { "+QPINC:", NULL };
static const char *upincnt_prefix[] = { "+UPINCNT:", NULL };
static const char *none_prefix[] = { NULL };
static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
@@ -825,7 +827,7 @@ static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
for (i = 1; i < len; i++) {
if (!strcmp(name, at_sim_name[i].name)) {
retries[i] = val;
retries[at_sim_name[i].type] = val;
break;
}
}
@@ -967,6 +969,90 @@ error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
static void at_qpinc_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_pin_retries_cb_t cb = cbd->cb;
const char *final = g_at_result_final_response(result);
GAtResultIter iter;
struct ofono_error error;
int retries[OFONO_SIM_PASSWORD_INVALID];
size_t i;
decode_at_error(&error, final);
if (!ok) {
cb(&error, NULL, cbd->data);
return;
}
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
retries[i] = -1;
g_at_result_iter_init(&iter, result);
while (g_at_result_iter_next(&iter, "+QPINC:")) {
const char *name;
int pin, puk;
if (!g_at_result_iter_next_string(&iter, &name))
continue;
if (!g_at_result_iter_next_number(&iter, &pin))
continue;
if (!g_at_result_iter_next_number(&iter, &puk))
continue;
if (!strcmp(name, "SC")) {
retries[OFONO_SIM_PASSWORD_SIM_PIN] = pin;
retries[OFONO_SIM_PASSWORD_SIM_PUK] = puk;
} else if (!strcmp(name, "P2")) {
retries[OFONO_SIM_PASSWORD_SIM_PIN2] = pin;
retries[OFONO_SIM_PASSWORD_SIM_PUK2] = puk;
}
}
cb(&error, retries, cbd->data);
}
static void upincnt_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_pin_retries_cb_t cb = cbd->cb;
const char *final = g_at_result_final_response(result);
GAtResultIter iter;
struct ofono_error error;
int retries[OFONO_SIM_PASSWORD_INVALID];
size_t i;
static enum ofono_sim_password_type password_types[] = {
OFONO_SIM_PASSWORD_SIM_PIN,
OFONO_SIM_PASSWORD_SIM_PIN2,
OFONO_SIM_PASSWORD_SIM_PUK,
OFONO_SIM_PASSWORD_SIM_PUK2,
};
decode_at_error(&error, final);
if (!ok) {
cb(&error, NULL, cbd->data);
return;
}
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+UPINCNT:"))
goto error;
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
retries);
cb(&error, retries, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
static void at_pin_retries_query(struct ofono_sim *sim,
ofono_sim_pin_retries_cb_t cb,
void *data)
@@ -1028,6 +1114,16 @@ static void at_pin_retries_query(struct ofono_sim *sim,
at_pnnm_cb, cbd, g_free) > 0)
return;
break;
case OFONO_VENDOR_QUECTEL:
if (g_at_chat_send(sd->chat, "AT+QPINC?", qpinc_prefix,
at_qpinc_cb, cbd, g_free) > 0)
return;
break;
case OFONO_VENDOR_UBLOX:
if (g_at_chat_send(sd->chat, "AT+UPINCNT", upincnt_prefix,
upincnt_cb, cbd, g_free) > 0)
return;
break;
default:
if (g_at_chat_send(sd->chat, "AT+CPINR", cpinr_prefixes,
at_cpinr_cb, cbd, g_free) > 0)
@@ -1254,6 +1350,7 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
case OFONO_VENDOR_ALCATEL:
case OFONO_VENDOR_HUAWEI:
case OFONO_VENDOR_SIMCOM:
case OFONO_VENDOR_SIERRA:
/*
* On ZTE modems, after pin is entered, SIM state is checked
* by polling CPIN as their modem doesn't provide unsolicited
@@ -1419,7 +1516,7 @@ static void at_lock_status_cb(gboolean ok, GAtResult *result,
{
struct cb_data *cbd = user_data;
GAtResultIter iter;
ofono_sim_locked_cb_t cb = cbd->cb;
ofono_query_facility_lock_cb_t cb = cbd->cb;
struct ofono_error error;
int locked;
@@ -1444,9 +1541,9 @@ static void at_lock_status_cb(gboolean ok, GAtResult *result,
cb(&error, locked, cbd->data);
}
static void at_pin_query_enabled(struct ofono_sim *sim,
static void at_query_clck(struct ofono_sim *sim,
enum ofono_sim_password_type passwd_type,
ofono_sim_locked_cb_t cb, void *data)
ofono_query_facility_lock_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
@@ -1529,7 +1626,7 @@ static struct ofono_sim_driver driver = {
.reset_passwd = at_pin_send_puk,
.lock = at_pin_enable,
.change_passwd = at_change_passwd,
.query_locked = at_pin_query_enabled,
.query_facility_lock = at_query_clck,
};
static struct ofono_sim_driver driver_noef = {
@@ -1543,7 +1640,7 @@ static struct ofono_sim_driver driver_noef = {
.reset_passwd = at_pin_send_puk,
.lock = at_pin_enable,
.change_passwd = at_change_passwd,
.query_locked = at_pin_query_enabled,
.query_facility_lock = at_query_clck,
};
void at_sim_init(void)

View File

@@ -42,5 +42,8 @@ enum ofono_vendor {
OFONO_VENDOR_SIMCOM_SIM900,
OFONO_VENDOR_ICERA,
OFONO_VENDOR_WAVECOM_Q2XXX,
OFONO_VENDOR_ALCATEL
OFONO_VENDOR_ALCATEL,
OFONO_VENDOR_QUECTEL,
OFONO_VENDOR_UBLOX,
OFONO_VENDOR_CINTERION,
};

View File

@@ -45,10 +45,12 @@
static const char *binp_prefix[] = { "+BINP:", NULL };
static const char *bvra_prefix[] = { "+BVRA:", NULL };
static const char *none_prefix[] = { NULL };
struct hf_data {
GAtChat *chat;
unsigned int ag_features;
unsigned int ag_chld_features;
int battchg_index;
guint register_source;
};
@@ -124,6 +126,108 @@ static void ciev_notify(GAtResult *result, gpointer user_data)
ofono_handsfree_battchg_notify(hf, value);
}
static void cnum_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_handsfree_cnum_query_cb_t cb = cbd->cb;
GAtResultIter iter;
struct ofono_phone_number *list = NULL;
int num = 0;
struct ofono_error error;
decode_at_error(&error, g_at_result_final_response(result));
if (!ok)
goto out;
g_at_result_iter_init(&iter, result);
while (g_at_result_iter_next(&iter, "+CNUM:"))
num++;
if (num == 0)
goto out;
list = g_new0(struct ofono_phone_number, num);
g_at_result_iter_init(&iter, result);
for (num = 0; g_at_result_iter_next(&iter, "+CNUM:"); ) {
const char *number;
int service;
int type;
if (!g_at_result_iter_skip_next(&iter))
continue;
if (!g_at_result_iter_next_string(&iter, &number))
continue;
if (!g_at_result_iter_next_number(&iter, &type))
continue;
if (!g_at_result_iter_skip_next(&iter))
continue;
if (!g_at_result_iter_next_number(&iter, &service))
continue;
/* We are only interested in Voice services */
if (service != 4)
continue;
strncpy(list[num].number, number,
OFONO_MAX_PHONE_NUMBER_LENGTH);
list[num].number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
list[num].type = type;
DBG("cnum_notify:%s", list[num].number);
num++;
}
out:
cb(&error, num, list, cbd->data);
g_free(list);
}
static void hfp_cnum_query(struct ofono_handsfree *hf,
ofono_handsfree_cnum_query_cb_t cb, void *data)
{
struct hf_data *hd = ofono_handsfree_get_data(hf);
struct cb_data *cbd = cb_data_new(cb, data);
if (g_at_chat_send(hd->chat, "AT+CNUM", none_prefix,
cnum_query_cb, cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, -1, NULL, data);
}
static void bind_notify(GAtResult *result, gpointer user_data)
{
struct ofono_handsfree *hf = user_data;
int hf_indicator;
int active;
GAtResultIter iter;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+BIND:"))
return;
if (!g_at_result_iter_next_number(&iter, &hf_indicator))
return;
if (!g_at_result_iter_next_number(&iter, &active))
return;
ofono_handsfree_hf_indicator_active_notify(hf, hf_indicator, active);
}
static gboolean hfp_handsfree_register(gpointer user_data)
{
struct ofono_handsfree *hf = user_data;
@@ -134,11 +238,13 @@ static gboolean hfp_handsfree_register(gpointer user_data)
g_at_chat_register(hd->chat, "+BSIR:", bsir_notify, FALSE, hf, NULL);
g_at_chat_register(hd->chat, "+BVRA:", bvra_notify, FALSE, hf, NULL);
g_at_chat_register(hd->chat, "+CIEV:", ciev_notify, FALSE, hf, NULL);
g_at_chat_register(hd->chat, "+BIND:", bind_notify, FALSE, hf, NULL);
if (hd->ag_features & HFP_AG_FEATURE_IN_BAND_RING_TONE)
ofono_handsfree_set_inband_ringing(hf, TRUE);
ofono_handsfree_set_ag_features(hf, hd->ag_features);
ofono_handsfree_set_ag_chld_features(hf, hd->ag_chld_features);
ofono_handsfree_register(hf);
return FALSE;
@@ -149,11 +255,13 @@ static int hfp_handsfree_probe(struct ofono_handsfree *hf,
{
struct hfp_slc_info *info = data;
struct hf_data *hd;
unsigned int i;
DBG("");
hd = g_new0(struct hf_data, 1);
hd->chat = g_at_chat_clone(info->chat);
hd->ag_features = info->ag_features;
hd->ag_chld_features = info->ag_mpty_features;
ofono_handsfree_set_data(hf, hd);
@@ -161,6 +269,14 @@ static int hfp_handsfree_probe(struct ofono_handsfree *hf,
ofono_handsfree_battchg_notify(hf,
info->cind_val[HFP_INDICATOR_BATTCHG]);
ofono_handsfree_set_hf_indicators(hf, info->hf_indicators,
info->num_hf_indicators);
for (i = 0; i < info->num_hf_indicators; i++)
ofono_handsfree_hf_indicator_active_notify(hf,
info->hf_indicators[i],
info->hf_indicator_active_map & (1 << i));
hd->register_source = g_idle_add(hfp_handsfree_register, hf);
return 0;
@@ -267,8 +383,27 @@ static void hfp_disable_nrec(struct ofono_handsfree *hf,
struct cb_data *cbd = cb_data_new(cb, data);
const char *buf = "AT+NREC=0";
if (g_at_chat_send(hd->chat, buf, NULL, hf_generic_set_cb,
cbd, g_free) > 0)
if (g_at_chat_send(hd->chat, buf, none_prefix,
hf_generic_set_cb, cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
static void hfp_hf_indicator(struct ofono_handsfree *hf,
unsigned short indicator, unsigned int value,
ofono_handsfree_cb_t cb, void *data)
{
struct hf_data *hd = ofono_handsfree_get_data(hf);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[128];
snprintf(buf, sizeof(buf), "AT+BIEV=%u,%u", indicator, value);
if (g_at_chat_send(hd->chat, buf, none_prefix,
hf_generic_set_cb, cbd, g_free) > 0)
return;
g_free(cbd);
@@ -280,9 +415,11 @@ static struct ofono_handsfree_driver driver = {
.name = "hfpmodem",
.probe = hfp_handsfree_probe,
.remove = hfp_handsfree_remove,
.cnum_query = hfp_cnum_query,
.request_phone_number = hfp_request_phone_number,
.voice_recognition = hfp_voice_recognition,
.disable_nrec = hfp_disable_nrec,
.hf_indicator = hfp_hf_indicator,
};
void hfp_handsfree_init(void)

View File

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

View File

@@ -41,10 +41,12 @@
#include "hfp.h"
#include "slc.h"
static const char *none_prefix[] = { NULL };
static const char *brsf_prefix[] = { "+BRSF:", NULL };
static const char *cind_prefix[] = { "+CIND:", NULL };
static const char *cmer_prefix[] = { "+CMER:", NULL };
static const char *chld_prefix[] = { "+CHLD:", NULL };
static const char *bind_prefix[] = { "+BIND:", NULL };
struct slc_establish_data {
gint ref_count;
@@ -76,6 +78,14 @@ void hfp_slc_info_init(struct hfp_slc_info *info, guint16 version)
info->hf_features |= HFP_HF_FEATURE_CODEC_NEGOTIATION;
if (version < HFP_VERSION_1_7)
goto done;
info->hf_features |= HFP_HF_FEATURE_HF_INDICATORS;
memset(info->hf_indicators, 0, sizeof(info->hf_indicators));
info->num_hf_indicators = 0;
info->hf_indicator_active_map = 0;
done:
memset(info->cind_val, 0, sizeof(info->cind_val));
memset(info->cind_pos, 0, sizeof(info->cind_pos));
@@ -103,10 +113,109 @@ static void slc_established(struct slc_establish_data *sed)
{
struct hfp_slc_info *info = sed->info;
g_at_chat_send(info->chat, "AT+CMEE=1", NULL, NULL, NULL, NULL);
g_at_chat_send(info->chat, "AT+CMEE=1", none_prefix,
NULL, NULL, NULL);
sed->connect_cb(sed->userdata);
}
static void bind_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct slc_establish_data *sed = user_data;
struct hfp_slc_info *info = sed->info;
GAtResultIter iter;
int hf_indicator;
int enabled;
unsigned int i;
if (!ok)
goto error;
g_at_result_iter_init(&iter, result);
while (g_at_result_iter_next(&iter, "+BIND:")) {
if (!g_at_result_iter_next_number(&iter, &hf_indicator))
goto error;
if (!g_at_result_iter_next_number(&iter, &enabled))
goto error;
ofono_info("AG wants indicator %d %s",
hf_indicator, enabled ? "enabled" : "disabled");
for (i = 0; i < info->num_hf_indicators; i++) {
if (info->hf_indicators[i] != hf_indicator)
continue;
info->hf_indicator_active_map |= enabled << i;
}
ofono_info("Active map: %02x", info->hf_indicator_active_map);
}
slc_established(sed);
return;
error:
slc_failed(sed);
}
static void bind_support_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct slc_establish_data *sed = user_data;
struct hfp_slc_info *info = sed->info;
GAtResultIter iter;
int hf_indicator;
if (!ok)
goto error;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+BIND:"))
goto error;
if (!g_at_result_iter_open_list(&iter))
goto error;
while (g_at_result_iter_next_number(&iter, &hf_indicator)) {
if (info->num_hf_indicators >= 20)
goto error;
ofono_info("AG supports the following HF indicator: %d",
hf_indicator);
info->hf_indicators[info->num_hf_indicators] = hf_indicator;
info->num_hf_indicators += 1;
}
if (!g_at_result_iter_close_list(&iter))
goto error;
slc_establish_data_ref(sed);
g_at_chat_send(info->chat, "AT+BIND?", bind_prefix,
bind_query_cb, sed, slc_establish_data_unref);
return;
error:
slc_failed(sed);
}
static void bind_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct slc_establish_data *sed = user_data;
struct hfp_slc_info *info = sed->info;
if (!ok) {
slc_failed(sed);
return;
}
slc_establish_data_ref(sed);
g_at_chat_send(info->chat, "AT+BIND=?", bind_prefix,
bind_support_cb, sed, slc_establish_data_unref);
}
static void chld_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct slc_establish_data *sed = user_data;
@@ -128,19 +237,19 @@ static void chld_cb(gboolean ok, GAtResult *result, gpointer user_data)
while (g_at_result_iter_next_unquoted_string(&iter, &str)) {
if (!strcmp(str, "0"))
ag_mpty_feature |= AG_CHLD_0;
ag_mpty_feature |= HFP_AG_CHLD_0;
else if (!strcmp(str, "1"))
ag_mpty_feature |= AG_CHLD_1;
ag_mpty_feature |= HFP_AG_CHLD_1;
else if (!strcmp(str, "1x"))
ag_mpty_feature |= AG_CHLD_1x;
ag_mpty_feature |= HFP_AG_CHLD_1x;
else if (!strcmp(str, "2"))
ag_mpty_feature |= AG_CHLD_2;
ag_mpty_feature |= HFP_AG_CHLD_2;
else if (!strcmp(str, "2x"))
ag_mpty_feature |= AG_CHLD_2x;
ag_mpty_feature |= HFP_AG_CHLD_2x;
else if (!strcmp(str, "3"))
ag_mpty_feature |= AG_CHLD_3;
ag_mpty_feature |= HFP_AG_CHLD_3;
else if (!strcmp(str, "4"))
ag_mpty_feature |= AG_CHLD_4;
ag_mpty_feature |= HFP_AG_CHLD_4;
}
if (!g_at_result_iter_close_list(&iter))
@@ -148,7 +257,14 @@ static void chld_cb(gboolean ok, GAtResult *result, gpointer user_data)
info->ag_mpty_features = ag_mpty_feature;
slc_established(sed);
if ((info->ag_features & HFP_AG_FEATURE_HF_INDICATORS) &&
(info->hf_features & HFP_HF_FEATURE_HF_INDICATORS)) {
slc_establish_data_ref(sed);
g_at_chat_send(info->chat, "AT+BIND=1", none_prefix,
bind_set_cb, sed, slc_establish_data_unref);
} else
slc_established(sed);
return;
error:
@@ -319,8 +435,8 @@ static void brsf_cb(gboolean ok, GAtResult *result, gpointer user_data)
sprintf(str, "AT+BAC=%d", HFP_CODEC_CVSD);
slc_establish_data_ref(sed);
g_at_chat_send(info->chat, str, NULL, bac_cb, sed,
slc_establish_data_unref);
g_at_chat_send(info->chat, str, none_prefix, bac_cb,
sed, slc_establish_data_unref);
return;
}

View File

@@ -19,14 +19,6 @@
*
*/
#define AG_CHLD_0 0x01
#define AG_CHLD_1 0x02
#define AG_CHLD_1x 0x04
#define AG_CHLD_2 0x08
#define AG_CHLD_2x 0x10
#define AG_CHLD_3 0x20
#define AG_CHLD_4 0x40
enum hfp_indicator {
HFP_INDICATOR_SERVICE = 0,
HFP_INDICATOR_CALL,
@@ -47,6 +39,9 @@ struct hfp_slc_info {
unsigned int hf_features;
unsigned char cind_pos[HFP_INDICATOR_LAST];
unsigned int cind_val[HFP_INDICATOR_LAST];
unsigned short hf_indicators[20];
unsigned char num_hf_indicators;
unsigned int hf_indicator_active_map;
};
void hfp_slc_info_init(struct hfp_slc_info *info, guint16 version);

View File

@@ -37,6 +37,7 @@
#include <ofono/voicecall.h>
#include "common.h"
#include "hfp.h"
#include "hfpmodem.h"
#include "slc.h"
@@ -45,6 +46,7 @@
#define POLL_CLCC_DELAY 50
#define EXPECT_RELEASE_DELAY 50
#define CLIP_TIMEOUT 500
#define EXPECT_RING_DELAY 200
static const char *none_prefix[] = { NULL };
static const char *clcc_prefix[] = { "+CLCC:", NULL };
@@ -293,7 +295,7 @@ static void clcc_poll_cb(gboolean ok, GAtResult *result, gpointer user_data)
* we won't get indicator update if any of them is released by CHLD=1x.
* So we have to poll it.
*/
if (num_active > 1 || num_held > 1)
if ((num_active > 1 || num_held > 1) && !vd->clcc_source)
vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL, poll_clcc,
vc);
}
@@ -331,6 +333,10 @@ static void generic_cb(gboolean ok, GAtResult *result, gpointer user_data)
}
}
if (!ok && vd->calls)
g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix,
clcc_poll_cb, req->vc, NULL);
req->cb(&error, req->data);
}
@@ -447,7 +453,7 @@ static void hfp_hold_all_active(struct ofono_voicecall *vc,
{
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
if (vd->ag_mpty_features & AG_CHLD_2) {
if (vd->ag_mpty_features & HFP_AG_CHLD_2) {
hfp_template("AT+CHLD=2", vc, generic_cb, 0, cb, data);
return;
}
@@ -461,7 +467,7 @@ static void hfp_release_all_held(struct ofono_voicecall *vc,
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
unsigned int held_status = 1 << CALL_STATUS_HELD;
if (vd->ag_mpty_features & AG_CHLD_0) {
if (vd->ag_mpty_features & HFP_AG_CHLD_0) {
hfp_template("AT+CHLD=0", vc, generic_cb, held_status,
cb, data);
return;
@@ -476,7 +482,7 @@ static void hfp_set_udub(struct ofono_voicecall *vc,
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
unsigned int incoming_or_waiting = 1 << CALL_STATUS_WAITING;
if (vd->ag_mpty_features & AG_CHLD_0) {
if (vd->ag_mpty_features & HFP_AG_CHLD_0) {
hfp_template("AT+CHLD=0", vc, generic_cb, incoming_or_waiting,
cb, data);
return;
@@ -498,6 +504,19 @@ static gboolean expect_release(gpointer user_data)
return FALSE;
}
static gboolean expect_ring(gpointer user_data)
{
struct ofono_voicecall *vc = user_data;
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
g_at_chat_send(vd->chat, "AT+CLCC", clcc_prefix,
clcc_poll_cb, vc, NULL);
vd->clip_source = 0;
return FALSE;
}
static void release_all_active_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
@@ -528,7 +547,7 @@ static void hfp_release_all_active(struct ofono_voicecall *vc,
{
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
if (vd->ag_mpty_features & AG_CHLD_1) {
if (vd->ag_mpty_features & HFP_AG_CHLD_1) {
hfp_template("AT+CHLD=1", vc, release_all_active_cb, 0x1, cb,
data);
return;
@@ -559,7 +578,7 @@ static void hfp_release_specific(struct ofono_voicecall *vc, int id,
struct release_id_req *req = NULL;
char buf[32];
if (!(vd->ag_mpty_features & AG_CHLD_1x))
if (!(vd->ag_mpty_features & HFP_AG_CHLD_1x))
goto error;
req = g_try_new0(struct release_id_req, 1);
@@ -590,7 +609,7 @@ static void hfp_private_chat(struct ofono_voicecall *vc, int id,
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
char buf[32];
if (vd->ag_mpty_features & AG_CHLD_2x) {
if (vd->ag_mpty_features & HFP_AG_CHLD_2x) {
snprintf(buf, sizeof(buf), "AT+CHLD=2%d", id);
hfp_template(buf, vc, generic_cb, 0, cb, data);
@@ -606,7 +625,7 @@ static void hfp_create_multiparty(struct ofono_voicecall *vc,
{
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
if (vd->ag_mpty_features & AG_CHLD_3) {
if (vd->ag_mpty_features & HFP_AG_CHLD_3) {
hfp_template("AT+CHLD=3", vc, generic_cb, 0, cb, data);
return;
@@ -625,7 +644,7 @@ static void hfp_transfer(struct ofono_voicecall *vc,
*/
unsigned int transfer = 0x1 | 0x2 | 0x4 | 0x8;
if (vd->ag_mpty_features & AG_CHLD_4) {
if (vd->ag_mpty_features & HFP_AG_CHLD_4) {
hfp_template("AT+CHLD=4", vc, generic_cb, transfer, cb, data);
return;
@@ -639,8 +658,10 @@ static void hfp_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
{
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
struct change_state_req *req = g_try_new0(struct change_state_req, 1);
int len = strlen(dtmf);
char *buf;
int s;
int i;
if (req == NULL)
goto error;
@@ -650,12 +671,15 @@ static void hfp_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
req->data = data;
req->affected_types = 0;
/* strlen("AT+VTS=) = 7 + NULL */
buf = g_try_new(char, strlen(dtmf) + 8);
/* strlen("AT") + (n-1) * strlen("+VTS=T;") + strlen(+VTS=T) + null */
buf = g_try_new(char, len * 7 + 2);
if (buf == NULL)
goto error;
sprintf(buf, "AT+VTS=%s", dtmf);
s = sprintf(buf, "AT+VTS=%c", dtmf[0]);
for (i = 1; i < len; i++)
s += sprintf(buf + s, ";+VTS=%c", dtmf[i]);
s = g_at_chat_send(vd->chat, buf, none_prefix,
generic_cb, req, g_free);
@@ -691,6 +715,16 @@ static void ccwa_notify(GAtResult *result, gpointer user_data)
at_util_call_compare_by_status))
return;
/* some phones may send extra CCWA after active call is ended
* this would trigger creation of second call in state 'WAITING'
* as our previous WAITING call has been promoted to INCOMING
*/
if (g_slist_find_custom(vd->calls,
GINT_TO_POINTER(CALL_STATUS_INCOMING),
at_util_call_compare_by_status))
return;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CCWA:"))
@@ -751,6 +785,11 @@ static void ring_notify(GAtResult *result, gpointer user_data)
struct ofono_call *call;
GSList *waiting;
if (vd->clip_source) {
g_source_remove(vd->clip_source);
vd->clip_source = 0;
}
/* RING can repeat, ignore if we already have an incoming call */
if (g_slist_find_custom(vd->calls,
GINT_TO_POINTER(CALL_STATUS_INCOMING),
@@ -975,7 +1014,15 @@ static void ciev_callsetup_notify(struct ofono_voicecall *vc,
break;
case 1:
/* Handled in RING/CCWA */
/*
* Handled in RING/CCWA most of the time, however sometimes
* the call is answered before the RING unsolicited
* notification has a chance to be generated on the device.
* In this case, we use a failsafe CLCC poll in expect_ring
* callback.
* */
vd->clip_source = g_timeout_add(EXPECT_RING_DELAY,
expect_ring, vc);
break;
case 2:
@@ -1101,6 +1148,10 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
struct ofono_voicecall *vc = user_data;
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
unsigned int mpty_ids;
GSList *n;
struct ofono_call *nc;
unsigned int num_active = 0;
unsigned int num_held = 0;
if (!ok)
return;
@@ -1109,6 +1160,22 @@ static void hfp_clcc_cb(gboolean ok, GAtResult *result, gpointer user_data)
g_slist_foreach(vd->calls, voicecall_notify, vc);
ofono_voicecall_mpty_hint(vc, mpty_ids);
n = vd->calls;
while (n) {
nc = n->data;
if (nc->status == CALL_STATUS_ACTIVE)
num_active++;
else if (nc->status == CALL_STATUS_HELD)
num_held++;
n = n->next;
}
if ((num_active > 1 || num_held > 1) && !vd->clcc_source)
vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL, poll_clcc, vc);
}
static void hfp_voicecall_initialized(gboolean ok, GAtResult *result,
@@ -1150,8 +1217,8 @@ static int hfp_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
ofono_voicecall_set_data(vc, vd);
g_at_chat_send(vd->chat, "AT+CLIP=1", NULL, NULL, NULL, NULL);
g_at_chat_send(vd->chat, "AT+CCWA=1", NULL,
g_at_chat_send(vd->chat, "AT+CLIP=1", none_prefix, NULL, NULL, NULL);
g_at_chat_send(vd->chat, "AT+CCWA=1", none_prefix,
hfp_voicecall_initialized, vc, NULL);
return 0;
}

View File

@@ -134,7 +134,9 @@ static void routing_resp_cb(const GIsiMessage *msg, void *data)
struct cbs_data *cd = ofono_cbs_get_data(cbs);
if (!check_resp(msg, SMS_GSM_CB_ROUTING_RESP)) {
ofono_cbs_remove(cbs);
/* on shutdown, cbs is already being removed */
if (g_isi_msg_error(msg) != -ESHUTDOWN)
ofono_cbs_remove(cbs);
return;
}

View File

@@ -652,7 +652,7 @@ static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque)
static void isi_query_locked(struct ofono_sim *sim,
enum ofono_sim_password_type passwd_type,
ofono_sim_locked_cb_t cb, void *data)
ofono_query_facility_lock_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
@@ -963,7 +963,7 @@ static struct ofono_sim_driver driver = {
.reset_passwd = isi_reset_passwd,
.lock = isi_lock,
.change_passwd = isi_change_passwd,
.query_locked = isi_query_locked,
.query_facility_lock = isi_query_locked,
};
void isi_sim_init(void)

View File

@@ -1032,14 +1032,6 @@ static void uicc_lock(struct ofono_sim *sim, enum ofono_sim_password_type type,
CALLBACK_WITH_FAILURE(cb, data);
}
static void uicc_query_locked(struct ofono_sim *sim,
enum ofono_sim_password_type type,
ofono_sim_locked_cb_t cb, void *data)
{
DBG("Not implemented");
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static gboolean decode_fcp_pin_status(const GIsiSubBlockIter *iter, uint8_t read,
uint8_t *pin1, uint8_t *pin2)
{
@@ -1677,7 +1669,6 @@ static struct ofono_sim_driver driver = {
.reset_passwd = uicc_reset_passwd,
.change_passwd = uicc_change_passwd,
.lock = uicc_lock,
.query_locked = uicc_query_locked,
};
void isi_uicc_init(void)

View File

@@ -0,0 +1,284 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 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_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "common.h"
/* See 3GPP 27.007 7.4 for possible values */
#define RIL_MAX_SERVICE_LENGTH 3
/*
* ril.h does not state that string count must be given, but that is
* still expected by the modem
*/
#define RIL_QUERY_STRING_COUNT 4
#define RIL_SET_STRING_COUNT 5
#define RIL_SET_PW_STRING_COUNT 3
struct ril_call_barring {
GRilIoQueue *q;
guint timer_id;
};
struct ril_call_barring_cbd {
struct ril_call_barring *bd;
union _ofono_call_barring_cb {
ofono_call_barring_query_cb_t query;
ofono_call_barring_set_cb_t set;
gpointer ptr;
} cb;
gpointer data;
};
#define ril_call_barring_cbd_free g_free
static inline struct ril_call_barring *ril_call_barring_get_data(
struct ofono_call_barring *b)
{
return ofono_call_barring_get_data(b);
}
static struct ril_call_barring_cbd *ril_call_barring_cbd_new(
struct ril_call_barring *bd, void *cb, void *data)
{
struct ril_call_barring_cbd *cbd;
cbd = g_new0(struct ril_call_barring_cbd, 1);
cbd->bd = bd;
cbd->cb.ptr = cb;
cbd->data = data;
return cbd;
}
static inline void ril_call_barring_submit_request(struct ril_call_barring *bd,
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
void *cb, void *data)
{
grilio_queue_send_request_full(bd->q, req, code, response,
ril_call_barring_cbd_free,
ril_call_barring_cbd_new(bd, cb, data));
}
static void ril_call_barring_query_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_barring_cbd *cbd = user_data;
ofono_call_barring_query_cb_t cb = cbd->cb.query;
if (status == RIL_E_SUCCESS) {
int bearer_class = 0;
GRilIoParser rilp;
/*
* Services for which the specified barring facility is active.
* "0" means "disabled for all, -1 if unknown"
*/
grilio_parser_init(&rilp, data, len);
grilio_parser_get_int32(&rilp, NULL); /* count */
grilio_parser_get_int32(&rilp, &bearer_class);
DBG("Active services: %d", bearer_class);
cb(ril_error_ok(&error), bearer_class, cbd->data);
} else {
ofono_error("Call Barring query error %d", status);
cb(ril_error_failure(&error), 0, cbd->data);
}
}
static void ril_call_barring_query(struct ofono_call_barring *b,
const char *lock, int cls,
ofono_call_barring_query_cb_t cb, void *data)
{
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
char cls_textual[RIL_MAX_SERVICE_LENGTH];
GRilIoRequest *req = grilio_request_new();
DBG("lock: %s, services to query: %d", lock, cls);
/*
* RIL modems do not support 7 as default bearer class. According to
* the 22.030 Annex C: When service code is not given it corresponds to
* "All tele and bearer services"
*/
if (cls == BEARER_CLASS_DEFAULT) {
cls = SERVICE_CLASS_NONE;
}
sprintf(cls_textual, "%d", cls);
/*
* See 3GPP 27.007 7.4 for parameter descriptions.
* According to ril.h password should be empty string "" when not
* needed, but in reality we only need to give string length as 0
*/
grilio_request_append_int32(req, RIL_QUERY_STRING_COUNT);
grilio_request_append_utf8(req, lock); /* Facility code */
grilio_request_append_int32(req, 0); /* Password length */
grilio_request_append_utf8(req, cls_textual);
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
ril_call_barring_submit_request(bd, req,
RIL_REQUEST_QUERY_FACILITY_LOCK,
ril_call_barring_query_cb, cb, data);
grilio_request_unref(req);
}
static void ril_call_barring_set_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_barring_cbd *cbd = user_data;
ofono_call_barring_set_cb_t cb = cbd->cb.set;
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
ofono_error("Call Barring Set error %d", status);
cb(ril_error_failure(&error), cbd->data);
}
}
static void ril_call_barring_set(struct ofono_call_barring *b,
const char *lock, int enable, const char *passwd, int cls,
ofono_call_barring_set_cb_t cb, void *data)
{
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
char cls_textual[RIL_MAX_SERVICE_LENGTH];
GRilIoRequest *req = grilio_request_new();
DBG("lock: %s, enable: %i, bearer class: %i", lock, enable, cls);
/*
* RIL modem does not support 7 as default bearer class. According to
* the 22.030 Annex C: When service code is not given it corresponds to
* "All tele and bearer services"
*/
if (cls == BEARER_CLASS_DEFAULT) {
cls = SERVICE_CLASS_NONE;
}
sprintf(cls_textual, "%d", cls);
/* See 3GPP 27.007 7.4 for parameter descriptions */
grilio_request_append_int32(req, RIL_SET_STRING_COUNT);
grilio_request_append_utf8(req, lock); /* Facility code */
grilio_request_append_utf8(req, enable ?
RIL_FACILITY_LOCK :
RIL_FACILITY_UNLOCK);
grilio_request_append_utf8(req, passwd);
grilio_request_append_utf8(req, cls_textual);
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
ril_call_barring_submit_request(bd, req,
RIL_REQUEST_SET_FACILITY_LOCK,
ril_call_barring_set_cb, cb, data);
grilio_request_unref(req);
}
static void ril_call_barring_set_passwd_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_barring_cbd *cbd = user_data;
ofono_call_barring_set_cb_t cb = cbd->cb.set;
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
ofono_error("Call Barring Set PW error %d", status);
cb(ril_error_failure(&error), cbd->data);
}
}
static void ril_call_barring_set_passwd(struct ofono_call_barring *b,
const char *lock, const char *old_passwd,
const char *new_passwd, ofono_call_barring_set_cb_t cb,
void *data)
{
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
GRilIoRequest *req = grilio_request_new();
DBG("");
grilio_request_append_int32(req, RIL_SET_PW_STRING_COUNT);
grilio_request_append_utf8(req, lock); /* Facility code */
grilio_request_append_utf8(req, old_passwd);
grilio_request_append_utf8(req, new_passwd);
ril_call_barring_submit_request(bd, req,
RIL_REQUEST_CHANGE_BARRING_PASSWORD,
ril_call_barring_set_passwd_cb, cb, data);
grilio_request_unref(req);
}
static gboolean ril_call_barring_register(gpointer user_data)
{
struct ofono_call_barring *b = user_data;
struct ril_call_barring *bd = ril_call_barring_get_data(b);
GASSERT(bd->timer_id);
bd->timer_id = 0;
ofono_call_barring_register(b);
return FALSE;
}
static int ril_call_barring_probe(struct ofono_call_barring *b,
unsigned int vendor, void *data)
{
struct ril_modem *modem = data;
struct ril_call_barring *bd = g_new0(struct ril_call_barring, 1);
DBG("");
bd->q = grilio_queue_new(ril_modem_io(modem));
bd->timer_id = g_idle_add(ril_call_barring_register, b);
ofono_call_barring_set_data(b, bd);
return 0;
}
static void ril_call_barring_remove(struct ofono_call_barring *b)
{
struct ril_call_barring *bd = ril_call_barring_get_data(b);
DBG("");
ofono_call_barring_set_data(b, NULL);
if (bd->timer_id > 0) {
g_source_remove(bd->timer_id);
}
grilio_queue_cancel_all(bd->q, FALSE);
grilio_queue_unref(bd->q);
g_free(bd);
}
const struct ofono_call_barring_driver ril_call_barring_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_call_barring_probe,
.remove = ril_call_barring_remove,
.query = ril_call_barring_query,
.set = ril_call_barring_set,
.set_passwd = ril_call_barring_set_passwd
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,275 @@
/*
* 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_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "common.h"
struct ril_call_forward {
GRilIoQueue *q;
guint timer_id;
};
enum ril_call_forward_action {
CF_ACTION_DISABLE,
CF_ACTION_ENABLE,
CF_ACTION_INTERROGATE,
CF_ACTION_REGISTRATION,
CF_ACTION_ERASURE
};
#define CF_TIME_DEFAULT (0)
struct ril_call_forward_cbd {
struct ril_call_forward *fd;
union _ofono_call_forward_cb {
ofono_call_forwarding_query_cb_t query;
ofono_call_forwarding_set_cb_t set;
gpointer ptr;
} cb;
gpointer data;
};
static inline struct ril_call_forward *ril_call_forward_get_data(
struct ofono_call_forwarding *cf)
{
return ofono_call_forwarding_get_data(cf);
}
static void ril_call_forward_cbd_free(gpointer cbd)
{
g_slice_free(struct ril_call_forward_cbd, cbd);
}
static struct ril_call_forward_cbd *ril_call_forward_cbd_new(void *cb,
void *data)
{
struct ril_call_forward_cbd *cbd;
cbd = g_slice_new0(struct ril_call_forward_cbd);
cbd->cb.ptr = cb;
cbd->data = data;
return cbd;
}
static GRilIoRequest *ril_call_forward_req(enum ril_call_forward_action action,
int type, int cls, const struct ofono_phone_number *number, int time)
{
GRilIoRequest *req = grilio_request_new();
/*
* Modem seems to respond with error to all requests
* made with bearer class BEARER_CLASS_DEFAULT.
*/
if (cls == BEARER_CLASS_DEFAULT) {
cls = SERVICE_CLASS_NONE;
}
grilio_request_append_int32(req, action);
grilio_request_append_int32(req, type);
grilio_request_append_int32(req, cls); /* Service class */
if (number) {
grilio_request_append_int32(req, number->type);
grilio_request_append_utf8(req, number->number);
} else {
grilio_request_append_int32(req, 0x81); /* TOA unknown */
grilio_request_append_utf8(req, NULL); /* No number */
}
grilio_request_append_int32(req, time);
return req;
}
static void ril_call_forward_set_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_forward_cbd *cbd = user_data;
ofono_call_forwarding_set_cb_t cb = cbd->cb.set;
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
ofono_error("CF setting failed");
cb(ril_error_failure(&error), cbd->data);
}
}
static void ril_call_forward_set(struct ofono_call_forwarding *cf,
enum ril_call_forward_action cmd, int type, int cls,
const struct ofono_phone_number *number, int time,
ofono_call_forwarding_set_cb_t cb, void *data)
{
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
GRilIoRequest *req = ril_call_forward_req(cmd, type, cls, number, time);
grilio_queue_send_request_full(fd->q, req, RIL_REQUEST_SET_CALL_FORWARD,
ril_call_forward_set_cb, ril_call_forward_cbd_free,
ril_call_forward_cbd_new(cb, data));
grilio_request_unref(req);
}
static void ril_call_forward_registration(struct ofono_call_forwarding *cf,
int type, int cls, const struct ofono_phone_number *number,
int time, ofono_call_forwarding_set_cb_t cb, void *data)
{
ofono_info("cf registration");
ril_call_forward_set(cf, CF_ACTION_REGISTRATION, type, cls,
number, time, cb, data);
}
static void ril_call_forward_erasure(struct ofono_call_forwarding *cf,
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
{
ofono_info("cf erasure");
ril_call_forward_set(cf, CF_ACTION_ERASURE, type, cls,
NULL, CF_TIME_DEFAULT, cb, data);
}
static void ril_call_forward_deactivate(struct ofono_call_forwarding *cf,
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
{
ofono_info("cf disable");
ril_call_forward_set(cf, CF_ACTION_DISABLE, type, cls,
NULL, CF_TIME_DEFAULT, cb, data);
}
static void ril_call_forward_activate(struct ofono_call_forwarding *cf,
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
{
ofono_info("cf enable");
ril_call_forward_set(cf, CF_ACTION_ENABLE, type, cls,
NULL, CF_TIME_DEFAULT, cb, data);
}
static void ril_call_forward_query_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_forward_cbd *cbd = user_data;
ofono_call_forwarding_query_cb_t cb = cbd->cb.query;
if (status == RIL_E_SUCCESS) {
struct ofono_call_forwarding_condition *list = NULL;
GRilIoParser rilp;
int count = 0;
int i;
grilio_parser_init(&rilp, data, len);
grilio_parser_get_int32(&rilp, &count);
list = g_new0(struct ofono_call_forwarding_condition, count);
for (i = 0; i < count; i++) {
struct ofono_call_forwarding_condition *fw = list + i;
char *str;
grilio_parser_get_int32(&rilp, &fw->status);
grilio_parser_get_int32(&rilp, NULL);
grilio_parser_get_int32(&rilp, &fw->cls);
grilio_parser_get_int32(&rilp, &fw->phone_number.type);
str = grilio_parser_get_utf8(&rilp);
if (str) {
strncpy(fw->phone_number.number, str,
OFONO_MAX_PHONE_NUMBER_LENGTH);
fw->phone_number.number[
OFONO_MAX_PHONE_NUMBER_LENGTH] = 0;
g_free(str);
}
grilio_parser_get_int32(&rilp, &fw->time);
}
cb(ril_error_ok(&error), count, list, cbd->data);
g_free(list);
} else {
ofono_error("CF query failed");
cb(ril_error_failure(&error), 0, NULL, cbd->data);
}
}
static void ril_call_forward_query(struct ofono_call_forwarding *cf, int type,
int cls, ofono_call_forwarding_query_cb_t cb, void *data)
{
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
GRilIoRequest *req = ril_call_forward_req(CF_ACTION_INTERROGATE,
type, cls, NULL, CF_TIME_DEFAULT);
ofono_info("cf query");
grilio_queue_send_request_full(fd->q, req,
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS,
ril_call_forward_query_cb, ril_call_forward_cbd_free,
ril_call_forward_cbd_new(cb, data));
grilio_request_unref(req);
}
static gboolean ril_call_forward_register(gpointer user_data)
{
struct ofono_call_forwarding *cf = user_data;
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
fd->timer_id = 0;
ofono_call_forwarding_register(cf);
return FALSE;
}
static int ril_call_forward_probe(struct ofono_call_forwarding *cf,
unsigned int vendor, void *data)
{
struct ril_modem *modem = data;
struct ril_call_forward *fd = g_try_new0(struct ril_call_forward, 1);
DBG("");
fd->q = grilio_queue_new(ril_modem_io(modem));
fd->timer_id = g_idle_add(ril_call_forward_register, cf);
ofono_call_forwarding_set_data(cf, fd);
return 0;
}
static void ril_call_forward_remove(struct ofono_call_forwarding *cf)
{
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
DBG("");
ofono_call_forwarding_set_data(cf, NULL);
if (fd->timer_id) {
g_source_remove(fd->timer_id);
}
grilio_queue_cancel_all(fd->q, FALSE);
grilio_queue_unref(fd->q);
g_free(fd);
}
const struct ofono_call_forwarding_driver ril_call_forwarding_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_call_forward_probe,
.remove = ril_call_forward_remove,
.erasure = ril_call_forward_erasure,
.deactivation = ril_call_forward_deactivate,
.query = ril_call_forward_query,
.registration = ril_call_forward_registration,
.activation = ril_call_forward_activate
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,309 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 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_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "common.h"
struct ril_call_settings {
GRilIoQueue *q;
guint timer_id;
};
struct ril_call_settings_cbd {
union _ofono_call_settings_cb {
ofono_call_settings_status_cb_t status;
ofono_call_settings_set_cb_t set;
ofono_call_settings_clir_cb_t clir;
gpointer ptr;
} cb;
gpointer data;
};
#define ril_call_settings_cbd_free g_free
static inline struct ril_call_settings *ril_call_settings_get_data(
struct ofono_call_settings *b)
{
return ofono_call_settings_get_data(b);
}
static struct ril_call_settings_cbd *ril_call_settings_cbd_new(void *cb,
void *data)
{
struct ril_call_settings_cbd *cbd;
cbd = g_new0(struct ril_call_settings_cbd, 1);
cbd->cb.ptr = cb;
cbd->data = data;
return cbd;
}
static inline void ril_call_settings_submit_req(struct ril_call_settings *sd,
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
void *cb, void *data)
{
grilio_queue_send_request_full(sd->q, req, code, response,
ril_call_settings_cbd_free,
ril_call_settings_cbd_new(cb, data));
}
static void ril_call_settings_clip_query_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_settings_cbd *cbd = user_data;
ofono_call_settings_status_cb_t cb = cbd->cb.status;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
int res = 0;
/* data length of the response */
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &res) && res > 0) {
grilio_parser_get_int32(&rilp, &res);
}
cb(ril_error_ok(&error), res, cbd->data);
} else {
cb(ril_error_failure(&error), -1, cbd->data);
}
}
static void ril_call_settings_set_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_settings_cbd *cbd = user_data;
ofono_call_settings_set_cb_t cb = cbd->cb.set;
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
cb(ril_error_failure(&error), cbd->data);
}
}
static void ril_call_settings_cw_set(struct ofono_call_settings *cs, int mode,
int cls, ofono_call_settings_set_cb_t cb, void *data)
{
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
GRilIoRequest *req = grilio_request_sized_new(12);
grilio_request_append_int32(req, 2); /* Number of params */
grilio_request_append_int32(req, mode); /* on/off */
/* Modem seems to respond with error to all queries
* or settings made with bearer class
* BEARER_CLASS_DEFAULT. Design decision: If given
* class is BEARER_CLASS_DEFAULT let's map it to
* SERVICE_CLASS_VOICE effectively making it the
* default bearer. This in line with API which is
* contains only voice anyways.
*/
if (cls == BEARER_CLASS_DEFAULT) {
cls = BEARER_CLASS_VOICE;
}
grilio_request_append_int32(req, cls); /* Service class */
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CALL_WAITING,
ril_call_settings_set_cb, cb, data);
grilio_request_unref(req);
}
static void ril_call_settings_cw_query_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_settings_cbd *cbd = user_data;
ofono_call_settings_status_cb_t cb = cbd->cb.status;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
int res = 0;
int sv = 0;
grilio_parser_init(&rilp, data, len);
/* first value in int[] is len so let's skip that */
grilio_parser_get_int32(&rilp, NULL);
/* status of call waiting service, disabled is returned only if
* service is not active for any service class */
grilio_parser_get_int32(&rilp, &res);
DBG("CW enabled/disabled: %d", res);
if (res > 0) {
/* services for which call waiting is enabled,
27.007 7.12 */
grilio_parser_get_int32(&rilp, &sv);
DBG("CW enabled for: %d", sv);
}
cb(ril_error_ok(&error), sv, cbd->data);
} else {
cb(ril_error_failure(&error), -1, cbd->data);
}
}
static void ril_call_settings_cw_query(struct ofono_call_settings *cs, int cls,
ofono_call_settings_status_cb_t cb, void *data)
{
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1); /* Number of params */
/*
* RILD expects service class to be 0 as certain carriers can reject
* the query with specific service class
*/
grilio_request_append_int32(req, 0);
ril_call_settings_submit_req(sd, req, RIL_REQUEST_QUERY_CALL_WAITING,
ril_call_settings_cw_query_cb, cb, data);
grilio_request_unref(req);
}
static void ril_call_settings_clip_query(struct ofono_call_settings *cs,
ofono_call_settings_status_cb_t cb, void *data)
{
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_QUERY_CLIP,
ril_call_settings_clip_query_cb, cb, data);
}
static void ril_call_settings_clir_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_settings_cbd *cbd = user_data;
ofono_call_settings_clir_cb_t cb = cbd->cb.clir;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
int override = -1, network = -1;
grilio_parser_init(&rilp, data, len);
/*first value in int[] is len so let's skip that*/
grilio_parser_get_int32(&rilp, NULL);
/* Set HideCallerId property from network */
grilio_parser_get_int32(&rilp, &override);
/* CallingLineRestriction indicates the state of
the CLIR supplementary service in the network */
grilio_parser_get_int32(&rilp, &network);
cb(ril_error_ok(&error), override, network, cbd->data);
} else {
cb(ril_error_failure(&error), -1, -1, cbd->data);
}
}
static void ril_call_settings_clir_query(struct ofono_call_settings *cs,
ofono_call_settings_clir_cb_t cb, void *data)
{
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
ril_call_settings_submit_req(sd, NULL, RIL_REQUEST_GET_CLIR,
ril_call_settings_clir_cb, cb, data);
}
static void ril_call_settings_clir_set(struct ofono_call_settings *cs,
int mode, ofono_call_settings_set_cb_t cb, void *data)
{
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1); /* Number of params */
grilio_request_append_int32(req, mode); /* for outgoing calls */
ril_call_settings_submit_req(sd, req, RIL_REQUEST_SET_CLIR,
ril_call_settings_set_cb, cb, data);
grilio_request_unref(req);
}
static gboolean ril_call_settings_register(gpointer user_data)
{
struct ofono_call_settings *cs = user_data;
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
DBG("");
GASSERT(sd->timer_id);
sd->timer_id = 0;
ofono_call_settings_register(cs);
/* Single-shot */
return FALSE;
}
static int ril_call_settings_probe(struct ofono_call_settings *cs,
unsigned int vendor, void *data)
{
struct ril_modem *modem = data;
struct ril_call_settings *sd = g_try_new0(struct ril_call_settings, 1);
DBG("");
sd->q = grilio_queue_new(ril_modem_io(modem));
sd->timer_id = g_idle_add(ril_call_settings_register, cs);
ofono_call_settings_set_data(cs, sd);
return 0;
}
static void ril_call_settings_remove(struct ofono_call_settings *cs)
{
struct ril_call_settings *sd = ril_call_settings_get_data(cs);
DBG("");
ofono_call_settings_set_data(cs, NULL);
if (sd->timer_id > 0) {
g_source_remove(sd->timer_id);
}
grilio_queue_cancel_all(sd->q, FALSE);
grilio_queue_unref(sd->q);
g_free(sd);
}
const struct ofono_call_settings_driver ril_call_settings_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_call_settings_probe,
.remove = ril_call_settings_remove,
.clip_query = ril_call_settings_clip_query,
.cw_query = ril_call_settings_cw_query,
.cw_set = ril_call_settings_cw_set,
.clir_query = ril_call_settings_clir_query,
.clir_set = ril_call_settings_clir_set
/*
* Not supported in RIL API
* .colp_query = ril_call_settings_colp_query,
* .colr_query = ril_call_settings_colr_query
*/
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,151 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 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_util.h"
#include "ril_log.h"
#include "ril_constants.h"
struct ril_call_volume {
struct ofono_call_volume *v;
GRilIoQueue *q;
guint timer_id;
};
struct ril_call_volume_req {
ofono_call_volume_cb_t cb;
gpointer data;
};
static inline struct ril_call_volume *ril_call_volume_get_data(
struct ofono_call_volume *v)
{
return ofono_call_volume_get_data(v);
}
static void ril_call_volume_mute_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_call_volume_req *cbd = user_data;
ofono_call_volume_cb_t cb = cbd->cb;
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
ofono_error("Could not set the ril mute state");
cb(ril_error_failure(&error), cbd->data);
}
}
static void ril_call_volume_mute(struct ofono_call_volume *v, int muted,
ofono_call_volume_cb_t cb, void *data)
{
struct ril_call_volume *vd = ril_call_volume_get_data(v);
struct ril_call_volume_req *cbd;
GRilIoRequest *req = grilio_request_sized_new(8);
cbd = g_new(struct ril_call_volume_req, 1);
cbd->cb = cb;
cbd->data = data;
DBG("%d", muted);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, muted);
grilio_queue_send_request_full(vd->q, req, RIL_REQUEST_SET_MUTE,
ril_call_volume_mute_cb, g_free, cbd);
grilio_request_unref(req);
}
static void ril_call_volume_query_mute_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_call_volume *vd = user_data;
if (status == RIL_E_SUCCESS) {
int muted = 0;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
grilio_parser_get_int32(&rilp, NULL); /* Array length */
grilio_parser_get_int32(&rilp, &muted);
DBG("{%d}", muted);
ofono_call_volume_set_muted(vd->v, muted);
} else {
ofono_error("Could not retrive the ril mute state");
}
}
static gboolean ril_call_volume_register(gpointer user_data)
{
struct ril_call_volume *vd = user_data;
DBG("");
GASSERT(vd->timer_id);
vd->timer_id = 0;
ofono_call_volume_register(vd->v);
/* Probe the mute state */
grilio_queue_send_request_full(vd->q, NULL,
RIL_REQUEST_GET_MUTE, ril_call_volume_query_mute_cb, NULL, vd);
/* This makes the timeout a single-shot */
return FALSE;
}
static int ril_call_volume_probe(struct ofono_call_volume *v,
unsigned int vendor, void *data)
{
struct ril_modem *modem = data;
struct ril_call_volume *vd = g_new0(struct ril_call_volume, 1);
DBG("");
vd->v = v;
vd->q = grilio_queue_new(ril_modem_io(modem));
vd->timer_id = g_idle_add(ril_call_volume_register, vd);
ofono_call_volume_set_data(v, vd);
return 0;
}
static void ril_call_volume_remove(struct ofono_call_volume *v)
{
struct ril_call_volume *vd = ril_call_volume_get_data(v);
DBG("");
ofono_call_volume_set_data(v, NULL);
if (vd->timer_id) {
g_source_remove(vd->timer_id);
}
grilio_queue_cancel_all(vd->q, FALSE);
grilio_queue_unref(vd->q);
g_free(vd);
}
const struct ofono_call_volume_driver ril_call_volume_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_call_volume_probe,
.remove = ril_call_volume_remove,
.mute = ril_call_volume_mute,
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

119
ofono/drivers/ril/ril_cbs.c Normal file
View File

@@ -0,0 +1,119 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 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_util.h"
#include "ril_log.h"
#include "ril_constants.h"
struct ril_cbs {
struct ofono_cbs *cbs;
GRilIoChannel *io;
guint timer_id;
gulong event_id;
};
static void ril_set_topics(struct ofono_cbs *cbs, const char *topics,
ofono_cbs_set_cb_t cb, void *data)
{
struct ofono_error error;
cb(ril_error_ok(&error), data);
}
static void ril_clear_topics(struct ofono_cbs *cbs,
ofono_cbs_set_cb_t cb, void *data)
{
struct ofono_error error;
cb(ril_error_ok(&error), data);
}
static void ril_cbs_notify(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_cbs *cd = user_data;
GRilIoParser rilp;
char* pdu;
GASSERT(code == RIL_UNSOL_ON_USSD);
grilio_parser_init(&rilp, data, len);
pdu = grilio_parser_get_utf8(&rilp);
DBG("%s", pdu);
if (pdu) {
ofono_cbs_notify(cd->cbs, (const guchar *)pdu, strlen(pdu));
g_free(pdu);
}
}
static gboolean ril_cbs_register(gpointer user_data)
{
struct ril_cbs *cd = user_data;
DBG("");
GASSERT(cd->timer_id);
cd->timer_id = 0;
ofono_cbs_register(cd->cbs);
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
/* Single-shot */
return FALSE;
}
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
DBG("");
cd->cbs = cbs;
cd->io = grilio_channel_ref(ril_modem_io(modem));
cd->timer_id = g_idle_add(ril_cbs_register, cd);
ofono_cbs_set_data(cbs, cd);
return 0;
}
static void ril_cbs_remove(struct ofono_cbs *cbs)
{
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
DBG("");
ofono_cbs_set_data(cbs, NULL);
if (cd->timer_id > 0) {
g_source_remove(cd->timer_id);
}
grilio_channel_remove_handler(cd->io, cd->event_id);
grilio_channel_unref(cd->io);
g_free(cd);
}
const struct ofono_cbs_driver ril_cbs_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_cbs_probe,
.remove = ril_cbs_remove,
.set_topics = ril_set_topics,
.clear_topics = ril_clear_topics
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

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

@@ -0,0 +1,521 @@
/*
*
* RIL constants adopted from AOSP's header:
*
* /hardware/ril/reference_ril/ril.h
*
* Copyright (C) 2013 Canonical 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
* 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_CONSTANTS_H
#define __RIL_CONSTANTS_H 1
/* Error Codes */
#define RIL_E_SUCCESS 0
#define RIL_E_RADIO_NOT_AVAILABLE 1
#define RIL_E_GENERIC_FAILURE 2
#define RIL_E_PASSWORD_INCORRECT 3
#define RIL_E_SIM_PIN2 4
#define RIL_E_SIM_PUK2 5
#define RIL_E_REQUEST_NOT_SUPPORTED 6
#define RIL_E_CANCELLED 7
#define RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL 8
#define RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW 9
#define RIL_E_SMS_SEND_FAIL_RETRY 10
#define RIL_E_SIM_ABSENT 11
#define RIL_E_SUBSCRIPTION_NOT_AVAILABLE 12
#define RIL_E_MODE_NOT_SUPPORTED 13
#define RIL_E_FDN_CHECK_FAILURE 14
#define RIL_E_ILLEGAL_SIM_OR_ME 15
#define RIL_E_UNUSED 16
#define RIL_E_DIAL_MODIFIED_TO_USSD 17
#define RIL_E_DIAL_MODIFIED_TO_SS 18
#define RIL_E_DIAL_MODIFIED_TO_DIAL 19
#define RIL_E_USSD_MODIFIED_TO_DIAL 20
#define RIL_E_USSD_MODIFIED_TO_SS 21
#define RIL_E_USSD_MODIFIED_TO_USSD 22
#define RIL_E_SS_MODIFIED_TO_DIAL 23
#define RIL_E_SS_MODIFIED_TO_USSD 24
#define RIL_E_SS_MODIFIED_TO_SS 25
#define RIL_E_SUBSCRIPTION_NOT_SUPPORTED 26
#define RIL_E_MISSING_RESOURCE 27
#define RIL_E_NO_SUCH_ELEMENT 28
#define RIL_E_INVALID_PARAMETER 29
/* call states */
enum ril_call_state {
RIL_CALL_ACTIVE = 0,
RIL_CALL_HOLDING = 1,
RIL_CALL_DIALING = 2,
RIL_CALL_ALERTING = 3,
RIL_CALL_INCOMING = 4,
RIL_CALL_WAITING = 5
};
/* Radio state */
enum ril_radio_state {
RADIO_STATE_OFF = 0,
RADIO_STATE_UNAVAILABLE = 1,
RADIO_STATE_SIM_NOT_READY = 2,
RADIO_STATE_SIM_LOCKED_OR_ABSENT = 3,
RADIO_STATE_SIM_READY = 4,
RADIO_STATE_RUIM_NOT_READY = 5,
RADIO_STATE_RUIM_READY = 6,
RADIO_STATE_RUIM_LOCKED_OR_ABSENT = 7,
RADIO_STATE_NV_NOT_READY = 8,
RADIO_STATE_NV_READY = 9,
RADIO_STATE_ON = 10
};
/* Preferred network types */
enum ril_pref_net_type {
PREF_NET_TYPE_GSM_WCDMA = 0,
PREF_NET_TYPE_GSM_ONLY = 1,
PREF_NET_TYPE_WCDMA = 2,
PREF_NET_TYPE_GSM_WCDMA_AUTO = 3,
PREF_NET_TYPE_CDMA_EVDO_AUTO = 4,
PREF_NET_TYPE_CDMA_ONLY = 5,
PREF_NET_TYPE_EVDO_ONLY = 6,
PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7,
PREF_NET_TYPE_LTE_CDMA_EVDO = 8,
PREF_NET_TYPE_LTE_GSM_WCDMA = 9,
PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10,
PREF_NET_TYPE_LTE_ONLY = 11,
PREF_NET_TYPE_LTE_WCDMA = 12
};
/* Radio technologies */
enum ril_radio_tech {
RADIO_TECH_UNKNOWN = 0,
RADIO_TECH_GPRS = 1,
RADIO_TECH_EDGE = 2,
RADIO_TECH_UMTS = 3,
RADIO_TECH_IS95A = 4,
RADIO_TECH_IS95B = 5,
RADIO_TECH_1xRTT = 6,
RADIO_TECH_EVDO_0 = 7,
RADIO_TECH_EVDO_A = 8,
RADIO_TECH_HSDPA = 9,
RADIO_TECH_HSUPA = 10,
RADIO_TECH_HSPA = 11,
RADIO_TECH_EVDO_B = 12,
RADIO_TECH_EHRPD = 13,
RADIO_TECH_LTE = 14,
RADIO_TECH_HSPAP = 15,
RADIO_TECH_GSM = 16,
RADIO_TECH_TD_SCDMA = 17,
RADIO_TECH_IWLAN = 18
};
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
#define CALL_FAIL_UNOBTAINABLE_NUMBER 1
#define CALL_FAIL_NORMAL 16
#define CALL_FAIL_BUSY 17
#define CALL_FAIL_CONGESTION 34
#define CALL_FAIL_ACM_LIMIT_EXCEEDED 68
#define CALL_FAIL_CALL_BARRED 240
#define CALL_FAIL_FDN_BLOCKED 241
#define CALL_FAIL_IMSI_UNKNOWN_IN_VLR 242
#define CALL_FAIL_IMEI_NOT_ACCEPTED 243
#define CALL_FAIL_DIAL_MODIFIED_TO_USSD 244
#define CALL_FAIL_DIAL_MODIFIED_TO_SS 245
#define CALL_FAIL_DIAL_MODIFIED_TO_DIAL 246
#define CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE 1000
#define CALL_FAIL_CDMA_DROP 1001
#define CALL_FAIL_CDMA_INTERCEPT 1002
#define CALL_FAIL_CDMA_REORDER 1003
#define CALL_FAIL_CDMA_SO_REJECT 1004
#define CALL_FAIL_CDMA_RETRY_ORDER 1005
#define CALL_FAIL_CDMA_ACCESS_FAILURE 1006
#define CALL_FAIL_CDMA_PREEMPTED 1007
#define CALL_FAIL_CDMA_NOT_EMERGENCY 1008
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
/* Not defined in ril.h but valid 3GPP specific cause values
* for call control. See 3GPP TS 24.008 Annex H. */
#define CALL_FAIL_NO_ROUTE_TO_DESTINATION 3
#define CALL_FAIL_CHANNEL_UNACCEPTABLE 6
#define CALL_FAIL_OPERATOR_DETERMINED_BARRING 8
#define CALL_FAIL_NO_USER_RESPONDING 18
#define CALL_FAIL_USER_ALERTING_NO_ANSWER 19
#define CALL_FAIL_CALL_REJECTED 21
#define CALL_FAIL_NUMBER_CHANGED 22
#define CALL_FAIL_ANONYMOUS_CALL_REJECTION 24
#define CALL_FAIL_PRE_EMPTION 25
#define CALL_FAIL_DESTINATION_OUT_OF_ORDER 27
#define CALL_FAIL_INCOMPLETE_NUMBER 28
#define CALL_FAIL_FACILITY_REJECTED 29
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
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
/* 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
};
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
/* SIM card states */
enum ril_card_state {
RIL_CARDSTATE_UNKNOWN = -1,
RIL_CARDSTATE_ABSENT = 0,
RIL_CARDSTATE_PRESENT = 1,
RIL_CARDSTATE_ERROR = 2
};
/* SIM personalization substates */
enum ril_perso_substate {
RIL_PERSOSUBSTATE_UNKNOWN = 0,
RIL_PERSOSUBSTATE_IN_PROGRESS = 1,
RIL_PERSOSUBSTATE_READY = 2,
RIL_PERSOSUBSTATE_SIM_NETWORK = 3,
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4,
RIL_PERSOSUBSTATE_SIM_CORPORATE = 5,
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6,
RIL_PERSOSUBSTATE_SIM_SIM = 7,
RIL_PERSOSUBSTATE_SIM_NETWORK_PUK = 8,
RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9,
RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10,
RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11,
RIL_PERSOSUBSTATE_SIM_SIM_PUK = 12,
RIL_PERSOSUBSTATE_RUIM_NETWORK1 = 13,
RIL_PERSOSUBSTATE_RUIM_NETWORK2 = 14,
RIL_PERSOSUBSTATE_RUIM_HRPD = 15,
RIL_PERSOSUBSTATE_RUIM_CORPORATE = 16,
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17,
RIL_PERSOSUBSTATE_RUIM_RUIM = 18,
RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19,
RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20,
RIL_PERSOSUBSTATE_RUIM_HRPD_PUK = 21,
RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22,
RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23,
RIL_PERSOSUBSTATE_RUIM_RUIM_PUK = 24
};
/* SIM - App states */
enum ril_app_state {
RIL_APPSTATE_ILLEGAL = -1,
RIL_APPSTATE_UNKNOWN = 0,
RIL_APPSTATE_DETECTED = 1,
RIL_APPSTATE_PIN = 2,
RIL_APPSTATE_PUK = 3,
RIL_APPSTATE_SUBSCRIPTION_PERSO = 4,
RIL_APPSTATE_READY = 5
};
/* SIM - PIN states */
enum ril_pin_state {
RIL_PINSTATE_UNKNOWN = 0,
RIL_PINSTATE_ENABLED_NOT_VERIFIED = 1,
RIL_PINSTATE_ENABLED_VERIFIED = 2,
RIL_PINSTATE_DISABLED = 3,
RIL_PINSTATE_ENABLED_BLOCKED = 4,
RIL_PINSTATE_ENABLED_PERM_BLOCKED = 5
};
/* SIM - App types */
enum ril_app_type {
RIL_APPTYPE_UNKNOWN = 0,
RIL_APPTYPE_SIM = 1,
RIL_APPTYPE_USIM = 2,
RIL_APPTYPE_RUIM = 3,
RIL_APPTYPE_CSIM = 4,
RIL_APPTYPE_ISIM = 5
};
/* 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
#define RIL_REQUEST_ENTER_SIM_PUK 3
#define RIL_REQUEST_ENTER_SIM_PIN2 4
#define RIL_REQUEST_ENTER_SIM_PUK2 5
#define RIL_REQUEST_CHANGE_SIM_PIN 6
#define RIL_REQUEST_CHANGE_SIM_PIN2 7
#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
#define RIL_REQUEST_GET_CURRENT_CALLS 9
#define RIL_REQUEST_DIAL 10
#define RIL_REQUEST_GET_IMSI 11
#define RIL_REQUEST_HANGUP 12
#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
#define RIL_REQUEST_CONFERENCE 16
#define RIL_REQUEST_UDUB 17
#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
#define RIL_REQUEST_SIGNAL_STRENGTH 19
#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
#define RIL_REQUEST_OPERATOR 22
#define RIL_REQUEST_RADIO_POWER 23
#define RIL_REQUEST_DTMF 24
#define RIL_REQUEST_SEND_SMS 25
#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
#define RIL_REQUEST_SETUP_DATA_CALL 27
#define RIL_REQUEST_SIM_IO 28
#define RIL_REQUEST_SEND_USSD 29
#define RIL_REQUEST_CANCEL_USSD 30
#define RIL_REQUEST_GET_CLIR 31
#define RIL_REQUEST_SET_CLIR 32
#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
#define RIL_REQUEST_SET_CALL_FORWARD 34
#define RIL_REQUEST_QUERY_CALL_WAITING 35
#define RIL_REQUEST_SET_CALL_WAITING 36
#define RIL_REQUEST_SMS_ACKNOWLEDGE 37
#define RIL_REQUEST_GET_IMEI 38
#define RIL_REQUEST_GET_IMEISV 39
#define RIL_REQUEST_ANSWER 40
#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
#define RIL_REQUEST_SET_FACILITY_LOCK 43
#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
#define RIL_REQUEST_DTMF_START 49
#define RIL_REQUEST_DTMF_STOP 50
#define RIL_REQUEST_BASEBAND_VERSION 51
#define RIL_REQUEST_SEPARATE_CONNECTION 52
#define RIL_REQUEST_SET_MUTE 53
#define RIL_REQUEST_GET_MUTE 54
#define RIL_REQUEST_QUERY_CLIP 55
#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
#define RIL_REQUEST_DATA_CALL_LIST 57
#define RIL_REQUEST_RESET_RADIO 58
#define RIL_REQUEST_OEM_HOOK_RAW 59
#define RIL_REQUEST_OEM_HOOK_STRINGS 60
#define RIL_REQUEST_SCREEN_STATE 61
#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
#define RIL_REQUEST_SET_BAND_MODE 65
#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
#define RIL_REQUEST_STK_GET_PROFILE 67
#define RIL_REQUEST_STK_SET_PROFILE 68
#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
#define RIL_REQUEST_SET_LOCATION_UPDATES 76
#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
#define RIL_REQUEST_SET_TTY_MODE 80
#define RIL_REQUEST_QUERY_TTY_MODE 81
#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
#define RIL_REQUEST_CDMA_FLASH 84
#define RIL_REQUEST_CDMA_BURST_DTMF 85
#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
#define RIL_REQUEST_CDMA_SEND_SMS 87
#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
#define RIL_REQUEST_DEVICE_IDENTITY 98
#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
#define RIL_REQUEST_GET_SMSC_ADDRESS 100
#define RIL_REQUEST_SET_SMSC_ADDRESS 101
#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
#define RIL_REQUEST_ISIM_AUTHENTICATION 105
#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
#define RIL_REQUEST_VOICE_RADIO_TECH 108
#define RIL_REQUEST_GET_CELL_INFO_LIST 109
#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
#define RIL_REQUEST_IMS_SEND_SMS 113
#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
#define RIL_REQUEST_NV_READ_ITEM 118
#define RIL_REQUEST_NV_WRITE_ITEM 119
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
#define RIL_REQUEST_NV_RESET_CONFIG 121
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
#define RIL_REQUEST_ALLOW_DATA 123
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
#define RIL_REQUEST_SIM_AUTHENTICATION 125
#define RIL_REQUEST_GET_DC_RT_INFO 126
#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
#define RIL_REQUEST_SET_DATA_PROFILE 128
#define RIL_REQUEST_SHUTDOWN 129
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
/* RIL Unsolicited Messages */
#define RIL_UNSOL_RESPONSE_BASE 1000
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
#define RIL_UNSOL_ON_USSD 1006
#define RIL_UNSOL_ON_USSD_REQUEST 1007
#define RIL_UNSOL_NITZ_TIME_RECEIVED 1008
#define RIL_UNSOL_SIGNAL_STRENGTH 1009
#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
#define RIL_UNSOL_STK_SESSION_END 1012
#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
#define RIL_UNSOL_STK_CALL_SETUP 1015
#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
#define RIL_UNSOL_SIM_REFRESH 1017
#define RIL_UNSOL_CALL_RING 1018
#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
#define RIL_UNSOL_CDMA_CALL_WAITING 1025
#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
#define RIL_UNSOL_CDMA_INFO_REC 1027
#define RIL_UNSOL_OEM_HOOK_RAW 1028
#define RIL_UNSOL_RINGBACK_TONE 1029
#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
#define RIL_UNSOL_RIL_CONNECTED 1034
#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
#define RIL_UNSOL_CELL_INFO_LIST 1036
#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
#define RIL_UNSOL_RADIO_CAPABILITY 1042
#define RIL_UNSOL_ON_SS 1043
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
/* Suplementary services Service class*/
#define SERVICE_CLASS_NONE 0
/* RIL_FACILITY_LOCK parameters */
#define RIL_FACILITY_UNLOCK "0"
#define RIL_FACILITY_LOCK "1"
#endif /*__RIL_CONSTANTS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

1514
ofono/drivers/ril/ril_data.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,118 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_DATA_H
#define RIL_DATA_H
#include "ril_types.h"
#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(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);
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);
gboolean ril_data_allowed(struct ril_data *data);
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 */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,193 @@
/*
* 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_util.h"
#include "ril_log.h"
/*
* TODO: No public RIL api to query manufacturer or model.
* Check where to get, could /system/build.prop be updated to have good values?
*/
struct ril_devinfo {
struct ofono_devinfo *info;
GRilIoQueue *q;
guint register_id;
guint imei_id;
char *imei;
};
struct ril_devinfo_cbd {
struct ril_devinfo *di;
ofono_devinfo_query_cb_t cb;
gpointer data;
};
#define ril_devinfo_cbd_free g_free
static inline struct ril_devinfo *ril_devinfo_get_data(
struct ofono_devinfo *info)
{
return ofono_devinfo_get_data(info);
}
struct ril_devinfo_cbd *ril_devinfo_cbd_new(struct ril_devinfo *di,
ofono_devinfo_query_cb_t cb, void *data)
{
struct ril_devinfo_cbd *cbd = g_new0(struct ril_devinfo_cbd, 1);
cbd->di = di;
cbd->cb = cb;
cbd->data = data;
return cbd;
}
static void ril_devinfo_query_unsupported(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb, void *data)
{
struct ofono_error error;
cb(ril_error_failure(&error), "", data);
}
static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_devinfo_cbd *cbd = user_data;
if (status == RIL_E_SUCCESS) {
char *res;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
res = grilio_parser_get_utf8(&rilp);
DBG("%s", res);
cbd->cb(ril_error_ok(&error), res ? res : "", cbd->data);
g_free(res);
} else {
cbd->cb(ril_error_failure(&error), NULL, cbd->data);
}
}
static void ril_devinfo_query_revision(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb, void *data)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG("");
grilio_queue_send_request_full(di->q, NULL, RIL_REQUEST_BASEBAND_VERSION,
ril_devinfo_query_cb, ril_devinfo_cbd_free,
ril_devinfo_cbd_new(di, cb, data));
}
static gboolean ril_devinfo_query_serial_cb(void *user_data)
{
struct ril_devinfo_cbd *cbd = user_data;
struct ril_devinfo *di = cbd->di;
struct ofono_error error;
GASSERT(di->imei_id);
di->imei_id = 0;
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
return FALSE;
}
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb,
void *data)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
GASSERT(!di->imei_id);
if (di->imei_id) {
g_source_remove(di->imei_id);
di->imei_id = 0;
}
DBG("%s", di->imei);
di->imei_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_devinfo_query_serial_cb,
ril_devinfo_cbd_new(di, cb, data),
ril_devinfo_cbd_free);
}
static gboolean ril_devinfo_register(gpointer user_data)
{
struct ril_devinfo *di = user_data;
DBG("");
di->register_id = 0;
ofono_devinfo_register(di->info);
/* This makes the timeout a single-shot */
return FALSE;
}
static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
DBG("%s %s %p", ril_modem_get_path(modem), modem->imei, di);
GASSERT(modem->imei);
di->q = grilio_queue_new(ril_modem_io(modem));
di->info = info;
di->imei = g_strdup(modem->imei);
di->register_id = g_idle_add(ril_devinfo_register, di);
ofono_devinfo_set_data(info, di);
return 0;
}
static void ril_devinfo_remove(struct ofono_devinfo *info)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG("%p", di);
ofono_devinfo_set_data(info, NULL);
if (di->register_id > 0) {
g_source_remove(di->register_id);
}
if (di->imei_id > 0) {
g_source_remove(di->imei_id);
}
grilio_queue_cancel_all(di->q, FALSE);
grilio_queue_unref(di->q);
g_free(di->imei);
g_free(di);
}
const struct ofono_devinfo_driver ril_devinfo_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_devinfo_probe,
.remove = ril_devinfo_remove,
.query_manufacturer = ril_devinfo_query_unsupported,
.query_model = ril_devinfo_query_unsupported,
.query_revision = ril_devinfo_query_revision,
.query_serial = ril_devinfo_query_serial
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

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

@@ -0,0 +1,283 @@
/*
* 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_network.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
#include "common.h"
/*
* This module is the ofono_gprs_driver implementation for rilmodem.
*
* Notes:
*
* 1. ofono_gprs_suspend/resume() are not used by this module, as
* the concept of suspended GPRS is not exposed by RILD.
*
* 2. ofono_gprs_bearer_notify() is never called as RILD does not
* expose an unsolicited event equivalent to +CPSB ( see 27.007
* 7.29 ), and the tech values returned by REQUEST_DATA/VOICE
* _REGISTRATION requests do not match the values defined for
* <AcT> in the +CPSB definition. Note, the values returned by
* the *REGISTRATION commands are aligned with those defined by
* +CREG ( see 27.003 7.2 ).
*/
struct ril_gprs {
struct ofono_gprs *gprs;
struct ril_modem *md;
struct ril_data *data;
struct ril_network *network;
GRilIoChannel *io;
GRilIoQueue *q;
gboolean attached;
int max_cids;
enum network_registration_status registration_status;
guint register_id;
gulong network_event_id;
gulong data_event_id;
guint set_attached_id;
};
struct ril_gprs_cbd {
struct ril_gprs *gd;
ofono_gprs_cb_t cb;
gpointer data;
};
#define ril_gprs_cbd_free g_free
static struct ril_gprs *ril_gprs_get_data(struct ofono_gprs *ofono)
{
return ofono ? ofono_gprs_get_data(ofono) : NULL;
}
static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd,
ofono_gprs_cb_t cb, void *data)
{
struct ril_gprs_cbd *cbd = g_new0(struct ril_gprs_cbd, 1);
cbd->gd = gd;
cbd->cb = cb;
cbd->data = data;
return cbd;
}
static enum network_registration_status ril_gprs_fix_registration_status(
struct ril_gprs *gd, enum network_registration_status status)
{
if (!ril_data_allowed(gd->data)) {
return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
} else {
/* TODO: need a way to make sure that SPDI information has
* already been read from the SIM (i.e. sim_spdi_read_cb in
* network.c has been called) */
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gd->md);
return ril_netreg_check_if_really_roaming(netreg, status);
}
}
static void ril_gprs_data_update_registration_state(struct ril_gprs *gd)
{
const enum network_registration_status status =
ril_gprs_fix_registration_status(gd, gd->network->data.status);
if (gd->registration_status != status) {
ofono_info("data reg changed %d -> %d (%s), attached %d",
gd->registration_status, status,
registration_status_to_string(status),
gd->attached);
gd->registration_status = status;
ofono_gprs_status_notify(gd->gprs, gd->registration_status);
}
}
static void ril_gprs_check_data_allowed(struct ril_gprs *gd)
{
DBG("%s %d %d", ril_modem_get_path(gd->md), ril_data_allowed(gd->data),
gd->attached);
if (!ril_data_allowed(gd->data) && gd->attached) {
gd->attached = FALSE;
if (gd->gprs) {
ofono_gprs_detached_notify(gd->gprs);
}
}
ril_gprs_data_update_registration_state(gd);
}
static gboolean ril_gprs_set_attached_cb(gpointer user_data)
{
struct ofono_error error;
struct ril_gprs_cbd *cbd = user_data;
struct ril_gprs *gd = cbd->gd;
GASSERT(gd->set_attached_id);
gd->set_attached_id = 0;
ril_gprs_check_data_allowed(gd);
cbd->cb(ril_error_ok(&error), cbd->data);
return FALSE;
}
static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
ofono_gprs_cb_t cb, void *data)
{
struct ril_gprs *gd = ril_gprs_get_data(gprs);
if (ril_data_allowed(gd->data) || !attached) {
DBG("%s attached: %d", ril_modem_get_path(gd->md), attached);
if (gd->set_attached_id) {
g_source_remove(gd->set_attached_id);
}
gd->attached = attached;
gd->set_attached_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_gprs_set_attached_cb,
ril_gprs_cbd_new(gd, cb, data),
ril_gprs_cbd_free);
} else {
struct ofono_error error;
DBG("%s not allowed to attach", ril_modem_get_path(gd->md));
cb(ril_error_failure(&error), data);
}
}
static void ril_gprs_allow_data_changed(struct ril_data *data, void *user_data)
{
struct ril_gprs *gd = user_data;
GASSERT(gd->data == data);
DBG("%s %d", ril_modem_get_path(gd->md), ril_data_allowed(data));
if (!gd->set_attached_id) {
ril_gprs_check_data_allowed(gd);
}
}
static void ril_gprs_data_registration_state_changed(struct ril_network *net,
void *user_data)
{
struct ril_gprs *gd = user_data;
const struct ril_registration_state *data = &net->data;
GASSERT(gd->network == net);
if (data->max_calls > gd->max_cids) {
DBG("Setting max cids to %d", data->max_calls);
gd->max_cids = data->max_calls;
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
}
ril_gprs_data_update_registration_state(gd);
}
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
ofono_gprs_status_cb_t cb, void *data)
{
struct ril_gprs *gd = ril_gprs_get_data(gprs);
struct ofono_error error;
const enum network_registration_status status = gd->attached ?
gd->registration_status :
NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
DBG("%d (%s)", status, registration_status_to_string(status));
cb(ril_error_ok(&error), status, data);
}
static gboolean ril_gprs_register(gpointer user_data)
{
struct ril_gprs *gd = user_data;
gd->register_id = 0;
gd->network_event_id = ril_network_add_data_state_changed_handler(
gd->network, ril_gprs_data_registration_state_changed, gd);
gd->data_event_id = ril_data_add_allow_changed_handler(gd->data,
ril_gprs_allow_data_changed, gd);
gd->registration_status = ril_gprs_fix_registration_status(gd,
gd->network->data.status);
gd->max_cids = gd->network->data.max_calls;
if (gd->max_cids > 0) {
DBG("Setting max cids to %d", gd->max_cids);
ofono_gprs_set_cid_range(gd->gprs, 1, gd->max_cids);
}
ofono_gprs_register(gd->gprs);
return FALSE;
}
static int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
struct ril_gprs *gd = g_new0(struct ril_gprs, 1);
DBG("%s", ril_modem_get_path(modem));
gd->md = modem;
gd->io = grilio_channel_ref(ril_modem_io(modem));
gd->q = grilio_queue_new(gd->io);
gd->data = ril_data_ref(modem->data);
gd->network = ril_network_ref(modem->network);
gd->gprs = gprs;
ofono_gprs_set_data(gprs, gd);
/* ofono crashes if we register right away */
gd->register_id = g_idle_add(ril_gprs_register, gd);
return 0;
}
static void ril_gprs_remove(struct ofono_gprs *gprs)
{
struct ril_gprs *gd = ril_gprs_get_data(gprs);
DBG("%s", ril_modem_get_path(gd->md));
ofono_gprs_set_data(gprs, NULL);
if (gd->set_attached_id) {
g_source_remove(gd->set_attached_id);
}
if (gd->register_id) {
g_source_remove(gd->register_id);
}
ril_network_remove_handler(gd->network, gd->network_event_id);
ril_network_unref(gd->network);
ril_data_remove_handler(gd->data, gd->data_event_id);
ril_data_unref(gd->data);
grilio_channel_unref(gd->io);
grilio_queue_cancel_all(gd->q, FALSE);
grilio_queue_unref(gd->q);
g_free(gd);
}
const struct ofono_gprs_driver ril_gprs_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_gprs_probe,
.remove = ril_gprs_remove,
.set_attached = ril_gprs_set_attached,
.attached_status = ril_gprs_registration_status,
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,680 @@
/*
* 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_network.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_mtu.h"
#include "ril_log.h"
#include <gutil_strv.h>
#include <arpa/inet.h>
#include "common.h"
#define CTX_ID_NONE ((unsigned int)(-1))
#define MAX_MTU 1280
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;
struct ril_data *data;
guint active_ctx_cid;
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;
};
static inline struct ril_gprs_context *ril_gprs_context_get_data(
struct ofono_gprs_context *gprs)
{
return ofono_gprs_context_get_data(gprs);
}
static char *ril_gprs_context_netmask(const char *address)
{
if (address) {
const char *suffix = strchr(address, '/');
if (suffix) {
int nbits = atoi(suffix + 1);
if (nbits > 0 && nbits < 33) {
const char* str;
struct in_addr in;
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
((1 << nbits)-1) << (32-nbits));
str = inet_ntoa(in);
if (str) {
return g_strdup(str);
}
}
}
}
return g_strdup("255.255.255.0");
}
static void ril_gprs_context_set_ipv4(struct ofono_gprs_context *gc,
char * const *ip_addr)
{
const guint n = gutil_strv_length(ip_addr);
if (n > 0) {
ofono_gprs_context_set_ipv4_address(gc, ip_addr[0], TRUE);
if (n > 1) {
ofono_gprs_context_set_ipv4_netmask(gc, ip_addr[1]);
}
}
}
static void ril_gprs_context_set_ipv6(struct ofono_gprs_context *gc,
char * const *ipv6_addr)
{
const guint n = gutil_strv_length(ipv6_addr);
if (n > 0) {
ofono_gprs_context_set_ipv6_address(gc, ipv6_addr[0]);
if (n > 1) {
const int p = atoi(ipv6_addr[1]);
if (p > 0 && p <= 128) {
ofono_gprs_context_set_ipv6_prefix_length(gc, p);
}
}
}
}
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) {
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)
{
if (gcd->active_call) {
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);
}
}
}
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);
}
}
static void ril_gprs_split_ip_by_protocol(char **ip_array,
char ***split_ip_addr,
char ***split_ipv6_addr)
{
const int n = gutil_strv_length(ip_array);
int i;
*split_ipv6_addr = *split_ip_addr = NULL;
for (i = 0; i < n && (!*split_ipv6_addr || !*split_ip_addr); i++) {
const char *addr = ip_array[i];
switch (ril_address_family(addr)) {
case AF_INET:
if (!*split_ip_addr) {
char *mask = ril_gprs_context_netmask(addr);
*split_ip_addr = g_strsplit(addr, "/", 2);
if (gutil_strv_length(*split_ip_addr) == 2) {
g_free((*split_ip_addr)[1]);
(*split_ip_addr)[1] = mask;
} else {
/* This is rather unlikely to happen */
*split_ip_addr =
gutil_strv_add(*split_ip_addr,
mask);
g_free(mask);
}
}
break;
case AF_INET6:
if (!*split_ipv6_addr) {
*split_ipv6_addr = g_strsplit(addr, "/", 2);
}
}
}
}
static void ril_gprs_split_gw_by_protocol(char **gw_array, char **ip_gw,
char **ipv6_gw)
{
const int n = gutil_strv_length(gw_array);
int i;
*ip_gw = *ipv6_gw = NULL;
for (i = 0; i < n && (!*ipv6_gw || !*ip_gw); i++) {
const char *gw_addr = gw_array[i];
switch (ril_address_family(gw_addr)) {
case AF_INET:
if (!*ip_gw) *ip_gw = g_strdup(gw_addr);
break;
case AF_INET6:
if (!*ipv6_gw) *ipv6_gw = g_strdup(gw_addr);
break;
}
}
}
static void ril_gprs_split_dns_by_protocol(char **dns_array, char ***dns_addr,
char ***dns_ipv6_addr)
{
const int n = gutil_strv_length(dns_array);
int i;
*dns_ipv6_addr = *dns_addr = 0;
for (i = 0; i < n; i++) {
const char *addr = dns_array[i];
switch (ril_address_family(addr)) {
case AF_INET:
*dns_addr = gutil_strv_add(*dns_addr, addr);
break;
case AF_INET6:
*dns_ipv6_addr = gutil_strv_add(*dns_ipv6_addr, addr);
break;
}
}
}
/* Only compares the stuff that's important to us */
static gboolean ril_gprs_context_data_call_equal(
const struct ril_data_call *c1,
const struct ril_data_call *c2)
{
if (!c1 && !c2) {
return TRUE;
} else if (c1 && c2) {
return c1->cid == c2->cid &&
c1->active == c2->active && c1->prot == c2->prot &&
!g_strcmp0(c1->ifname, c2->ifname) &&
gutil_strv_equal(c1->dnses, c2->dnses) &&
gutil_strv_equal(c1->gateways, c2->gateways) &&
gutil_strv_equal(c1->addresses, c2->addresses);
} else {
return FALSE;
}
}
static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
{
struct ril_gprs_context *gcd = arg;
struct ofono_gprs_context *gc = gcd->gc;
/*
* 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);
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;
/* 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;
}
/*
* 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 != PDP_FAIL_NONE) {
ofono_info("data call status: %d", call->status);
}
if (call->active == RIL_DATA_CALL_ACTIVE) {
gboolean signal = FALSE;
if (call->ifname && g_strcmp0(call->ifname, prev_call->ifname)) {
DBG("interface changed");
signal = TRUE;
ofono_gprs_context_set_interface(gc, call->ifname);
}
if (!gutil_strv_equal(call->addresses, prev_call->addresses)) {
char **split_ip_addr = NULL;
char **split_ipv6_addr = NULL;
DBG("address changed");
signal = TRUE;
/* Pick 1 address of each protocol */
ril_gprs_split_ip_by_protocol(call->addresses,
&split_ip_addr, &split_ipv6_addr);
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
call->prot == OFONO_GPRS_PROTO_IPV6) &&
split_ipv6_addr) {
ril_gprs_context_set_ipv6(gc, split_ipv6_addr);
}
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
call->prot == OFONO_GPRS_PROTO_IP) &&
split_ip_addr) {
ril_gprs_context_set_ipv4(gc, split_ip_addr);
}
g_strfreev(split_ip_addr);
g_strfreev(split_ipv6_addr);
}
if (!gutil_strv_equal(call->gateways, prev_call->gateways)){
char *ip_gw = NULL;
char *ipv6_gw = NULL;
DBG("gateway changed");
signal = TRUE;
/* Pick 1 gw for each protocol*/
ril_gprs_split_gw_by_protocol(call->gateways,
&ip_gw, &ipv6_gw);
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
call->prot == OFONO_GPRS_PROTO_IPV6) &&
ipv6_gw) {
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
}
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
call->prot == OFONO_GPRS_PROTO_IP) &&
ip_gw) {
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
}
g_free(ip_gw);
g_free(ipv6_gw);
}
if (!gutil_strv_equal(call->dnses, prev_call->dnses)){
char **dns_ip = NULL;
char **dns_ipv6 = NULL;
DBG("name server(s) changed");
signal = TRUE;
/* split based on protocol*/
ril_gprs_split_dns_by_protocol(call->dnses,
&dns_ip, &dns_ipv6);
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
call->prot == OFONO_GPRS_PROTO_IPV6) &&
dns_ipv6) {
ofono_gprs_context_set_ipv6_dns_servers(gc,
(const char **) dns_ipv6);
}
if ((call->prot == OFONO_GPRS_PROTO_IPV4V6 ||
call->prot == OFONO_GPRS_PROTO_IP) && dns_ip) {
ofono_gprs_context_set_ipv4_dns_servers(gc,
(const char**)dns_ip);
}
g_strfreev(dns_ip);
g_strfreev(dns_ipv6);
}
if (signal) {
ofono_gprs_context_signal_change(gc, call->cid);
}
}
ril_data_call_free(prev_call);
}
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 *gcd = user_data;
struct ofono_gprs_context *gc = gcd->gc;
struct ofono_error error;
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;
ril_error_init_failure(&error);
if (ril_status != RIL_E_SUCCESS) {
ofono_error("GPRS context: Reply failure: %s",
ril_error_to_string(ril_status));
goto done;
}
if (call->status != PDP_FAIL_NONE) {
ofono_error("Unexpected data call status %d", call->status);
error.type = OFONO_ERROR_TYPE_CMS;
error.error = call->status;
goto done;
}
/* Must have interface */
if (!call->ifname) {
ofono_error("GPRS context: No interface");
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");
goto done;
}
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);
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,
(const char **) dns_ipv6_addr);
}
if (split_ip_addr &&
(call->prot == OFONO_GPRS_PROTO_IP ||
call->prot == OFONO_GPRS_PROTO_IPV4V6)) {
ril_gprs_context_set_ipv4(gc, split_ip_addr);
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
ofono_gprs_context_set_ipv4_dns_servers(gc,
(const char **) dns_addr);
}
done:
g_strfreev(split_ip_addr);
g_strfreev(split_ipv6_addr);
g_strfreev(dns_addr);
g_strfreev(dns_ipv6_addr);
g_free(ip_gw);
g_free(ipv6_gw);
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,
const struct ofono_gprs_primary_context *ctx,
ofono_gprs_context_cb_t cb, void *data)
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gcd->modem);
const int rs = ofono_netreg_get_status(netreg);
/* 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) {
struct ofono_error error;
ofono_info("Can't activate context %d (roaming)",
ctx->cid);
cb(ril_error_failure(&error), data);
return;
}
}
ofono_info("Activating context: %d", ctx->cid);
GASSERT(!gcd->activate.req);
GASSERT(ctx->cid != CTX_ID_NONE);
gcd->active_ctx_cid = ctx->cid;
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_primary_cb(struct ril_data *data,
int ril_status, void *user_data)
{
struct ril_gprs_context *gcd = user_data;
/*
* 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.
*/
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,
unsigned int id, ofono_gprs_context_cb_t cb, void *data)
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
ofono_info("Deactivate primary");
if (gcd->active_call && gcd->active_ctx_cid == id) {
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);
}
}
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
unsigned int id)
{
DBG("%d", id);
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
}
static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
unsigned int vendor, void *data)
{
struct ril_modem *modem = data;
struct ril_gprs_context *gcd = g_new0(struct ril_gprs_context, 1);
DBG("");
gcd->gc = gc;
gcd->modem = modem;
gcd->network = ril_network_ref(modem->network);
gcd->data = ril_data_ref(modem->data);
gcd->active_ctx_cid = CTX_ID_NONE;
ofono_gprs_context_set_data(gc, gcd);
return 0;
}
static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
DBG("");
ofono_gprs_context_set_data(gc, 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) {
/* 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);
ril_data_call_free(gcd->active_call);
ril_mtu_watch_free(gcd->mtu_watch);
g_free(gcd);
}
const struct ofono_gprs_context_driver ril_gprs_context_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_gprs_context_probe,
.remove = ril_gprs_context_remove,
.activate_primary = ril_gprs_context_activate_primary,
.deactivate_primary = ril_gprs_context_deactivate_primary,
.detach_shutdown = ril_gprs_context_detach_shutdown,
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,31 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 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_LOG_H
#define RIL_LOG_H
#define GLOG_MODULE_NAME ril_log
#include <gutil_log.h>
#include <ofono/log.h>
#endif /* RIL_LOG_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

268
ofono/drivers/ril/ril_mce.c Normal file
View File

@@ -0,0 +1,268 @@
/*
* 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_mce.h"
#include "ril_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"
typedef GObjectClass RilMceClass;
typedef struct ril_mce RilMce;
struct ril_mce_priv {
GRilIoChannel *io;
DBusConnection *conn;
DBusPendingCall *req;
guint daemon_watch;
guint signal_watch;
};
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)
{
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;
}
}
static enum ril_mce_display_state ril_mce_parse_display_state(DBusMessage *msg)
{
DBusMessageIter it;
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 *msg, void *user_data)
{
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 *self = RIL_MCE(user_data);
struct ril_mce_priv *priv = self->priv;
DBG("");
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, self, NULL);
}
}
static void ril_mce_disconnect(DBusConnection *conn, void *user_data)
{
struct ril_mce *self = user_data;
struct ril_mce_priv *priv = self->priv;
DBG("");
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()
{
struct ril_mce *self = g_object_new(RIL_MCE_TYPE, NULL);
struct ril_mce_priv *priv = self->priv;
DBG("");
priv->daemon_watch = g_dbus_add_service_watch(priv->conn, MCE_SERVICE,
ril_mce_connect, ril_mce_disconnect, self, NULL);
return self;
}
struct ril_mce *ril_mce_ref(struct ril_mce *self)
{
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
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,51 @@
/*
* 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_MCE_H
#define RIL_MCE_H
#include "ril_types.h"
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 */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,505 @@
/*
* 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_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"
#include "ofono.h"
#define MAX_PDP_CONTEXTS (2)
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
enum ril_modem_power_state {
POWERED_OFF,
POWERED_ON,
POWERING_OFF
};
enum ril_modem_online_state {
OFFLINE,
GOING_ONLINE,
ONLINE,
GOING_OFFLINE
};
struct ril_modem_online_request {
ofono_modem_online_cb_t cb;
struct ril_modem_data *md;
void *data;
guint timeout_id;
};
struct ril_modem_data {
struct ril_modem modem;
GRilIoQueue *q;
struct ofono_radio_settings *radio_settings;
char *imei;
char *ecclist_file;
gboolean pre_sim_done;
gboolean allow_data;
guint online_check_id;
enum ril_modem_power_state power_state;
gulong radio_state_event_id;
ril_modem_cb_t removed_cb;
void *removed_cb_data;
ril_modem_online_cb_t online_cb;
void *online_cb_data;
struct ril_modem_online_request set_online;
struct ril_modem_online_request set_offline;
};
#define RADIO_POWER_TAG(md) (md)
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
{
struct ril_modem_data *md = ofono_modem_get_data(o);
GASSERT(md->modem.ofono == o);
return md;
}
static struct ril_modem_data *ril_modem_data_from_modem(struct ril_modem *m)
{
return m ? G_CAST(m, struct ril_modem_data, modem) : NULL;
}
static void *ril_modem_get_atom_data(struct ril_modem *modem,
enum ofono_atom_type type)
{
if (modem && modem->ofono) {
struct ofono_atom *atom =
__ofono_modem_find_atom(modem->ofono, type);
if (atom) {
return __ofono_atom_get_data(atom);
}
}
return NULL;
}
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem)
{
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_SIM);
}
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem)
{
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_GPRS);
}
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
{
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
}
void ril_modem_delete(struct ril_modem *md)
{
if (md && md->ofono) {
ofono_modem_remove(md->ofono);
}
}
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
void *data)
{
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
md->removed_cb = cb;
md->removed_cb_data = data;
}
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
void *data)
{
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
md->online_cb = cb;
md->online_cb_data = data;
}
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
{
if (req->timeout_id) {
g_source_remove(req->timeout_id);
req->timeout_id = 0;
}
if (req->cb) {
struct ofono_error error;
ofono_modem_online_cb_t cb = req->cb;
void *data = req->data;
req->cb = NULL;
req->data = NULL;
cb(ril_error_ok(&error), data);
}
}
static void ril_modem_update_online_state(struct ril_modem_data *md)
{
switch (md->modem.radio->state) {
case RADIO_STATE_ON:
DBG("online");
ril_modem_online_request_ok(&md->set_online);
break;
case RADIO_STATE_OFF:
case RADIO_STATE_UNAVAILABLE:
DBG("offline");
ril_modem_online_request_ok(&md->set_offline);
break;
default:
break;
}
if (!md->set_offline.timeout_id && !md->set_online.timeout_id &&
md->power_state == POWERING_OFF) {
md->power_state = POWERED_OFF;
if (md->modem.ofono) {
ofono_modem_set_powered(md->modem.ofono, FALSE);
}
}
}
static gboolean ril_modem_online_request_timeout(gpointer data)
{
struct ril_modem_online_request *req = data;
struct ofono_error error;
ofono_modem_online_cb_t cb = req->cb;
void *cb_data = req->data;
GASSERT(req->timeout_id);
GASSERT(cb);
req->timeout_id = 0;
req->cb = NULL;
req->data = NULL;
cb(ril_error_failure(&error), cb_data);
ril_modem_update_online_state(req->md);
return G_SOURCE_REMOVE;
}
static gboolean ril_modem_online_check(gpointer data)
{
struct ril_modem_data *md = data;
GASSERT(md->online_check_id);
md->online_check_id = 0;
ril_modem_update_online_state(md);
return FALSE;
}
static void ril_modem_schedule_online_check(struct ril_modem_data *md)
{
if (!md->online_check_id) {
md->online_check_id = g_idle_add(ril_modem_online_check, md);
}
}
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
{
if (md->modem.radio->state == RADIO_STATE_ON) {
if (!md->radio_settings) {
DBG("Initializing radio settings interface");
md->radio_settings =
ofono_radio_settings_create(md->modem.ofono, 0,
RILMODEM_DRIVER, md);
}
} else if (md->radio_settings) {
DBG("Removing radio settings interface");
ofono_radio_settings_remove(md->radio_settings);
md->radio_settings = NULL;
}
}
static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
{
struct ril_modem_data *md = data;
GASSERT(md->modem.radio == radio);
ril_modem_update_radio_settings(md);
ril_modem_update_online_state(md);
}
static void ril_modem_pre_sim(struct ofono_modem *modem)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("%s", ofono_modem_get_path(modem));
md->pre_sim_done = TRUE;
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
ril_modem_update_radio_settings(md);
if (!md->radio_state_event_id) {
md->radio_state_event_id =
ril_radio_add_state_changed_handler(md->modem.radio,
ril_modem_radio_state_cb, md);
}
}
static void ril_modem_post_sim(struct ofono_modem *modem)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
struct ofono_gprs *gprs;
DBG("%s", ofono_modem_get_path(modem));
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
if (gprs) {
int i;
for (i = 0; i < MAX_PDP_CONTEXTS; i++) {
struct ofono_gprs_context *gc =
ofono_gprs_context_create(modem, 0,
RILMODEM_DRIVER, md);
if (gc == NULL)
break;
ofono_gprs_add_context(gprs, gc);
}
}
ofono_phonebook_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
ofono_message_waiting_register(ofono_message_waiting_create(modem));
}
static void ril_modem_post_online(struct ofono_modem *modem)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("%s", ofono_modem_get_path(modem));
ofono_call_volume_create(modem, 0, RILMODEM_DRIVER, md);
ofono_netreg_create(modem, 0, RILMODEM_DRIVER, md);
ofono_ussd_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_settings_create(modem, 0, RILMODEM_DRIVER, md);
}
static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
ofono_modem_online_cb_t cb, void *data)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
struct ril_modem_online_request *req;
DBG("%s going %sline", ofono_modem_get_path(modem),
online ? "on" : "off");
if (md->online_cb) {
md->online_cb(&md->modem, online, md->online_cb_data);
}
if (online) {
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
req = &md->set_online;
} else {
ril_radio_power_off(md->modem.radio, RADIO_POWER_TAG(md));
req = &md->set_offline;
}
req->cb = cb;
req->data = data;
if (req->timeout_id) {
g_source_remove(req->timeout_id);
}
req->timeout_id = g_timeout_add_seconds(ONLINE_TIMEOUT_SECS,
ril_modem_online_request_timeout, req);
ril_modem_schedule_online_check(md);
}
static int ril_modem_enable(struct ofono_modem *modem)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("%s", ofono_modem_get_path(modem));
md->power_state = POWERED_ON;
return 0;
}
static int ril_modem_disable(struct ofono_modem *modem)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("%s", ofono_modem_get_path(modem));
if (md->set_online.timeout_id || md->set_offline.timeout_id) {
md->power_state = POWERING_OFF;
return -EINPROGRESS;
} else {
md->power_state = POWERED_OFF;
return 0;
}
}
static int ril_modem_probe(struct ofono_modem *modem)
{
DBG("%s", ofono_modem_get_path(modem));
return 0;
}
static void ril_modem_remove(struct ofono_modem *ofono)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(ofono);
struct ril_modem *modem = &md->modem;
DBG("%s", ril_modem_get_path(modem));
if (md->removed_cb) {
ril_modem_cb_t cb = md->removed_cb;
void *data = md->removed_cb_data;
md->removed_cb = NULL;
md->removed_cb_data = NULL;
cb(modem, data);
}
ofono_modem_set_data(ofono, NULL);
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
ril_radio_unref(modem->radio);
if (md->online_check_id) {
g_source_remove(md->online_check_id);
}
if (md->set_online.timeout_id) {
g_source_remove(md->set_online.timeout_id);
}
if (md->set_offline.timeout_id) {
g_source_remove(md->set_offline.timeout_id);
}
ril_network_unref(modem->network);
ril_sim_card_unref(modem->sim_card);
ril_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->ecclist_file);
g_free(md->imei);
g_free(md);
}
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,
struct ril_network *network, struct ril_sim_card *card,
struct ril_data *data, struct ril_sim_settings *settings)
{
/* Skip the slash from the path, it looks like "/ril_0" */
struct ofono_modem *ofono = ofono_modem_create(slot->path + 1,
RILMODEM_DRIVER);
if (ofono) {
int err;
struct ril_modem_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);
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);
md->set_online.md = md;
md->set_offline.md = md;
ofono_modem_set_data(ofono, md);
err = ofono_modem_register(ofono);
if (!err) {
ril_radio_power_cycle(modem->radio);
GASSERT(io->connected);
/*
* ofono_modem_reset sets Powered to TRUE without
* issuing PropertyChange signal.
*/
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",
err, RILMODEM_DRIVER);
/*
* If ofono_modem_register() failed, then
* ofono_modem_remove() won't invoke
* ril_modem_remove() callback.
*/
ril_modem_remove(ofono);
}
ofono_modem_remove(ofono);
}
return NULL;
}
const struct ofono_modem_driver ril_modem_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_modem_probe,
.remove = ril_modem_remove,
.enable = ril_modem_enable,
.disable = ril_modem_disable,
.pre_sim = ril_modem_pre_sim,
.post_sim = ril_modem_post_sim,
.post_online = ril_modem_post_online,
.set_online = ril_modem_set_online
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

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

@@ -0,0 +1,552 @@
/*
* 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_network.h"
#include "ril_util.h"
#include "ril_log.h"
#include "common.h"
#include "simutil.h"
enum ril_netreg_events {
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
NETREG_RIL_EVENT_COUNT
};
enum ril_netreg_network_events {
NETREG_NETWORK_EVENT_OPERATOR_CHANGED,
NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED,
NETREG_NETWORK_EVENT_COUNT
};
struct ril_netreg {
GRilIoChannel *io;
GRilIoQueue *q;
struct ofono_netreg *netreg;
struct ril_network *network;
char *log_prefix;
guint timer_id;
guint notify_id;
guint current_operator_id;
gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
};
struct ril_netreg_cbd {
struct ril_netreg *nd;
union {
ofono_netreg_status_cb_t status;
ofono_netreg_operator_cb_t operator;
ofono_netreg_operator_list_cb_t operator_list;
ofono_netreg_register_cb_t reg;
ofono_netreg_strength_cb_t strength;
gpointer ptr;
} cb;
gpointer data;
};
#define ril_netreg_cbd_free g_free
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
{
return ofono ? ofono_netreg_get_data(ofono) : NULL;
}
static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
void *cb, void *data)
{
struct ril_netreg_cbd *cbd = g_new0(struct ril_netreg_cbd, 1);
cbd->nd = nd;
cbd->cb.ptr = cb;
cbd->data = data;
return cbd;
}
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
gint status)
{
if (status == NETWORK_REGISTRATION_STATUS_ROAMING) {
/* These functions tolerate NULL argument */
const char *net_mcc = ofono_netreg_get_mcc(netreg);
const char *net_mnc = ofono_netreg_get_mnc(netreg);
struct sim_spdi *spdi = ofono_netreg_get_spdi(netreg);
if (spdi && net_mcc && net_mnc) {
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
ofono_info("not roaming based on spdi");
return NETWORK_REGISTRATION_STATUS_REGISTERED;
}
}
}
return status;
}
static int ril_netreg_check_status(struct ril_netreg *nd, int status)
{
return (nd && nd->netreg) ?
ril_netreg_check_if_really_roaming(nd->netreg, status) :
status;
}
static gboolean ril_netreg_status_notify_cb(gpointer user_data)
{
struct ril_netreg *nd = user_data;
const struct ril_registration_state *reg = &nd->network->voice;
DBG("%s", nd->log_prefix);
GASSERT(nd->notify_id);
nd->notify_id = 0;
ofono_netreg_status_notify(nd->netreg,
ril_netreg_check_status(nd, reg->status),
reg->lac, reg->ci, reg->access_tech);
return FALSE;
}
static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
{
struct ril_netreg *nd = user_data;
/* Coalesce multiple notifications into one */
if (nd->notify_id) {
DBG("%snotification aready queued", nd->log_prefix);
} else {
DBG("%squeuing notification", nd->log_prefix);
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
}
}
static void ril_netreg_registration_status(struct ofono_netreg *netreg,
ofono_netreg_status_cb_t cb, void *data)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
const struct ril_registration_state *reg = &nd->network->voice;
struct ofono_error error;
DBG("%s", nd->log_prefix);
cb(ril_error_ok(&error),
ril_netreg_check_status(nd, reg->status),
reg->lac, reg->ci, reg->access_tech, data);
}
static gboolean ril_netreg_current_operator_cb(void *user_data)
{
struct ril_netreg_cbd *cbd = user_data;
struct ril_netreg *nd = cbd->nd;
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
struct ofono_error error;
DBG("%s", nd->log_prefix);
GASSERT(nd->current_operator_id);
nd->current_operator_id = 0;
cb(ril_error_ok(&error), nd->network->operator, cbd->data);
return FALSE;
}
static void ril_netreg_current_operator(struct ofono_netreg *netreg,
ofono_netreg_operator_cb_t cb, void *data)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
/*
* 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);
}
nd->current_operator_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_netreg_current_operator_cb,
ril_netreg_cbd_new(nd, cb, data),
ril_netreg_cbd_free);
}
static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_netreg_cbd *cbd = user_data;
ofono_netreg_operator_list_cb_t cb = cbd->cb.operator_list;
struct ofono_network_operator *list;
struct ofono_error error;
int noperators = 0, i;
GRilIoParser rilp;
gboolean ok = TRUE;
if (status != RIL_E_SUCCESS) {
ofono_error("Failed to retrive the list of operators: %s",
ril_error_to_string(status));
cb(ril_error_failure(&error), 0, NULL, cbd->data);
return;
}
grilio_parser_init(&rilp, data, len);
/* Number of operators at the list (4 strings for every operator) */
grilio_parser_get_int32(&rilp, &noperators);
GASSERT(!(noperators % 4));
noperators /= 4;
ofono_info("noperators = %d", noperators);
list = g_new0(struct ofono_network_operator, noperators);
for (i = 0; i < noperators && ok; i++) {
struct ofono_network_operator *op = list + i;
char *lalpha = grilio_parser_get_utf8(&rilp);
char *salpha = grilio_parser_get_utf8(&rilp);
char *numeric = grilio_parser_get_utf8(&rilp);
char *status = grilio_parser_get_utf8(&rilp);
/* Try to use long by default */
if (lalpha) {
strncpy(op->name, lalpha,
OFONO_MAX_OPERATOR_NAME_LENGTH);
} else if (salpha) {
strncpy(op->name, salpha,
OFONO_MAX_OPERATOR_NAME_LENGTH);
} else {
op->name[0] = 0;
}
/* Set the proper status */
if (!strcmp(status, "available")) {
list[i].status = OPERATOR_STATUS_AVAILABLE;
} else if (!strcmp(status, "current")) {
list[i].status = OPERATOR_STATUS_CURRENT;
} else if (!strcmp(status, "forbidden")) {
list[i].status = OPERATOR_STATUS_FORBIDDEN;
} else {
list[i].status = OPERATOR_STATUS_UNKNOWN;
}
op->tech = -1;
ok = ril_parse_mcc_mnc(numeric, op);
if (ok) {
if (op->tech < 0) {
op->tech = cbd->nd->network->voice.access_tech;
}
DBG("[operator=%s, %s, %s, status: %s]", op->name,
op->mcc, op->mnc, status);
} else {
DBG("failed to parse operator list");
}
g_free(lalpha);
g_free(salpha);
g_free(numeric);
g_free(status);
}
if (ok) {
cb(ril_error_ok(&error), noperators, list, cbd->data);
} else {
cb(ril_error_failure(&error), 0, NULL, cbd->data);
}
g_free(list);
}
static void ril_netreg_list_operators(struct ofono_netreg *netreg,
ofono_netreg_operator_list_cb_t cb, void *data)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
grilio_queue_send_request_full(nd->q, NULL,
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS,
ril_netreg_list_operators_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, cb, data));
}
static void ril_netreg_register_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_netreg_cbd *cbd = user_data;
ofono_netreg_register_cb_t cb = cbd->cb.reg;
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
ofono_error("registration failed, ril result %d", status);
cb(ril_error_failure(&error), cbd->data);
}
}
static void ril_netreg_register_auto(struct ofono_netreg *netreg,
ofono_netreg_register_cb_t cb, void *data)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
ofono_info("nw select automatic");
grilio_queue_send_request_full(nd->q, NULL,
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
ril_netreg_register_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, cb, data));
}
static void ril_netreg_register_manual(struct ofono_netreg *netreg,
const char *mcc, const char *mnc,
ofono_netreg_register_cb_t cb, void *data)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
GRilIoRequest *req = grilio_request_new();
ofono_info("nw select manual: %s%s", mcc, mnc);
grilio_request_append_format(req, "%s%s+0", mcc, mnc);
grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
ril_netreg_register_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, cb, data));
grilio_request_unref(req);
}
static int ril_netreg_get_signal_strength(const void *data, guint len)
{
GRilIoParser rilp;
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
grilio_parser_init(&rilp, data, len);
/* RIL_SignalStrength_v6 */
/* GW_SignalStrength */
grilio_parser_get_int32(&rilp, &gw_signal);
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
/* CDMA_SignalStrength */
grilio_parser_get_int32(&rilp, &cdma_dbm);
grilio_parser_get_int32(&rilp, NULL); /* ecio */
/* EVDO_SignalStrength */
grilio_parser_get_int32(&rilp, &evdo_dbm);
grilio_parser_get_int32(&rilp, NULL); /* ecio */
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
/* LTE_SignalStrength */
grilio_parser_get_int32(&rilp, &lte_signal);
grilio_parser_get_int32(&rilp, NULL); /* rsrp */
grilio_parser_get_int32(&rilp, NULL); /* rsrq */
grilio_parser_get_int32(&rilp, NULL); /* rssnr */
grilio_parser_get_int32(&rilp, NULL); /* cqi */
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d", gw_signal, cdma_dbm,
evdo_dbm, lte_signal);
/* Return the first valid one */
if (gw_signal != 99 && gw_signal != -1) {
return (gw_signal * 100) / 31;
}
if (lte_signal != 99 && lte_signal != -1) {
return (lte_signal * 100) / 31;
}
/* In case of dbm, return the value directly */
if (cdma_dbm != -1) {
return MIN(cdma_dbm, 100);
}
if (evdo_dbm != -1) {
return MIN(evdo_dbm, 100);
}
return -1;
}
static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
const void *data, guint len, void *user_data)
{
struct ril_netreg *nd = user_data;
int strength;
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
strength = ril_netreg_get_signal_strength(data, len);
DBG("%d", strength);
ofono_netreg_strength_notify(nd->netreg, strength);
}
static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_netreg_cbd *cbd = user_data;
ofono_netreg_strength_cb_t cb = cbd->cb.strength;
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
int strength = ril_netreg_get_signal_strength(data, len);
cb(ril_error_ok(&error), strength, cbd->data);
} else {
ofono_error("Failed to retrive the signal strength: %s",
ril_error_to_string(status));
cb(ril_error_failure(&error), -1, cbd->data);
}
}
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_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,
const void *data, guint len, void *user_data)
{
struct ril_netreg *nd = user_data;
GRilIoParser rilp;
struct ofono_network_time time;
int year, mon, mday, hour, min, sec, dst, tzi;
char tzs, tz[4];
gchar *nitz;
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
grilio_parser_init(&rilp, data, len);
nitz = grilio_parser_get_utf8(&rilp);
DBG("%s", nitz);
sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u", &year, &mon, &mday,
&hour, &min, &sec, &tzs, &tzi, &dst);
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
time.utcoff = atoi(tz) * 15 * 60;
time.dst = dst;
time.sec = sec;
time.min = min;
time.hour = hour;
time.mday = mday;
time.mon = mon;
time.year = 2000 + year;
ofono_netreg_time_notify(nd->netreg, &time);
g_free(nitz);
}
static gboolean ril_netreg_register(gpointer user_data)
{
struct ril_netreg *nd = user_data;
GASSERT(nd->timer_id);
nd->timer_id = 0;
ofono_netreg_register(nd->netreg);
/* Register for network state changes */
nd->network_event_id[NETREG_NETWORK_EVENT_OPERATOR_CHANGED] =
ril_network_add_operator_changed_handler(nd->network,
ril_netreg_status_notify, nd);
nd->network_event_id[NETREG_NETWORK_EVENT_VOICE_STATE_CHANGED] =
ril_network_add_voice_state_changed_handler(nd->network,
ril_netreg_status_notify, nd);
/* Register for network time updates */
nd->ril_event_id[NETREG_RIL_EVENT_NITZ_TIME_RECEIVED] =
grilio_channel_add_unsol_event_handler(nd->io,
ril_netreg_nitz_notify,
RIL_UNSOL_NITZ_TIME_RECEIVED, nd);
/* Register for signal strength changes */
nd->ril_event_id[NETREG_RIL_EVENT_SIGNAL_STRENGTH] =
grilio_channel_add_unsol_event_handler(nd->io,
ril_netreg_strength_notify,
RIL_UNSOL_SIGNAL_STRENGTH, nd);
/* This makes the timeout a single-shot */
return FALSE;
}
static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
guint slot = ril_modem_slot(modem);
DBG("[%u] %p", slot, netreg);
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
nd->io = grilio_channel_ref(ril_modem_io(modem));
nd->q = grilio_queue_new(nd->io);
nd->network = ril_network_ref(modem->network);
nd->netreg = netreg;
ofono_netreg_set_data(netreg, nd);
nd->timer_id = g_idle_add(ril_netreg_register, nd);
return 0;
}
static void ril_netreg_remove(struct ofono_netreg *netreg)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
int i;
DBG("%p", netreg);
grilio_queue_cancel_all(nd->q, FALSE);
ofono_netreg_set_data(netreg, NULL);
if (nd->timer_id > 0) {
g_source_remove(nd->timer_id);
}
if (nd->notify_id) {
g_source_remove(nd->notify_id);
}
if (nd->current_operator_id) {
g_source_remove(nd->current_operator_id);
}
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
}
ril_network_unref(nd->network);
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
G_N_ELEMENTS(nd->ril_event_id));
grilio_channel_unref(nd->io);
grilio_queue_unref(nd->q);
g_free(nd->log_prefix);
g_free(nd);
}
const struct ofono_netreg_driver ril_netreg_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_netreg_probe,
.remove = ril_netreg_remove,
.registration_status = ril_netreg_registration_status,
.current_operator = ril_netreg_current_operator,
.list_operators = ril_netreg_list_operators,
.register_auto = ril_netreg_register_auto,
.register_manual = ril_netreg_register_manual,
.strength = ril_netreg_strength
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

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

View File

@@ -0,0 +1,75 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_NETWORK_H
#define RIL_NETWORK_H
#include "ril_types.h"
#include <ofono/radio-settings.h>
struct ofono_network_operator;
struct ril_registration_state {
int status; /* enum network_registration_status */
int access_tech; /* enum access_technology or -1 if none */
int ril_tech;
int max_calls;
int lac;
int ci;
};
struct ril_network {
GObject object;
struct ril_network_priv *priv;
struct ril_registration_state voice;
struct ril_registration_state data;
const struct ofono_network_operator *operator;
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, 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_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,166 @@
/*
* 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_util.h"
#include "ril_log.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;
DBusConnection *conn;
char *path;
char *log_prefix;
};
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
DBusMessage *msg = user_data;
DBusMessage *reply;
if (ril_status == RIL_E_SUCCESS) {
DBusMessageIter it, array;
const guchar* bytes = data;
guint i;
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 %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 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
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,172 @@
/*
* 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_PLUGIN_H
#define RIL_PLUGIN_H
#include "ril_types.h"
#include <ofono/modem.h>
#include <ofono/call-barring.h>
#include <ofono/call-forwarding.h>
#include <ofono/call-settings.h>
#include <ofono/call-volume.h>
#include <ofono/cbs.h>
#include <ofono/devinfo.h>
#include <ofono/gprs-context.h>
#include <ofono/gprs.h>
#include <ofono/netreg.h>
#include <ofono/phonebook.h>
#include <ofono/radio-settings.h>
#include <ofono/sim.h>
#include <ofono/sms.h>
#include <ofono/stk.h>
#include <ofono/ussd.h>
#include <ofono/voicecall.h>
#include <grilio_queue.h>
#include <grilio_request.h>
#include <grilio_parser.h>
#define RILMODEM_DRIVER "ril"
typedef struct ril_slot_info const *ril_slot_info_ptr;
struct ril_slot_info {
const char *path;
const char *imei;
const char *ecclist_file;
gboolean enabled;
gboolean sim_present;
const struct ril_slot_config *config;
};
struct ril_plugin {
const char *mms_imsi;
const char *mms_path;
const char *default_voice_imsi;
const char *default_data_imsi;
const char *default_voice_path;
const char *default_data_path;
const ril_slot_info_ptr *slots;
gboolean ready;
};
struct ril_modem {
GRilIoChannel *io;
const char *imei;
const char *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 (0x08)
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x10)
#define RIL_PLUGIN_SIGNAL_MMS_IMSI (0x20)
#define RIL_PLUGIN_SIGNAL_MMS_PATH (0x40)
#define RIL_PLUGIN_SIGNAL_READY (0x80)
typedef void (*ril_modem_cb_t)(struct ril_modem *modem, void *data);
typedef void (*ril_modem_online_cb_t)(struct ril_modem *modem, gboolean online,
void *data);
void ril_plugin_set_enabled_slots(struct ril_plugin *plugin, char **slots);
gboolean ril_plugin_set_mms_imsi(struct ril_plugin *plugin, const char *imsi);
void ril_plugin_set_default_voice_imsi(struct ril_plugin *plugin,
const char *imsi);
void ril_plugin_set_default_data_imsi(struct ril_plugin *plugin,
const char *imsi);
struct ril_oem_raw;
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *md,
const char *log_prefix);
void ril_oem_raw_free(struct ril_oem_raw *raw);
struct ril_sim_info_dbus;
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
struct ril_sim_info *info);
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus);
struct ril_cell_info_dbus;
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
struct ril_cell_info *info);
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus);
struct ril_plugin_dbus;
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin);
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus);
void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
gboolean clock);
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
gboolean present);
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,
struct ril_network *network, struct ril_sim_card *card,
struct ril_data *data, struct ril_sim_settings *settings);
void ril_modem_delete(struct ril_modem *modem);
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
void *data);
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
void *data);
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
#define ril_modem_slot(modem) ((modem)->config.slot)
#define ril_modem_io(modem) ((modem)->io)
int ril_sim_app_type(struct ofono_sim *sim);
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
extern const struct ofono_call_barring_driver ril_call_barring_driver;
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;
extern const struct ofono_call_settings_driver ril_call_settings_driver;
extern const struct ofono_call_volume_driver ril_call_volume_driver;
extern const struct ofono_cbs_driver ril_cbs_driver;
extern const struct ofono_devinfo_driver ril_devinfo_driver;
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_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;
extern const struct ofono_sms_driver ril_sms_driver;
extern const struct ofono_stk_driver ril_stk_driver;
extern const struct ofono_ussd_driver ril_ussd_driver;
extern const struct ofono_voicecall_driver ril_voicecall_driver;
#endif /* RIL_PLUGIN_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,199 @@
/*
* 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_sim_settings.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ril_constants.h"
struct ril_radio_settings {
struct ofono_radio_settings *rs;
struct ril_sim_settings *settings;
const char *log_prefix;
char *allocated_log_prefix;
guint source_id;
};
struct ril_radio_settings_cbd {
struct ril_radio_settings *rsd;
union _ofono_radio_settings_cb {
ofono_radio_settings_rat_mode_set_cb_t rat_mode_set;
ofono_radio_settings_rat_mode_query_cb_t rat_mode_query;
ofono_radio_settings_available_rats_query_cb_t available_rats;
gpointer ptr;
} cb;
gpointer data;
};
#define 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)
{
return ofono_radio_settings_get_data(rs);
}
static void ril_radio_settings_later(struct ril_radio_settings *rsd,
GSourceFunc fn, void *cb, void *data)
{
struct ril_radio_settings_cbd *cbd;
cbd = g_new0(struct ril_radio_settings_cbd, 1);
cbd->rsd = rsd;
cbd->cb.ptr = cb;
cbd->data = data;
GASSERT(!rsd->source_id);
rsd->source_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
fn, cbd, g_free);
}
static gboolean ril_radio_settings_set_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;
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,
enum ofono_radio_access_mode mode,
ofono_radio_settings_rat_mode_set_cb_t cb, void *data)
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
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 gboolean ril_radio_settings_query_rat_mode_cb(gpointer user_data)
{
struct ril_radio_settings_cbd *cbd = user_data;
struct ril_radio_settings *rsd = cbd->rsd;
enum ofono_radio_access_mode mode = rsd->settings->pref_mode;
struct ofono_error error;
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,
ofono_radio_settings_rat_mode_query_cb_t cb, void *data)
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
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->settings->enable_4g) {
rats |= OFONO_RADIO_ACCESS_MODE_LTE;
}
GASSERT(cbd->rsd->source_id);
rsd->source_id = 0;
cbd->cb.available_rats(ril_error_ok(&error), rats, cbd->data);
return G_SOURCE_REMOVE;
}
static void ril_radio_settings_query_available_rats(
struct ofono_radio_settings *rs,
ofono_radio_settings_available_rats_query_cb_t cb, void *data)
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
DBG_(rsd, "");
ril_radio_settings_later(rsd, ril_radio_settings_query_available_rats_cb,
cb, data);
}
static gboolean ril_radio_settings_register(gpointer user_data)
{
struct ril_radio_settings *rsd = user_data;
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,
unsigned int vendor, void *data)
{
struct ril_modem *modem = data;
struct ril_radio_settings *rsd = g_new0(struct ril_radio_settings, 1);
DBG("%s", modem->log_prefix);
rsd->rs = rs;
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;
}
static void ril_radio_settings_remove(struct ofono_radio_settings *rs)
{
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
DBG_(rsd, "");
ofono_radio_settings_set_data(rs, NULL);
if (rsd->source_id) {
g_source_remove(rsd->source_id);
}
ril_sim_settings_unref(rsd->settings);
g_free(rsd->allocated_log_prefix);
g_free(rsd);
}
const struct ofono_radio_settings_driver ril_radio_settings_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_radio_settings_probe,
.remove = ril_radio_settings_remove,
.query_rat_mode = ril_radio_settings_query_rat_mode,
.set_rat_mode = ril_radio_settings_set_rat_mode,
.query_available_rats = ril_radio_settings_query_available_rats
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

1328
ofono/drivers/ril/ril_sim.c Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -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:
*/

516
ofono/drivers/ril/ril_sms.c Normal file
View File

@@ -0,0 +1,516 @@
/*
* 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_constants.h"
#include "ril_util.h"
#include "ril_log.h"
#include "smsutil.h"
#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 sim_path[4] = {0x3F, 0x00, 0x7F, 0x10};
enum ril_sms_events {
SMS_EVENT_NEW_SMS,
SMS_EVENT_NEW_STATUS_REPORT,
SMS_EVENT_NEW_SMS_ON_SIM,
SMS_EVENT_COUNT
};
struct ril_sms {
GRilIoChannel *io;
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;
};
struct ril_sms_cbd {
union _ofono_sms_cb {
ofono_sms_sca_set_cb_t sca_set;
ofono_sms_sca_query_cb_t sca_query;
ofono_sms_submit_cb_t submit;
gpointer ptr;
} cb;
gpointer data;
};
struct ril_sms_on_sim_req {
struct ril_sms *sd;
int record;
};
#define ril_sms_cbd_free g_free
#define ril_sms_on_sim_req_free g_free
static inline struct ril_sms *ril_sms_get_data(struct ofono_sms *sms)
{
return ofono_sms_get_data(sms);
}
struct ril_sms_cbd *ril_sms_cbd_new(struct ril_sms *sd, void *cb, void *data)
{
struct ril_sms_cbd *cbd = g_new0(struct ril_sms_cbd, 1);
cbd->cb.ptr = cb;
cbd->data = data;
return cbd;
}
struct ril_sms_on_sim_req *ril_sms_on_sim_req_new(struct ril_sms *sd, int rec)
{
struct ril_sms_on_sim_req *cbd = g_new0(struct ril_sms_on_sim_req, 1);
cbd->sd = sd;
cbd->record = rec;
return cbd;
}
static void ril_sms_sca_set_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_sms_cbd *cbd = user_data;
ofono_sms_sca_set_cb_t cb = cbd->cb.sca_set;
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
ofono_error("csca setting failed");
cb(ril_error_failure(&error), cbd->data);
}
}
static void ril_sms_sca_set(struct ofono_sms *sms,
const struct ofono_phone_number *sca,
ofono_sms_sca_set_cb_t cb, void *data)
{
struct ril_sms *sd = ril_sms_get_data(sms);
GRilIoRequest *req = grilio_request_new();
char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 4];
if (sca->type == TYPE_LOCAL) {
snprintf(number, sizeof(number), "\"%s\"", sca->number);
} else {
snprintf(number, sizeof(number), "\"+%s\"", sca->number);
}
DBG("Setting sca: %s", number);
grilio_request_append_utf8(req, number);
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SET_SMSC_ADDRESS, ril_sms_sca_set_cb,
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
grilio_request_unref(req);
}
static void ril_sms_sca_query_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sms_cbd *cbd = user_data;
ofono_sms_sca_query_cb_t cb = cbd->cb.sca_query;
struct ofono_error error;
GRilIoParser rilp;
gchar *temp_buf;
if (status != RIL_E_SUCCESS) {
ofono_error("csca query failed");
cb(ril_error_failure(&error), NULL, cbd->data);
return;
}
grilio_parser_init(&rilp, data, len);
temp_buf = grilio_parser_get_utf8(&rilp);
if (temp_buf) {
/* RIL gives address in quotes */
gchar *number = strtok(temp_buf, "\"");
struct ofono_phone_number sca;
strncpy(sca.number, number, OFONO_MAX_PHONE_NUMBER_LENGTH);
sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
if (sca.number[0] == '+') {
number = number + 1;
sca.type = TYPE_INTERNATIONAL;
} else {
sca.type = TYPE_LOCAL;
}
DBG("csca_query_cb: %s, %d", sca.number, sca.type);
cb(ril_error_ok(&error), &sca, cbd->data);
g_free(temp_buf);
} else {
ofono_error("return value invalid");
cb(ril_error_failure(&error), NULL, cbd->data);
}
}
static void ril_sms_sca_query(struct ofono_sms *sms,
ofono_sms_sca_query_cb_t cb, void *data)
{
struct ril_sms *sd = ril_sms_get_data(sms);
DBG("Sending csca_query");
grilio_queue_send_request_full(sd->q, NULL,
RIL_REQUEST_GET_SMSC_ADDRESS, ril_sms_sca_query_cb,
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
}
static void ril_sms_submit_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sms_cbd *cbd = user_data;
ofono_sms_submit_cb_t cb = cbd->cb.submit;
struct ofono_error error;
int mr = 0;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
int err = -1;
grilio_parser_init(&rilp, data, len);
/* TP-Message-Reference for GSM/
* BearerData MessageId for CDMA
*/
grilio_parser_get_int32(&rilp, &mr);
grilio_parser_skip_string(&rilp);
/* error: 3GPP 27.005, 3.2.5, -1 if unknown or not applicable */
grilio_parser_get_int32(&rilp, &err);
DBG("sms msg ref: %d, error: %d", mr, err);
ril_error_init_ok(&error);
} else if (status == RIL_E_GENERIC_FAILURE) {
ofono_info("not allowed by MO SMS control, do not retry");
error.type = OFONO_ERROR_TYPE_CMS;
error.error = 500;
} else {
ofono_error("sms sending failed, retry");
ril_error_init_failure(&error);
}
cb(&error, mr, cbd->data);
}
static void ril_sms_submit(struct ofono_sms *sms, const unsigned char *pdu,
int pdu_len, int tpdu_len, int mms,
ofono_sms_submit_cb_t cb, void *data)
{
struct ril_sms *sd = ril_sms_get_data(sms);
GRilIoRequest *req = grilio_request_new();
int smsc_len;
char *tpdu;
DBG("pdu_len: %d, tpdu_len: %d mms: %d", pdu_len, tpdu_len, mms);
grilio_request_append_int32(req, 2); /* Number of strings */
/* SMSC address:
*
* smsc_len == 1, then zero-length SMSC was spec'd
* RILD expects a NULL string in this case instead
* of a zero-length string.
*/
smsc_len = pdu_len - tpdu_len;
if (smsc_len > 1) {
/* TODO: encode SMSC & write to parcel */
DBG("SMSC address specified (smsc_len %d); NOT-IMPLEMENTED",
smsc_len);
}
grilio_request_append_utf8(req, NULL); /* default SMSC address */
/* TPDU:
*
* 'pdu' is a raw hexadecimal string
* encode_hex() turns it into an ASCII/hex UTF8 buffer
* grilio_request_append_utf8() encodes utf8 -> utf16
*/
tpdu = encode_hex(pdu + smsc_len, tpdu_len, 0);
grilio_request_append_utf8(req, tpdu);
DBG("%s", tpdu);
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SEND_SMS, ril_sms_submit_cb,
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
grilio_request_unref(req);
g_free(tpdu);
}
static void ril_ack_delivery_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
if (status != RIL_E_SUCCESS) {
ofono_error("SMS acknowledgement failed: "
"Further SMS reception is not guaranteed");
}
}
static void ril_ack_delivery(struct ril_sms *sd, gboolean error)
{
GRilIoRequest *req = grilio_request_sized_new(12);
const int code = (error ? 0 : 0xff);
DBG("(%d,%d)", error, code);
grilio_request_append_int32(req, 2); /* Array size*/
grilio_request_append_int32(req, error); /* Success (1)/Failure (0) */
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);
}
static void ril_sms_notify(GRilIoChannel *io, guint ril_event,
const void *data, guint len, void *user_data)
{
struct ril_sms *sd = user_data;
GRilIoParser rilp;
char *ril_pdu;
int ril_pdu_len;
unsigned int smsc_len;
long ril_buf_len;
guchar *ril_data;
ril_pdu = NULL;
ril_data = NULL;
DBG("event: %d; data_len: %d", ril_event, len);
grilio_parser_init(&rilp, data, len);
ril_pdu = grilio_parser_get_utf8(&rilp);
if (ril_pdu == NULL)
goto error;
ril_pdu_len = strlen(ril_pdu);
DBG("ril_pdu_len is %d", ril_pdu_len);
ril_data = decode_hex(ril_pdu, ril_pdu_len, &ril_buf_len, -1);
if (ril_data == NULL)
goto error;
/* The first octect in the pdu contains the SMSC address length
* which is the X following octects it reads. We add 1 octet to
* the read length to take into account this read octet in order
* to calculate the proper tpdu length.
*/
smsc_len = ril_data[0] + 1;
ofono_info("sms received, smsc_len is %d", smsc_len);
DBG("(%s)", ril_pdu);
if (ril_event == RIL_UNSOL_RESPONSE_NEW_SMS) {
/* Last parameter is 'tpdu_len' ( substract SMSC length ) */
ofono_sms_deliver_notify(sd->sms, ril_data, ril_buf_len,
ril_buf_len - smsc_len);
} else {
GASSERT(ril_event == RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT);
ofono_sms_status_notify(sd->sms, ril_data, ril_buf_len,
ril_buf_len - smsc_len);
}
g_free(ril_pdu);
g_free(ril_data);
ril_ack_delivery(sd, TRUE);
return;
error:
g_free(ril_pdu);
g_free(ril_data);
ril_ack_delivery(sd, FALSE);
ofono_error("Unable to parse NEW_SMS notification");
}
static void ril_new_sms_on_sim_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
DBG("%d", status);
if (status == RIL_E_SUCCESS) {
ofono_info("sms deleted from sim");
} else {
ofono_error("deleting sms from sim failed");
}
}
static void ril_request_delete_sms_om_sim(struct ril_sms *sd, int record)
{
GRilIoRequest *req = grilio_request_sized_new(8);
DBG("Deleting record: %d", record);
grilio_request_append_int32(req, 1); /* Array length */
grilio_request_append_int32(req, record);
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_DELETE_SMS_ON_SIM,
ril_new_sms_on_sim_cb, NULL, NULL);
grilio_request_unref(req);
}
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 = userdata;
struct ril_sms *sd = cbd->sd;
/*
* It seems when reading EFsms RIL returns the whole record including
* the first status byte therefore we ignore that as we are only
* interested of the following pdu
*/
/* The first octect in the pdu contains the SMSC address length
* which is the X following octects it reads. We add 1 octet to
* the read length to take into account this read octet in order
* to calculate the proper tpdu length.
*/
if (ok) {
unsigned int smsc_len = sdata[1] + 1;
ofono_sms_deliver_notify(sd->sms, sdata + 1, length - 1,
length - smsc_len - 1);
ril_request_delete_sms_om_sim(sd, cbd->record);
} else {
ofono_error("cannot read sms from sim");
}
ril_sms_on_sim_req_free(cbd);
}
static void ril_sms_on_sim(GRilIoChannel *io, guint ril_event,
const void *data, guint len, void *user_data)
{
struct ril_sms *sd = user_data;
struct ofono_sim *sim = ril_modem_ofono_sim(sd->modem);
int data_len = 0, rec = 0;
GRilIoParser rilp;
ofono_info("new sms on sim");
grilio_parser_init(&rilp, data, len);
if (sim &&
grilio_parser_get_int32(&rilp, &data_len) && data_len > 0 &&
grilio_parser_get_int32(&rilp, &rec)) {
DBG("rec %d", 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));
}
}
}
static gboolean ril_sms_register(gpointer user_data)
{
struct ril_sms *sd = user_data;
DBG("");
GASSERT(sd->timer_id);
sd->timer_id = 0;
ofono_sms_register(sd->sms);
/* Register event handlers */
sd->event_id[SMS_EVENT_NEW_SMS] =
grilio_channel_add_unsol_event_handler(sd->io, ril_sms_notify,
RIL_UNSOL_RESPONSE_NEW_SMS, sd);
sd->event_id[SMS_EVENT_NEW_STATUS_REPORT] =
grilio_channel_add_unsol_event_handler(sd->io, ril_sms_notify,
RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, sd);
sd->event_id[SMS_EVENT_NEW_SMS_ON_SIM] =
grilio_channel_add_unsol_event_handler(sd->io, ril_sms_on_sim,
RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, sd);
/* Single-shot */
return FALSE;
}
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;
}
static void ril_sms_remove(struct ofono_sms *sms)
{
int i;
struct ril_sms *sd = ril_sms_get_data(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]);
}
if (sd->timer_id > 0) {
g_source_remove(sd->timer_id);
}
grilio_channel_unref(sd->io);
grilio_queue_cancel_all(sd->q, FALSE);
grilio_queue_unref(sd->q);
g_free(sd);
}
const struct ofono_sms_driver ril_sms_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_sms_probe,
.remove = ril_sms_remove,
.sca_query = ril_sms_sca_query,
.sca_set = ril_sms_sca_set,
.submit = ril_sms_submit,
.bearer_query = NULL, /* FIXME: needs investigation. */
.bearer_set = NULL
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

303
ofono/drivers/ril/ril_stk.c Normal file
View File

@@ -0,0 +1,303 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 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_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "util.h"
#ifndef UI_LANG
# define UI_LANG "/var/lib/environment/nemo/locale.conf"
#endif
enum ril_stk_events {
STK_EVENT_PROACTIVE_COMMAND,
STK_EVENT_SESSION_END,
STK_EVENT_NOTIFY,
STK_EVENT_COUNT
};
struct ril_stk {
struct ofono_stk *stk;
GRilIoChannel *io;
GRilIoQueue *q;
gulong event_id[STK_EVENT_COUNT];
};
struct ril_stk_cbd {
union _ofono_stk_cb {
ofono_stk_envelope_cb_t envelope;
ofono_stk_generic_cb_t generic;
gpointer ptr;
} cb;
gpointer data;
};
#define ril_stk_cbd_free g_free
static inline struct ril_stk *ril_stk_get_data(struct ofono_stk *stk)
{
return ofono_stk_get_data(stk);
}
struct ril_stk_cbd *ril_stk_cbd_new(void *cb, void *data)
{
struct ril_stk_cbd *cbd = g_new0(struct ril_stk_cbd, 1);
cbd->cb.ptr = cb;
cbd->data = data;
return cbd;
}
static void ril_stk_envelope_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_stk_cbd *cbd = user_data;
ofono_stk_envelope_cb_t cb = cbd->cb.envelope;
if (status == RIL_E_SUCCESS) {
DBG("%u bytes(s)", len);
cb(ril_error_ok(&error), NULL, 0, cbd->data);
} else {
DBG("Envelope reply failure: %s", ril_error_to_string(status));
cb(ril_error_failure(&error), NULL, 0, cbd->data);
}
}
static void ril_stk_envelope(struct ofono_stk *stk, int length,
const unsigned char *cmd, ofono_stk_envelope_cb_t cb, void *data)
{
struct ril_stk *sd = ril_stk_get_data(stk);
GRilIoRequest *req = grilio_request_new();
char *hex_envelope = encode_hex(cmd, length, 0);
DBG("%s", hex_envelope);
grilio_request_append_utf8(req, hex_envelope);
g_free(hex_envelope);
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND,
ril_stk_envelope_cb, ril_stk_cbd_free,
ril_stk_cbd_new(cb, data));
grilio_request_unref(req);
}
static void ril_stk_terminal_response_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_stk_cbd *cbd = user_data;
ofono_stk_generic_cb_t cb = cbd->cb.generic;
DBG("");
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), cbd->data);
} else {
ofono_error("Error in sending terminal response");
cb(ril_error_failure(&error), cbd->data);
}
}
static void ril_stk_terminal_response(struct ofono_stk *stk, int length,
const unsigned char *resp,
ofono_stk_generic_cb_t cb, void *data)
{
struct ril_stk *sd = ril_stk_get_data(stk);
GRilIoRequest *req = grilio_request_new();
char *hex_tr = encode_hex(resp, length, 0);
DBG("rilmodem terminal response: %s", hex_tr);
grilio_request_append_utf8(req, hex_tr);
g_free(hex_tr);
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE,
ril_stk_terminal_response_cb,
ril_stk_cbd_free, ril_stk_cbd_new(cb, data));
grilio_request_unref(req);
}
static void ril_stk_user_confirmation(struct ofono_stk *stk,
ofono_bool_t confirm)
{
struct ril_stk *sd = ril_stk_get_data(stk);
GRilIoRequest *req = grilio_request_sized_new(8);
DBG("%d", confirm);
grilio_request_append_int32(req, 1); /* size of array */
grilio_request_append_int32(req, confirm); /* yes/no */
grilio_queue_send_request(sd->q, req,
RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM);
grilio_request_unref(req);
}
static void ril_stk_pcmd_notify(GRilIoChannel *io, guint code,
const void *data, guint data_len, void *user_data)
{
struct ril_stk *sd = user_data;
GRilIoParser rilp;
char *pcmd;
guchar *pdu;
long len = 0;
GASSERT(code == RIL_UNSOL_STK_PROACTIVE_COMMAND);
grilio_parser_init(&rilp, data, data_len);
pcmd = grilio_parser_get_utf8(&rilp);
DBG("pcmd: %s", pcmd);
pdu = decode_hex(pcmd, strlen(pcmd), &len, -1);
g_free(pcmd);
ofono_stk_proactive_command_notify(sd->stk, len, pdu);
g_free(pdu);
}
static void ril_stk_event_notify(GRilIoChannel *io, guint code,
const void *data, guint data_len, void *user_data)
{
struct ril_stk *sd = user_data;
GRilIoParser rilp;
char *pcmd = NULL;
guchar *pdu = NULL;
long len;
/* Proactive command has been handled by the modem. */
GASSERT(code == RIL_UNSOL_STK_EVENT_NOTIFY);
grilio_parser_init(&rilp, data, data_len);
pcmd = grilio_parser_get_utf8(&rilp);
DBG("pcmd: %s", pcmd);
pdu = decode_hex(pcmd, strlen(pcmd), &len, -1);
g_free(pcmd);
ofono_stk_proactive_command_handled_notify(sd->stk, len, pdu);
g_free(pdu);
}
static void ril_stk_session_end_notify(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_stk *sd = user_data;
DBG("");
GASSERT(code == RIL_UNSOL_STK_SESSION_END);
ofono_stk_proactive_session_end_notify(sd->stk);
}
static void ril_stk_agent_ready(struct ofono_stk *stk)
{
struct ril_stk *sd = ril_stk_get_data(stk);
DBG("");
if (!sd->event_id[STK_EVENT_PROACTIVE_COMMAND]) {
DBG("Subscribing notifications");
sd->event_id[STK_EVENT_PROACTIVE_COMMAND] =
grilio_channel_add_unsol_event_handler(sd->io,
ril_stk_pcmd_notify,
RIL_UNSOL_STK_PROACTIVE_COMMAND, sd);
GASSERT(!sd->event_id[STK_EVENT_SESSION_END]);
sd->event_id[STK_EVENT_SESSION_END] =
grilio_channel_add_unsol_event_handler(sd->io,
ril_stk_session_end_notify,
RIL_UNSOL_STK_SESSION_END, sd);
GASSERT(!sd->event_id[STK_EVENT_NOTIFY]);
sd->event_id[STK_EVENT_NOTIFY] =
grilio_channel_add_unsol_event_handler(sd->io,
ril_stk_event_notify,
RIL_UNSOL_STK_EVENT_NOTIFY, sd);
grilio_queue_send_request(sd->q, NULL,
RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING);
}
}
static void ril_stk_set_lang()
{
GError *error = NULL;
GIOChannel* chan = g_io_channel_new_file(UI_LANG, "r", &error);
if (chan) {
GString* buf = g_string_new(NULL);
gsize term;
while (g_io_channel_read_line_string(chan, buf, &term, NULL) ==
G_IO_STATUS_NORMAL) {
char* lang;
g_string_set_size(buf, term);
lang = strstr(buf->str, "LANG=");
if (lang) {
setenv("LANG", lang + 5, TRUE);
}
}
g_string_free(buf, TRUE);
g_io_channel_unref(chan);
} else {
DBG("%s: %s", UI_LANG, error->message);
g_error_free(error);
}
}
static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor, void *data)
{
struct ril_modem *modem = data;
struct ril_stk *sd = g_new0(struct ril_stk, 1);
DBG("");
sd->stk = stk;
sd->io = grilio_channel_ref(ril_modem_io(modem));
sd->q = grilio_queue_new(sd->io);
ofono_stk_set_data(stk, sd);
ofono_stk_register(stk);
ril_stk_set_lang();
return 0;
}
static void ril_stk_remove(struct ofono_stk *stk)
{
struct ril_stk *sd = ril_stk_get_data(stk);
int i;
DBG("");
ofono_stk_set_data(stk, NULL);
for (i=0; i<G_N_ELEMENTS(sd->event_id); i++) {
grilio_channel_remove_handler(sd->io, sd->event_id[i]);
}
grilio_channel_unref(sd->io);
grilio_queue_cancel_all(sd->q, FALSE);
grilio_queue_unref(sd->q);
g_free(sd);
}
const struct ofono_stk_driver ril_stk_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_stk_probe,
.remove = ril_stk_remove,
.envelope = ril_stk_envelope,
.terminal_response = ril_stk_terminal_response,
.user_confirmation = ril_stk_user_confirmation,
.ready = ril_stk_agent_ready
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,107 @@
# 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,
# 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]
# Required entry, defines the RIL socket path
socket=/dev/socket/rild
# Subscription string. Some (mostly, older) RILs require that 4 bytes
# (usually SUB1 or SUB2) are written to the socket before rild starts
# talking to us.
#
# Not sent by default.
#
#sub=SUB1
# RIL logging prefix, to tell one socket from another in the log.
# Makes sense if you have more than one modem configured.
#
# No prefix by default.
#
#name=RIL1
# Slot id for SET_UICC_SUBSCRIPTION request.
#
# By default the first modem becomes slot 0, the next one slot 1 and so on.
#
#slot=0
# RIL request timeout, in milliseconds.
#
# The default is zero (no timeout)
#
#timeout=0
# Setting this one to false would disable 4G technology selection.
#
# By default 4G is enabled
#
#enable4G=true
# RIL_REQUEST_SET_UICC_SUBSCRIPTION is 115 in RIL version 9 (or earlier)
# and 122 in RIL version 10 and later. Since ofono doesn't know in advance
# which RIL version it's dealing with, it makes the decision at runtime.
# Settings it to false disables the workaround and always sends 122.
#
# Default is true (select SET_UICC_SUBSCRIPTION based on the RIL version)
#
#uiccWorkaround=true
# 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
# Since RIL interface doesn't provide the standard way of querying the
# number of pin retries left, some RIL implementation (namely Qualcomm)
# allow to query the retry count by sending the empty pin. If your RIL
# actually does check the empty pin (and decrements the retry count)
# then you should turn this feature off.
#
# Default is true
#
#emptyPinQuery=true

View File

@@ -0,0 +1,66 @@
/*
* 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_TYPES_H
#define RIL_TYPES_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <grilio_types.h>
#include <gutil_macros.h>
#include <ofono/types.h>
struct ofono_modem;
struct ofono_sim;
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ril_constants.h"
#define RIL_RETRY_SECS (2)
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
struct ril_mce;
struct ril_data;
struct ril_modem;
struct ril_radio;
struct ril_network;
struct ril_sim_card;
struct ril_sim_info;
struct ril_sim_settings;
struct ril_cell_info;
struct ril_slot_config {
guint slot;
gboolean enable_4g;
gboolean empty_pin_query;
};
#endif /* RIL_TYPES_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,223 @@
/*
* 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_util.h"
#include "ril_log.h"
#include "ril_constants.h"
#include "smsutil.h"
#include "util.h"
struct ril_ussd {
struct ofono_ussd *ussd;
GRilIoChannel *io;
GRilIoQueue *q;
guint timer_id;
gulong event_id;
};
struct ril_ussd_cbd {
ofono_ussd_cb_t cb;
gpointer data;
};
#define ril_ussd_cbd_free g_free
static inline struct ril_ussd *ril_ussd_get_data(struct ofono_ussd *ussd)
{
return ofono_ussd_get_data(ussd);
}
static struct ril_ussd_cbd *ril_ussd_cbd_new(ofono_ussd_cb_t cb, void *data)
{
struct ril_ussd_cbd *cbd = g_new0(struct ril_ussd_cbd, 1);
cbd->cb = cb;
cbd->data = data;
return cbd;
}
static void ril_ussd_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_ussd_cbd *cbd = user_data;
if (status == RIL_E_SUCCESS) {
cbd->cb(ril_error_ok(&error), cbd->data);
} else {
cbd->cb(ril_error_failure(&error), cbd->data);
}
}
static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
const unsigned char *pdu, int len, ofono_ussd_cb_t cb, void *data)
{
struct ofono_error error;
enum sms_charset charset;
struct ril_ussd *ud = ril_ussd_get_data(ussd);
ofono_info("send ussd, len:%d", len);
if (cbs_dcs_decode(dcs, NULL, NULL, &charset, NULL, NULL, NULL)) {
if (charset == SMS_CHARSET_7BIT) {
unsigned char unpacked_buf[182];
long written = 0;
unpack_7bit_own_buf(pdu, len, 0, TRUE,
sizeof(unpacked_buf)-1, &written, 0,
unpacked_buf);
unpacked_buf[written] = 0;
if (written >= 1) {
/*
* When USSD was packed, additional CR
* might have been added (according to
* 23.038 6.1.2.3.1). So if the last
* character is CR, it should be removed
* here.
*
* Over 2 characters long USSD string must
* end with # (checked in valid_ussd_string),
* so it should be safe to remove extra CR.
*/
GRilIoRequest *req = grilio_request_new();
int length = strlen((char *)unpacked_buf);
while (length > 2 &&
unpacked_buf[length-1] == '\r') {
unpacked_buf[--length] = 0;
}
grilio_request_append_utf8_chars(req, (char*)
unpacked_buf, length);
grilio_queue_send_request(ud->q, req,
RIL_REQUEST_SEND_USSD);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
return;
}
}
}
cb(ril_error_failure(&error), data);
}
static void ril_ussd_cancel(struct ofono_ussd *ussd,
ofono_ussd_cb_t cb, void *data)
{
struct ril_ussd *ud = ril_ussd_get_data(ussd);
ofono_info("send ussd cancel");
grilio_queue_send_request_full(ud->q, NULL, RIL_REQUEST_CANCEL_USSD,
ril_ussd_cb, ril_ussd_cbd_free, ril_ussd_cbd_new(cb, data));
}
static void ril_ussd_notify(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_ussd *ud = user_data;
GRilIoParser rilp;
char *ussd_from_network = NULL;
char *type = NULL;
int ussdtype = 0;
ofono_info("ussd_received");
GASSERT(code == RIL_UNSOL_ON_USSD);
grilio_parser_init(&rilp, data, len);
grilio_parser_get_uint32(&rilp, NULL);
type = grilio_parser_get_utf8(&rilp);
ussd_from_network = grilio_parser_get_utf8(&rilp);
ussdtype = g_ascii_xdigit_value(*type);
if (ussd_from_network) {
const int data_len = strlen(ussd_from_network);
DBG("ussd_received, length %d", data_len);
ofono_ussd_notify(ud->ussd, ussdtype, 0xFF,
(const unsigned char *) ussd_from_network, data_len);
} else {
ofono_ussd_notify(ud->ussd, ussdtype, 0, NULL, 0);
}
/* ussd_from_network not freed because core does that if dcs is 0xFF */
g_free(type);
return;
}
static gboolean ril_ussd_register(gpointer user_data)
{
struct ril_ussd *ud = user_data;
DBG("");
GASSERT(ud->timer_id);
ud->timer_id = 0;
ofono_ussd_register(ud->ussd);
/* Register for USSD events */
ud->event_id = grilio_channel_add_unsol_event_handler(ud->io,
ril_ussd_notify, RIL_UNSOL_ON_USSD, ud);
/* Single-shot */
return FALSE;
}
static int ril_ussd_probe(struct ofono_ussd *ussd, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
struct ril_ussd *ud = g_try_new0(struct ril_ussd, 1);
DBG("");
ud->ussd = ussd;
ud->io = grilio_channel_ref(ril_modem_io(modem));
ud->q = grilio_queue_new(ud->io);
ud->timer_id = g_idle_add(ril_ussd_register, ud);
ofono_ussd_set_data(ussd, ud);
return 0;
}
static void ril_ussd_remove(struct ofono_ussd *ussd)
{
struct ril_ussd *ud = ril_ussd_get_data(ussd);
DBG("");
ofono_ussd_set_data(ussd, NULL);
if (ud->timer_id > 0) {
g_source_remove(ud->timer_id);
}
grilio_channel_remove_handler(ud->io, ud->event_id);
grilio_channel_unref(ud->io);
grilio_queue_cancel_all(ud->q, FALSE);
grilio_queue_unref(ud->q);
g_free(ud);
}
const struct ofono_ussd_driver ril_ussd_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_ussd_probe,
.remove = ril_ussd_remove,
.request = ril_ussd_request,
.cancel = ril_ussd_cancel
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,399 @@
/*
* 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_util.h"
#include "ril_log.h"
#include <grilio_channel.h>
#include <sys/socket.h>
#include <ctype.h>
#include "common.h"
#include "netreg.h"
const char *ril_error_to_string(int error)
{
#define RIL_E_(name) case RIL_E_##name: return #name
#define GRILIO_E_(name) case GRILIO_STATUS_##name: return "GRILIO_" #name
static char unknown[12];
switch (error) {
case RIL_E_SUCCESS: return "OK";
GRILIO_E_(TIMEOUT);
GRILIO_E_(CANCELLED);
RIL_E_(RADIO_NOT_AVAILABLE);
RIL_E_(GENERIC_FAILURE);
RIL_E_(PASSWORD_INCORRECT);
RIL_E_(SIM_PIN2);
RIL_E_(SIM_PUK2);
RIL_E_(REQUEST_NOT_SUPPORTED);
RIL_E_(CANCELLED);
RIL_E_(OP_NOT_ALLOWED_DURING_VOICE_CALL);
RIL_E_(OP_NOT_ALLOWED_BEFORE_REG_TO_NW);
RIL_E_(SMS_SEND_FAIL_RETRY);
RIL_E_(SIM_ABSENT);
RIL_E_(SUBSCRIPTION_NOT_AVAILABLE);
RIL_E_(MODE_NOT_SUPPORTED);
RIL_E_(FDN_CHECK_FAILURE);
RIL_E_(ILLEGAL_SIM_OR_ME);
RIL_E_(UNUSED);
RIL_E_(DIAL_MODIFIED_TO_USSD);
RIL_E_(DIAL_MODIFIED_TO_SS);
RIL_E_(DIAL_MODIFIED_TO_DIAL);
RIL_E_(USSD_MODIFIED_TO_DIAL);
RIL_E_(USSD_MODIFIED_TO_SS);
RIL_E_(USSD_MODIFIED_TO_USSD);
RIL_E_(SS_MODIFIED_TO_DIAL);
RIL_E_(SS_MODIFIED_TO_USSD);
RIL_E_(SS_MODIFIED_TO_SS);
RIL_E_(SUBSCRIPTION_NOT_SUPPORTED);
RIL_E_(MISSING_RESOURCE);
RIL_E_(NO_SUCH_ELEMENT);
RIL_E_(INVALID_PARAMETER);
default:
snprintf(unknown, sizeof(unknown), "%d", error);
return unknown;
}
}
const char *ril_request_to_string(guint request)
{
#define RIL_REQUEST_(name) case RIL_REQUEST_##name: return #name
static char unknown[24];
switch (request) {
RIL_REQUEST_(GET_SIM_STATUS);
RIL_REQUEST_(ENTER_SIM_PIN);
RIL_REQUEST_(ENTER_SIM_PUK);
RIL_REQUEST_(ENTER_SIM_PIN2);
RIL_REQUEST_(ENTER_SIM_PUK2);
RIL_REQUEST_(CHANGE_SIM_PIN);
RIL_REQUEST_(CHANGE_SIM_PIN2);
RIL_REQUEST_(ENTER_NETWORK_DEPERSONALIZATION);
RIL_REQUEST_(GET_CURRENT_CALLS);
RIL_REQUEST_(DIAL);
RIL_REQUEST_(GET_IMSI);
RIL_REQUEST_(HANGUP);
RIL_REQUEST_(HANGUP_WAITING_OR_BACKGROUND);
RIL_REQUEST_(HANGUP_FOREGROUND_RESUME_BACKGROUND);
RIL_REQUEST_(SWITCH_HOLDING_AND_ACTIVE);
RIL_REQUEST_(CONFERENCE);
RIL_REQUEST_(UDUB);
RIL_REQUEST_(LAST_CALL_FAIL_CAUSE);
RIL_REQUEST_(SIGNAL_STRENGTH);
RIL_REQUEST_(VOICE_REGISTRATION_STATE);
RIL_REQUEST_(DATA_REGISTRATION_STATE);
RIL_REQUEST_(OPERATOR);
RIL_REQUEST_(RADIO_POWER);
RIL_REQUEST_(DTMF);
RIL_REQUEST_(SEND_SMS);
RIL_REQUEST_(SEND_SMS_EXPECT_MORE);
RIL_REQUEST_(SETUP_DATA_CALL);
RIL_REQUEST_(SIM_IO);
RIL_REQUEST_(SEND_USSD);
RIL_REQUEST_(CANCEL_USSD);
RIL_REQUEST_(GET_CLIR);
RIL_REQUEST_(SET_CLIR);
RIL_REQUEST_(QUERY_CALL_FORWARD_STATUS);
RIL_REQUEST_(SET_CALL_FORWARD);
RIL_REQUEST_(QUERY_CALL_WAITING);
RIL_REQUEST_(SET_CALL_WAITING);
RIL_REQUEST_(SMS_ACKNOWLEDGE);
RIL_REQUEST_(GET_IMEI);
RIL_REQUEST_(GET_IMEISV);
RIL_REQUEST_(ANSWER);
RIL_REQUEST_(DEACTIVATE_DATA_CALL);
RIL_REQUEST_(QUERY_FACILITY_LOCK);
RIL_REQUEST_(SET_FACILITY_LOCK);
RIL_REQUEST_(CHANGE_BARRING_PASSWORD);
RIL_REQUEST_(QUERY_NETWORK_SELECTION_MODE);
RIL_REQUEST_(SET_NETWORK_SELECTION_AUTOMATIC);
RIL_REQUEST_(SET_NETWORK_SELECTION_MANUAL);
RIL_REQUEST_(QUERY_AVAILABLE_NETWORKS);
RIL_REQUEST_(DTMF_START);
RIL_REQUEST_(DTMF_STOP);
RIL_REQUEST_(BASEBAND_VERSION);
RIL_REQUEST_(SEPARATE_CONNECTION);
RIL_REQUEST_(SET_MUTE);
RIL_REQUEST_(GET_MUTE);
RIL_REQUEST_(QUERY_CLIP);
RIL_REQUEST_(LAST_DATA_CALL_FAIL_CAUSE);
RIL_REQUEST_(DATA_CALL_LIST);
RIL_REQUEST_(RESET_RADIO);
RIL_REQUEST_(OEM_HOOK_RAW);
RIL_REQUEST_(OEM_HOOK_STRINGS);
RIL_REQUEST_(SCREEN_STATE);
RIL_REQUEST_(SET_SUPP_SVC_NOTIFICATION);
RIL_REQUEST_(WRITE_SMS_TO_SIM);
RIL_REQUEST_(DELETE_SMS_ON_SIM);
RIL_REQUEST_(SET_BAND_MODE);
RIL_REQUEST_(QUERY_AVAILABLE_BAND_MODE);
RIL_REQUEST_(STK_GET_PROFILE);
RIL_REQUEST_(STK_SET_PROFILE);
RIL_REQUEST_(STK_SEND_ENVELOPE_COMMAND);
RIL_REQUEST_(STK_SEND_TERMINAL_RESPONSE);
RIL_REQUEST_(STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM);
RIL_REQUEST_(EXPLICIT_CALL_TRANSFER);
RIL_REQUEST_(SET_PREFERRED_NETWORK_TYPE);
RIL_REQUEST_(GET_PREFERRED_NETWORK_TYPE);
RIL_REQUEST_(GET_NEIGHBORING_CELL_IDS);
RIL_REQUEST_(SET_LOCATION_UPDATES);
RIL_REQUEST_(CDMA_SET_SUBSCRIPTION_SOURCE);
RIL_REQUEST_(CDMA_SET_ROAMING_PREFERENCE);
RIL_REQUEST_(CDMA_QUERY_ROAMING_PREFERENCE);
RIL_REQUEST_(SET_TTY_MODE);
RIL_REQUEST_(QUERY_TTY_MODE);
RIL_REQUEST_(CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE);
RIL_REQUEST_(CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE);
RIL_REQUEST_(CDMA_FLASH);
RIL_REQUEST_(CDMA_BURST_DTMF);
RIL_REQUEST_(CDMA_VALIDATE_AND_WRITE_AKEY);
RIL_REQUEST_(CDMA_SEND_SMS);
RIL_REQUEST_(CDMA_SMS_ACKNOWLEDGE);
RIL_REQUEST_(GSM_GET_BROADCAST_SMS_CONFIG);
RIL_REQUEST_(GSM_SET_BROADCAST_SMS_CONFIG);
RIL_REQUEST_(GSM_SMS_BROADCAST_ACTIVATION);
RIL_REQUEST_(CDMA_GET_BROADCAST_SMS_CONFIG);
RIL_REQUEST_(CDMA_SET_BROADCAST_SMS_CONFIG);
RIL_REQUEST_(CDMA_SMS_BROADCAST_ACTIVATION);
RIL_REQUEST_(CDMA_SUBSCRIPTION);
RIL_REQUEST_(CDMA_WRITE_SMS_TO_RUIM);
RIL_REQUEST_(CDMA_DELETE_SMS_ON_RUIM);
RIL_REQUEST_(DEVICE_IDENTITY);
RIL_REQUEST_(EXIT_EMERGENCY_CALLBACK_MODE);
RIL_REQUEST_(GET_SMSC_ADDRESS);
RIL_REQUEST_(SET_SMSC_ADDRESS);
RIL_REQUEST_(REPORT_SMS_MEMORY_STATUS);
RIL_REQUEST_(REPORT_STK_SERVICE_IS_RUNNING);
RIL_REQUEST_(CDMA_GET_SUBSCRIPTION_SOURCE);
RIL_REQUEST_(ISIM_AUTHENTICATION);
RIL_REQUEST_(ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU);
RIL_REQUEST_(STK_SEND_ENVELOPE_WITH_STATUS);
RIL_REQUEST_(VOICE_RADIO_TECH);
RIL_REQUEST_(GET_CELL_INFO_LIST);
RIL_REQUEST_(SET_UNSOL_CELL_INFO_LIST_RATE);
RIL_REQUEST_(SET_INITIAL_ATTACH_APN);
RIL_REQUEST_(IMS_REGISTRATION_STATE);
RIL_REQUEST_(IMS_SEND_SMS);
RIL_REQUEST_(SIM_TRANSMIT_APDU_BASIC);
RIL_REQUEST_(SIM_OPEN_CHANNEL);
RIL_REQUEST_(SIM_CLOSE_CHANNEL);
RIL_REQUEST_(SIM_TRANSMIT_APDU_CHANNEL);
RIL_REQUEST_(NV_READ_ITEM);
RIL_REQUEST_(NV_WRITE_ITEM);
RIL_REQUEST_(NV_WRITE_CDMA_PRL);
RIL_REQUEST_(NV_RESET_CONFIG);
RIL_REQUEST_(SET_UICC_SUBSCRIPTION);
RIL_REQUEST_(ALLOW_DATA);
RIL_REQUEST_(GET_HARDWARE_CONFIG);
RIL_REQUEST_(SIM_AUTHENTICATION);
RIL_REQUEST_(GET_DC_RT_INFO);
RIL_REQUEST_(SET_DC_RT_INFO_RATE);
RIL_REQUEST_(SET_DATA_PROFILE);
RIL_REQUEST_(SHUTDOWN);
RIL_REQUEST_(GET_RADIO_CAPABILITY);
RIL_REQUEST_(SET_RADIO_CAPABILITY);
default:
snprintf(unknown, sizeof(unknown), "RIL_REQUEST_%d", request);
return unknown;
}
}
const char *ril_unsol_event_to_string(guint event)
{
#define RIL_UNSOL_(name) case RIL_UNSOL_##name: return #name
static char unknown[24];
switch (event) {
RIL_UNSOL_(RESPONSE_RADIO_STATE_CHANGED);
RIL_UNSOL_(RESPONSE_CALL_STATE_CHANGED);
RIL_UNSOL_(RESPONSE_VOICE_NETWORK_STATE_CHANGED);
RIL_UNSOL_(RESPONSE_NEW_SMS);
RIL_UNSOL_(RESPONSE_NEW_SMS_STATUS_REPORT);
RIL_UNSOL_(RESPONSE_NEW_SMS_ON_SIM);
RIL_UNSOL_(ON_USSD);
RIL_UNSOL_(ON_USSD_REQUEST);
RIL_UNSOL_(NITZ_TIME_RECEIVED);
RIL_UNSOL_(SIGNAL_STRENGTH);
RIL_UNSOL_(DATA_CALL_LIST_CHANGED);
RIL_UNSOL_(SUPP_SVC_NOTIFICATION);
RIL_UNSOL_(STK_SESSION_END);
RIL_UNSOL_(STK_PROACTIVE_COMMAND);
RIL_UNSOL_(STK_EVENT_NOTIFY);
RIL_UNSOL_(STK_CALL_SETUP);
RIL_UNSOL_(SIM_SMS_STORAGE_FULL);
RIL_UNSOL_(SIM_REFRESH);
RIL_UNSOL_(CALL_RING);
RIL_UNSOL_(RESPONSE_SIM_STATUS_CHANGED);
RIL_UNSOL_(RESPONSE_CDMA_NEW_SMS);
RIL_UNSOL_(RESPONSE_NEW_BROADCAST_SMS);
RIL_UNSOL_(CDMA_RUIM_SMS_STORAGE_FULL);
RIL_UNSOL_(RESTRICTED_STATE_CHANGED);
RIL_UNSOL_(ENTER_EMERGENCY_CALLBACK_MODE);
RIL_UNSOL_(CDMA_CALL_WAITING);
RIL_UNSOL_(CDMA_OTA_PROVISION_STATUS);
RIL_UNSOL_(CDMA_INFO_REC);
RIL_UNSOL_(OEM_HOOK_RAW);
RIL_UNSOL_(RINGBACK_TONE);
RIL_UNSOL_(RESEND_INCALL_MUTE);
RIL_UNSOL_(CDMA_SUBSCRIPTION_SOURCE_CHANGED);
RIL_UNSOL_(CDMA_PRL_CHANGED);
RIL_UNSOL_(EXIT_EMERGENCY_CALLBACK_MODE);
RIL_UNSOL_(RIL_CONNECTED);
RIL_UNSOL_(VOICE_RADIO_TECH_CHANGED);
RIL_UNSOL_(CELL_INFO_LIST);
RIL_UNSOL_(RESPONSE_IMS_NETWORK_STATE_CHANGED);
RIL_UNSOL_(UICC_SUBSCRIPTION_STATUS_CHANGED);
RIL_UNSOL_(SRVCC_STATE_NOTIFY);
RIL_UNSOL_(HARDWARE_CONFIG_CHANGED);
RIL_UNSOL_(DC_RT_INFO_CHANGED);
RIL_UNSOL_(RADIO_CAPABILITY);
RIL_UNSOL_(ON_SS);
RIL_UNSOL_(STK_CC_ALPHA_NOTIFY);
default:
snprintf(unknown, sizeof(unknown), "RIL_UNSOL_%d", event);
return unknown;
}
}
const char *ril_radio_state_to_string(int radio_state)
{
#define RADIO_STATE_(name) case RADIO_STATE_##name: return #name
static char unknown[16];
switch (radio_state) {
RADIO_STATE_(OFF);
RADIO_STATE_(UNAVAILABLE);
RADIO_STATE_(SIM_NOT_READY);
RADIO_STATE_(SIM_LOCKED_OR_ABSENT);
RADIO_STATE_(SIM_READY);
RADIO_STATE_(RUIM_NOT_READY);
RADIO_STATE_(RUIM_READY);
RADIO_STATE_(RUIM_LOCKED_OR_ABSENT);
RADIO_STATE_(NV_NOT_READY);
RADIO_STATE_(NV_READY);
RADIO_STATE_(ON);
default:
snprintf(unknown, sizeof(unknown), "%d (?)", radio_state);
return unknown;
}
}
int ril_address_family(const char *addr)
{
if (strchr(addr, ':')) {
return AF_INET6;
} else if (strchr(addr, '.')) {
return AF_INET;
} else {
return AF_UNSPEC;
}
}
/* Returns enum access_technology or -1 on failure. */
int ril_parse_tech(const char *stech, int *ril_tech)
{
int access_tech = -1;
int tech = -1;
if (stech && stech[0]) {
tech = atoi(stech);
switch (tech) {
case RADIO_TECH_GPRS:
case RADIO_TECH_GSM:
access_tech = ACCESS_TECHNOLOGY_GSM;
break;
case RADIO_TECH_EDGE:
access_tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
break;
case RADIO_TECH_UMTS:
access_tech = ACCESS_TECHNOLOGY_UTRAN;
break;
case RADIO_TECH_HSDPA:
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA;
break;
case RADIO_TECH_HSUPA:
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSUPA;
break;
case RADIO_TECH_HSPA:
case RADIO_TECH_HSPAP:
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
break;
case RADIO_TECH_LTE:
access_tech = ACCESS_TECHNOLOGY_EUTRAN;
break;
default:
DBG("Unknown RIL tech %s", stech);
/* no break */
case RADIO_TECH_IWLAN:
case RADIO_TECH_UNKNOWN:
tech = -1;
break;
}
}
if (ril_tech) {
*ril_tech = tech;
}
return access_tech;
}
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
{
if (str) {
int i;
const char *ptr = str;
/* Three digit country code */
for (i = 0;
i < OFONO_MAX_MCC_LENGTH && *ptr && isdigit(*ptr);
i++) {
op->mcc[i] = *ptr++;
}
op->mcc[i] = 0;
if (i == OFONO_MAX_MCC_LENGTH) {
/* Usually 2 but sometimes 3 digit network code */
for (i=0;
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
i++) {
op->mnc[i] = *ptr++;
}
op->mnc[i] = 0;
if (i > 0) {
/*
* Sometimes MCC/MNC are followed by + and
* what looks like the technology code. This
* is of course completely undocumented.
*/
if (*ptr == '+') {
int tech = ril_parse_tech(ptr+1, NULL);
if (tech >= 0) {
op->tech = tech;
}
}
return TRUE;
}
}
}
return FALSE;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,50 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_UTIL_H
#define RIL_UTIL_H
#include "ril_types.h"
struct ofono_network_operator;
const char *ril_error_to_string(int error);
const char *ril_request_to_string(guint request);
const char *ril_unsol_event_to_string(guint event);
const char *ril_radio_state_to_string(int radio_state);
int ril_parse_tech(const char *stech, int *ril_tech);
int ril_address_family(const char *addr);
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
#define ril_error_init_ok(err) \
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)
#define ril_error_init_failure(err) \
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_FAILURE)
#define ril_error_init_sim_error(err,sw1,sw2) \
((err)->error = ((sw1) << 8)|(sw2), (err)->type = OFONO_ERROR_TYPE_SIM)
#define ril_error_ok(err) (ril_error_init_ok(err), err)
#define ril_error_failure(err) (ril_error_init_failure(err), err)
#define ril_error_sim(err,sw1,sw2) (ril_error_init_sim_error(err,sw1,sw2), err)
#endif /* RIL_UTIL_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,878 @@
/*
* 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_constants.h"
#include "ril_ecclist.h"
#include "ril_util.h"
#include "ril_log.h"
#include "common.h"
#include <gutil_ring.h>
#define FLAG_NEED_CLIP 1
enum ril_voicecall_events {
VOICECALL_EVENT_CALL_STATE_CHANGED,
VOICECALL_EVENT_SUPP_SVC_NOTIFICATION,
VOICECALL_EVENT_RINGBACK_TONE,
VOICECALL_EVENT_COUNT,
};
struct ril_voicecall {
GSList *calls;
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;
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;
gulong ecclist_change_id;
};
struct ril_voicecall_change_state_req {
struct ofono_voicecall *vc;
ofono_voicecall_cb_t cb;
gpointer data;
int affected_types;
};
struct lastcause_req {
struct ofono_voicecall *vc;
int id;
};
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
/*
* structs ofono_voicecall and voicecall are fully defined
* in src/voicecall.c; we need (read) access to the
* call objects, so partially redefine them here.
*/
struct ofono_voicecall {
GSList *call_list;
/* ... */
};
struct voicecall {
struct ofono_call *call;
/* ... */
};
static inline struct ril_voicecall *ril_voicecall_get_data(
struct ofono_voicecall *vc)
{
return ofono_voicecall_get_data(vc);
}
static gint ril_voicecall_compare(gconstpointer a, gconstpointer b)
{
const struct ofono_call *ca = a;
const struct ofono_call *cb = b;
if (ca->id < cb->id)
return -1;
if (ca->id > cb->id)
return 1;
return 0;
}
static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
{
GRilIoParser rilp;
GSList *l = NULL;
int num = 0, i;
gchar *number, *name;
grilio_parser_init(&rilp, data, len);
/* Number of RIL_Call structs */
grilio_parser_get_int32(&rilp, &num);
for (i = 0; i < num; i++) {
struct ofono_call *call = g_new(struct ofono_call, 1);
gint tmp;
ofono_call_init(call);
grilio_parser_get_int32(&rilp, &call->status);
grilio_parser_get_uint32(&rilp, &call->id);
grilio_parser_get_int32(&rilp, &call->phone_number.type);
grilio_parser_get_int32(&rilp, NULL); /* isMpty */
tmp = 0;
grilio_parser_get_int32(&rilp, &tmp);
call->direction = (tmp ? /* isMT */
CALL_DIRECTION_MOBILE_TERMINATED :
CALL_DIRECTION_MOBILE_ORIGINATED);
grilio_parser_get_int32(&rilp, NULL); /* als */
grilio_parser_get_int32(&rilp, &call->type); /* isVoice */
grilio_parser_get_int32(&rilp, NULL); /* isVoicePrivacy */
number = grilio_parser_get_utf8(&rilp);
if (number) {
strncpy(call->phone_number.number, number,
OFONO_MAX_PHONE_NUMBER_LENGTH);
g_free(number);
}
grilio_parser_get_int32(&rilp, NULL); /* numberPresentation */
name = grilio_parser_get_utf8(&rilp);
if (name) {
strncpy(call->name, name, OFONO_MAX_CALLER_NAME_LENGTH);
g_free(name);
}
grilio_parser_get_int32(&rilp, NULL); /* namePresentation */
grilio_parser_get_int32(&rilp, &tmp); /* uusInfo */
GASSERT(!tmp);
if (strlen(call->phone_number.number) > 0) {
call->clip_validity = 0;
} else {
call->clip_validity = 2;
}
DBG("[id=%d,status=%d,type=%d,number=%s,name=%s]",
call->id, call->status, call->type,
call->phone_number.number, call->name);
l = g_slist_insert_sorted(l, call, ril_voicecall_compare);
}
return l;
}
/* Valid call statuses have value >= 0 */
static int call_status_with_id(struct ofono_voicecall *vc, int id)
{
GSList *l;
struct voicecall *v;
GASSERT(vc);
for (l = vc->call_list; l; l = l->next) {
v = l->data;
if (v->call->id == id) {
return v->call->status;
}
}
return -1;
}
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct lastcause_req *reqdata = user_data;
struct ofono_voicecall *vc = reqdata->vc;
int tmp;
int id = reqdata->id;
int call_status;
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
grilio_parser_get_int32(&rilp, &last_cause);
}
/*
* Not all call control cause values specified in 3GPP TS 24.008
* "Mobile radio interface Layer 3 specification; Core network
* protocols", Annex H, are properly reflected in the RIL API.
* For example, cause #21 "call rejected" is mapped to
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
* from a network failure.
*/
switch (last_cause) {
case CALL_FAIL_UNOBTAINABLE_NUMBER:
case CALL_FAIL_NORMAL:
case CALL_FAIL_BUSY:
case CALL_FAIL_NO_ROUTE_TO_DESTINATION:
case CALL_FAIL_CHANNEL_UNACCEPTABLE:
case CALL_FAIL_OPERATOR_DETERMINED_BARRING:
case CALL_FAIL_NO_USER_RESPONDING:
case CALL_FAIL_USER_ALERTING_NO_ANSWER:
case CALL_FAIL_CALL_REJECTED:
case CALL_FAIL_NUMBER_CHANGED:
case CALL_FAIL_ANONYMOUS_CALL_REJECTION:
case CALL_FAIL_PRE_EMPTION:
case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
case CALL_FAIL_INCOMPLETE_NUMBER:
case CALL_FAIL_FACILITY_REJECTED:
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
break;
case CALL_FAIL_NORMAL_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
if (call_status == CALL_STATUS_ACTIVE ||
call_status == CALL_STATUS_HELD ||
call_status == CALL_STATUS_DIALING ||
call_status == CALL_STATUS_ALERTING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
} else if (call_status == CALL_STATUS_INCOMING) {
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
}
break;
case CALL_FAIL_ERROR_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
if (call_status == CALL_STATUS_DIALING ||
call_status == CALL_STATUS_ALERTING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
}
break;
default:
reason = OFONO_DISCONNECT_REASON_ERROR;
break;
}
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
id, last_cause, reason);
ofono_voicecall_disconnected(vc, id, reason, NULL);
}
static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_voicecall *vd = user_data;
GSList *calls;
GSList *n, *o;
struct ofono_error error;
GASSERT(vd->clcc_poll_id);
vd->clcc_poll_id = 0;
if (status != RIL_E_SUCCESS) {
ofono_error("We are polling CLCC and received an error");
ofono_error("All bets are off for call management");
return;
}
calls = ril_voicecall_parse_clcc(data, len);
n = calls;
o = vd->calls;
while (n || o) {
struct ofono_call *nc = n ? n->data : NULL;
struct ofono_call *oc = o ? o->data : NULL;
if (oc && (nc == NULL || (nc->id > oc->id))) {
if (vd->local_release & (1 << oc->id)) {
ofono_voicecall_disconnected(vd->vc, oc->id,
OFONO_DISCONNECT_REASON_LOCAL_HANGUP,
NULL);
} else {
/* Get disconnect cause before informing
* oFono core */
struct lastcause_req *reqdata =
g_new0(struct lastcause_req, 1);
reqdata->vc = vd->vc;
reqdata->id = oc->id;
grilio_queue_send_request_full(vd->q, NULL,
RIL_REQUEST_LAST_CALL_FAIL_CAUSE,
ril_voicecall_lastcause_cb,
g_free, reqdata);
}
ril_voicecall_clear_dtmf_queue(vd);
o = o->next;
} else if (nc && (oc == NULL || (nc->id < oc->id))) {
/* new call, signal it */
if (nc->type) {
ofono_voicecall_notify(vd->vc, nc);
if (vd->cb) {
ofono_voicecall_cb_t cb = vd->cb;
void *cbdata = vd->data;
vd->cb = NULL;
vd->data = NULL;
cb(ril_error_ok(&error), cbdata);
}
}
n = n->next;
} else {
/*
* Always use the clip_validity from old call
* the only place this is truly told to us is
* in the CLIP notify, the rest are fudged
* anyway. Useful when RING, CLIP is used,
* and we're forced to use CLCC and clip_validity
* is 1
*/
if (oc->clip_validity == 1) {
nc->clip_validity = oc->clip_validity;
}
nc->cnap_validity = oc->cnap_validity;
/*
* CDIP doesn't arrive as part of CLCC, always
* re-use from the old call
*/
memcpy(&nc->called_number, &oc->called_number,
sizeof(oc->called_number));
/*
* If the CLIP is not provided and the CLIP never
* arrives, or RING is used, then signal the call
* here
*/
if (nc->status == CALL_STATUS_INCOMING &&
(vd->flags & FLAG_NEED_CLIP)) {
if (nc->type) {
ofono_voicecall_notify(vd->vc, nc);
}
vd->flags &= ~FLAG_NEED_CLIP;
} else if (memcmp(nc, oc, sizeof(*nc)) && nc->type) {
ofono_voicecall_notify(vd->vc, nc);
}
n = n->next;
o = o->next;
}
}
g_slist_free_full(vd->calls, g_free);
vd->calls = calls;
vd->local_release = 0;
}
static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
{
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,
req, RIL_REQUEST_GET_CURRENT_CALLS,
ril_voicecall_clcc_poll_cb, NULL, vd);
grilio_request_unref(req);
}
}
static void ril_voicecall_request_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_voicecall_change_state_req *req = user_data;
struct ril_voicecall *vd = ril_voicecall_get_data(req->vc);
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
GSList *l;
if (req->affected_types) {
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
if (req->affected_types & (1 << call->status)) {
vd->local_release |= (1 << call->id);
}
}
}
ril_error_init_ok(&error);
} else {
ofono_error("generic fail");
ril_error_init_failure(&error);
}
ril_voicecall_clcc_poll(vd);
/* We have to callback after we schedule a poll if required */
if (req->cb) {
req->cb(&error, req->data);
}
}
static void ril_voicecall_request(const guint rreq, struct ofono_voicecall *vc,
unsigned int affected_types, GRilIoRequest *ioreq,
ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ril_voicecall_change_state_req *req;
req = g_new0(struct ril_voicecall_change_state_req, 1);
req->vc = vc;
req->cb = cb;
req->data = data;
req->affected_types = affected_types;
grilio_queue_send_request_full(vd->q, ioreq, rreq,
ril_voicecall_request_cb, g_free, req);
}
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_voicecall *vd = user_data;
if (status == RIL_E_SUCCESS) {
if (vd->cb) {
/* CLCC will update the oFono call list with
* proper ids if it's not done yet */
ril_voicecall_clcc_poll(vd);
}
} else {
ofono_error("call failed.");
/*
* 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);
}
}
}
static void ril_voicecall_dial(struct ofono_voicecall *vc,
const struct ofono_phone_number *ph,
enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
const char *phstr = phone_number_to_string(ph);
GRilIoRequest *req = grilio_request_new();
ofono_info("dialing \"%s\"", phstr);
DBG("%s,%d,0", phstr, clir);
GASSERT(!vd->cb);
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, NULL, vd);
grilio_request_unref(req);
}
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ofono_error error;
GSList *l;
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
GRilIoRequest *req = grilio_request_sized_new(8);
/* TODO: Hangup just the active ones once we have call
* state tracking (otherwise it can't handle ringing) */
DBG("Hanging up call with id %d", call->id);
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
grilio_request_append_int32(req, call->id);
/* Send request to RIL */
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req,
NULL, NULL);
grilio_request_unref(req);
}
/* TODO: Deal in case of an error at hungup */
cb(ril_error_ok(&error), data);
}
static void ril_voicecall_hangup_specific(struct ofono_voicecall *vc,
int id, ofono_voicecall_cb_t cb, void *data)
{
GRilIoRequest *req = grilio_request_sized_new(8);
struct ofono_error error;
DBG("Hanging up call with id %d", id);
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
grilio_request_append_int32(req, id);
/* Send request to RIL */
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req, NULL, NULL);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
}
static void ril_voicecall_call_state_changed_event(GRilIoChannel *io,
guint ril_event, const void *data, guint len, void *user_data)
{
struct ril_voicecall *vd = user_data;
GASSERT(ril_event == RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);
/* Just need to request the call list again */
ril_voicecall_clcc_poll(vd);
}
static void ril_voicecall_supp_svc_notification_event(GRilIoChannel *io,
guint ril_event, const void *data, guint len, void *user_data)
{
GRilIoParser rilp;
struct ril_voicecall *vd = user_data;
struct ofono_phone_number phone;
int type = 0, code = 0, index = 0;
char *tmp = NULL;
GASSERT(ril_event == RIL_UNSOL_SUPP_SVC_NOTIFICATION);
grilio_parser_init(&rilp, data, len);
grilio_parser_get_int32(&rilp, &type);
grilio_parser_get_int32(&rilp, &code);
grilio_parser_get_int32(&rilp, &index);
grilio_parser_get_int32(&rilp, NULL);
tmp = grilio_parser_get_utf8(&rilp);
if (tmp) {
strncpy(phone.number, tmp, OFONO_MAX_PHONE_NUMBER_LENGTH);
phone.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = 0;
g_free(tmp);
} else {
phone.number[0] = 0;
}
DBG("RIL data: MT/MO: %i, code: %i, index: %i", type, code, index);
/* 0 stands for MO intermediate (support TBD), 1 for MT unsolicited */
if (type == 1) {
ofono_voicecall_ssn_mt_notify(vd->vc, 0, code, index, &phone);
} else {
ofono_error("Unknown SS notification");
}
}
static void ril_voicecall_answer(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
/* Send request to RIL */
DBG("Answering current call");
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, 0, NULL, cb, data);
}
static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_voicecall *vd = user_data;
GASSERT(vd->send_dtmf_id);
vd->send_dtmf_id = 0;
if (status == RIL_E_SUCCESS) {
/* Send the next one */
ril_voicecall_send_one_dtmf(vd);
} else {
DBG("error=%d", status);
ril_voicecall_clear_dtmf_queue(vd);
}
}
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd)
{
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 */
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);
}
}
static void ril_voicecall_send_dtmf(struct ofono_voicecall *vc,
const char *dtmf, ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ofono_error error;
/*
* Queue any incoming DTMF, send them to RIL one-by-one,
* immediately call back core with no error
*/
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)
{
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;
}
}
static void ril_voicecall_clcc_poll_on_success(GRilIoChannel *io,
int status, const void *data, guint len, void *user_data)
{
if (status == RIL_E_SUCCESS) {
ril_voicecall_clcc_poll((struct ril_voicecall *)user_data);
}
}
static void ril_voicecall_create_multiparty(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
grilio_queue_send_request_full(vd->q, NULL, RIL_REQUEST_CONFERENCE,
ril_voicecall_clcc_poll_on_success, NULL, vd);
}
static void ril_voicecall_transfer(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_EXPLICIT_CALL_TRANSFER,
vc, 0, NULL, cb, data);
}
static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, id);
grilio_queue_send_request_full(vd->q, req,
RIL_REQUEST_SEPARATE_CONNECTION,
ril_voicecall_clcc_poll_on_success, NULL, vd);
grilio_request_unref(req);
}
static void ril_voicecall_swap_without_accept(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
vc, 0, NULL, cb, data);
}
static void ril_voicecall_hold_all_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
vc, 0, NULL, cb, data);
}
static void ril_voicecall_release_all_held(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
vc, 0, NULL, cb, data);
}
static void ril_voicecall_release_all_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
vc, 0, NULL, cb, data);
}
static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
vc, 0, NULL, cb, data);
}
static gboolean ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
{
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1); /* size of array */
grilio_request_append_int32(req, 1); /* notifications enabled */
grilio_queue_send_request(vd->q, req,
RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION);
grilio_request_unref(req);
/* Makes this a single shot */
return FALSE;
}
static void ril_voicecall_ringback_tone_event(GRilIoChannel *io,
guint code, const void *data, guint len, void *user_data)
{
struct ril_voicecall *vd = user_data;
GRilIoParser rilp;
guint32 playTone = FALSE;
int tmp;
GASSERT(code == RIL_UNSOL_RINGBACK_TONE);
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
grilio_parser_get_uint32(&rilp, &playTone);
}
DBG("play ringback tone: %d", playTone);
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;
GASSERT(vd->timer_id);
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);
/* request supplementary service notifications*/
ril_voicecall_enable_supp_svc(vd);
/* Unsol when call state changes */
vd->event_id[VOICECALL_EVENT_CALL_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(vd->io,
ril_voicecall_call_state_changed_event,
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, vd);
/* Unsol when call set in hold */
vd->event_id[VOICECALL_EVENT_SUPP_SVC_NOTIFICATION] =
grilio_channel_add_unsol_event_handler(vd->io,
ril_voicecall_supp_svc_notification_event,
RIL_UNSOL_SUPP_SVC_NOTIFICATION, vd);
/* Register for ringback tone notifications */
vd->event_id[VOICECALL_EVENT_RINGBACK_TONE] =
grilio_channel_add_unsol_event_handler(vd->io,
ril_voicecall_ringback_tone_event,
RIL_UNSOL_RINGBACK_TONE, vd);
/* This makes the timeout a single-shot */
return FALSE;
}
static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
struct ril_voicecall *vd;
DBG("");
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;
}
static void ril_voicecall_remove(struct ofono_voicecall *vc)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
DBG("");
ofono_voicecall_set_data(vc, NULL);
g_slist_free_full(vd->calls, g_free);
if (vd->timer_id > 0) {
g_source_remove(vd->timer_id);
}
ril_ecclist_remove_handler(vd->ecclist, vd->ecclist_change_id);
ril_ecclist_unref(vd->ecclist);
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);
gutil_ring_unref(vd->dtmf_queue);
g_free(vd);
}
const struct ofono_voicecall_driver ril_voicecall_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_voicecall_probe,
.remove = ril_voicecall_remove,
.dial = ril_voicecall_dial,
.answer = ril_voicecall_answer,
.hangup_all = ril_voicecall_hangup_all,
.release_specific = ril_voicecall_hangup_specific,
.send_tones = ril_voicecall_send_dtmf,
.create_multiparty = ril_voicecall_create_multiparty,
.transfer = ril_voicecall_transfer,
.private_chat = ril_voicecall_private_chat,
.swap_without_accept = ril_voicecall_swap_without_accept,
.hold_all_active = ril_voicecall_hold_all_active,
.release_all_held = ril_voicecall_release_all_held,
.set_udub = ril_voicecall_set_udub,
.release_all_active = ril_voicecall_release_all_active
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,310 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2014 Jolla Ltd
* Contact: Miia Leinonen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <glib.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include "common.h"
#include "gril.h"
#include "call-barring.h"
#include "rilmodem.h"
#include "ril_constants.h"
/* See 3GPP 27.007 7.4 for possible values */
#define RIL_MAX_SERVICE_LENGTH 3
/*
* ril.h does not state that string count must be given, but that is
* still expected by the modem
*/
#define RIL_QUERY_STRING_COUNT 4
#define RIL_SET_STRING_COUNT 5
#define RIL_SET_PW_STRING_COUNT 3
#define RIL_LENGTH_ZERO 0
struct barring_data {
GRil *ril;
guint timer_id;
};
static void ril_call_barring_query_cb(struct ril_msg *message,
gpointer user_data)
{
struct cb_data *cbd = user_data;
struct parcel rilp;
struct ofono_error error;
ofono_call_barring_query_cb_t cb = cbd->cb;
int bearer_class = 0;
if (message->error != RIL_E_SUCCESS) {
ofono_error("Call Barring query failed, err: %i",
message->error);
decode_ril_error(&error, "FAIL");
goto out;
}
ril_util_init_parcel(message, &rilp);
/*
* Services for which the specified barring facility is active.
* "0" means "disabled for all, -1 if unknown"
*/
parcel_r_int32(&rilp); /* count - we know there is only 1 */
bearer_class = parcel_r_int32(&rilp);
DBG("Active services: %i", bearer_class);
decode_ril_error(&error, "OK");
out:
cb(&error, bearer_class, cbd->data);
}
static void ril_call_barring_query(struct ofono_call_barring *cb,
const char *lock, int cls,
ofono_call_barring_query_cb_t callback,
void *data)
{
struct barring_data *bd = ofono_call_barring_get_data(cb);
struct cb_data *cbd = cb_data_new(callback, data);
struct parcel rilp;
int ret = 0;
char cls_textual[RIL_MAX_SERVICE_LENGTH];
DBG("lock: %s, services to query: %i", lock, cls);
/*
* RIL modems do not support 7 as default bearer class. According to
* the 22.030 Annex C: When service code is not given it corresponds to
* "All tele and bearer services"
*/
if (cls == BEARER_CLASS_DEFAULT)
cls = SERVICE_CLASS_NONE;
sprintf(cls_textual, "%d", cls);
/*
* See 3GPP 27.007 7.4 for parameter descriptions.
* According to ril.h password should be empty string "" when not
* needed, but in reality we only need to give string length as 0
*/
parcel_init(&rilp);
parcel_w_int32(&rilp, RIL_QUERY_STRING_COUNT); /* Nbr of strings */
parcel_w_string(&rilp, (char *) lock); /* Facility code */
parcel_w_int32(&rilp, RIL_LENGTH_ZERO); /* Password length */
parcel_w_string(&rilp, (char *) cls_textual);
parcel_w_string(&rilp, NULL); /* AID (for FDN, not yet supported) */
ret = g_ril_send(bd->ril, RIL_REQUEST_QUERY_FACILITY_LOCK,
rilp.data, rilp.size, ril_call_barring_query_cb,
cbd, g_free);
parcel_free(&rilp);
if (ret <= 0) {
ofono_error("Sending Call Barring query failed, err: %i", ret);
g_free(cbd);
CALLBACK_WITH_FAILURE(callback, -1, data);
}
}
static void ril_call_barring_set_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
struct ofono_error error;
ofono_call_barring_set_cb_t cb = cbd->cb;
if (message->error != RIL_E_SUCCESS) {
ofono_error("Call Barring Set request failed, err: %i",
message->error);
decode_ril_error(&error, "FAIL");
goto out;
}
decode_ril_error(&error, "OK");
out:
cb(&error, cbd->data);
}
static void ril_call_barring_set(struct ofono_call_barring *cb,
const char *lock, int enable,
const char *passwd, int cls,
ofono_call_barring_set_cb_t callback,
void *data)
{
struct barring_data *bd = ofono_call_barring_get_data(cb);
struct cb_data *cbd = cb_data_new(callback, data);
struct parcel rilp;
int ret = 0;
char cls_textual[RIL_MAX_SERVICE_LENGTH];
DBG("lock: %s, enable: %i, bearer class: %i", lock, enable, cls);
/*
* RIL modem does not support 7 as default bearer class. According to
* the 22.030 Annex C: When service code is not given it corresponds to
* "All tele and bearer services"
*/
if (cls == BEARER_CLASS_DEFAULT)
cls = SERVICE_CLASS_NONE;
sprintf(cls_textual, "%d", cls);
/* See 3GPP 27.007 7.4 for parameter descriptions */
parcel_init(&rilp);
parcel_w_int32(&rilp, RIL_SET_STRING_COUNT); /* Nbr of strings */
parcel_w_string(&rilp, (char *) lock); /* Facility code */
if (enable)
parcel_w_string(&rilp, RIL_FACILITY_LOCK);
else
parcel_w_string(&rilp, RIL_FACILITY_UNLOCK);
parcel_w_string(&rilp, (char *) passwd);
parcel_w_string(&rilp, (char *) cls_textual);
parcel_w_string(&rilp, NULL); /* AID (for FDN, not yet supported) */
ret = g_ril_send(bd->ril, RIL_REQUEST_SET_FACILITY_LOCK,
rilp.data, rilp.size, ril_call_barring_set_cb,
cbd, g_free);
parcel_free(&rilp);
if (ret <= 0) {
ofono_error("Sending Call Barring Set request failed, err: %i",
ret);
g_free(cbd);
CALLBACK_WITH_FAILURE(callback, data);
}
}
static void ril_call_barring_set_passwd_cb(struct ril_msg *message,
gpointer user_data)
{
struct cb_data *cbd = user_data;
struct ofono_error error;
ofono_call_barring_set_cb_t cb = cbd->cb;
if (message->error != RIL_E_SUCCESS) {
ofono_error("Call Barring Set PW req failed, err: %i",
message->error);
decode_ril_error(&error, "FAIL");
goto out;
}
decode_ril_error(&error, "OK");
out:
cb(&error, cbd->data);
}
static void ril_call_barring_set_passwd(struct ofono_call_barring *barr,
const char *lock,
const char *old_passwd,
const char *new_passwd,
ofono_call_barring_set_cb_t cb,
void *data)
{
struct barring_data *bd = ofono_call_barring_get_data(barr);
struct cb_data *cbd = cb_data_new(cb, data);
struct parcel rilp;
int ret = 0;
DBG("");
parcel_init(&rilp);
parcel_w_int32(&rilp, RIL_SET_PW_STRING_COUNT); /* Nbr of strings */
parcel_w_string(&rilp, (char *) lock); /* Facility code */
parcel_w_string(&rilp, (char *) old_passwd);
parcel_w_string(&rilp, (char *) new_passwd);
ret = g_ril_send(bd->ril, RIL_REQUEST_CHANGE_BARRING_PASSWORD,
rilp.data, rilp.size, ril_call_barring_set_passwd_cb,
cbd, g_free);
parcel_free(&rilp);
if (ret <= 0) {
ofono_error("Sending Call Barring Set PW req failed, err: %i",
ret);
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
}
static gboolean ril_delayed_register(gpointer user_data)
{
struct ofono_call_barring *cb = user_data;
struct barring_data *bd = ofono_call_barring_get_data(cb);
bd->timer_id = 0;
ofono_call_barring_register(cb);
return FALSE;
}
static int ril_call_barring_probe(struct ofono_call_barring *cb,
unsigned int vendor, void *user)
{
GRil *ril = user;
struct barring_data *bd = g_try_new0(struct barring_data, 1);
bd->ril = g_ril_clone(ril);
ofono_call_barring_set_data(cb, bd);
bd->timer_id = g_timeout_add_seconds(2, ril_delayed_register, cb);
return 0;
}
static void ril_call_barring_remove(struct ofono_call_barring *cb)
{
struct barring_data *data = ofono_call_barring_get_data(cb);
ofono_call_barring_set_data(cb, NULL);
if (data->timer_id > 0)
g_source_remove(data->timer_id);
g_ril_unref(data->ril);
g_free(data);
}
static struct ofono_call_barring_driver driver = {
.name = "rilmodem",
.probe = ril_call_barring_probe,
.remove = ril_call_barring_remove,
.query = ril_call_barring_query,
.set = ril_call_barring_set,
.set_passwd = ril_call_barring_set_passwd
};
void ril_call_barring_init(void)
{
ofono_call_barring_driver_register(&driver);
}
void ril_call_barring_exit(void)
{
ofono_call_barring_driver_unregister(&driver);
}

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-2014 Jolla Ltd
* Contact: Jussi Kangas <jussi.kangas@tieto.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -89,16 +89,13 @@ static void ril_registration(struct ofono_call_forwarding *cf, int type,
parcel_w_int32(&rilp, type);
/* Modem seems to respond with error to all queries
/*
* Modem seems to respond with error to all queries
* or settings made with bearer class
* BEARER_CLASS_DEFAULT. Design decision: If given
* class is BEARER_CLASS_DEFAULT let's map it to
* SERVICE_CLASS_VOICE effectively making it the
* default bearer. This in line with API which is
* contains only voice anyways. TODO: Checkout
* the behaviour with final modem
* BEARER_CLASS_VOICE as per RIL design.
*/
if (cls == BEARER_CLASS_DEFAULT)
cls = BEARER_CLASS_VOICE;
@@ -137,16 +134,13 @@ static void ril_send_forward_cmd(struct ofono_call_forwarding *cf,
parcel_w_int32(&rilp, type);
/* Modem seems to respond with error to all queries
/*
* Modem seems to respond with error to all queries
* or settings made with bearer class
* BEARER_CLASS_DEFAULT. Design decision: If given
* class is BEARER_CLASS_DEFAULT let's map it to
* SERVICE_CLASS_VOICE effectively making it the
* default bearer. This in line with API which is
* contains only voice anyways. TODO: Checkout
* the behaviour with final modem
* BEARER_CLASS_VOICE as per RIL design.
*/
if (cls == BEARER_CLASS_DEFAULT)
cls = BEARER_CLASS_VOICE;
@@ -220,7 +214,7 @@ static void ril_query_cb(struct ril_msg *message, gpointer user_data)
nmbr_of_resps);
for (i = 0; i < nmbr_of_resps; i++) {
const char *str;
char *str = NULL;
list[i].status = parcel_r_int32(&rilp);
@@ -231,22 +225,19 @@ static void ril_query_cb(struct ril_msg *message, gpointer user_data)
list[i].phone_number.type = parcel_r_int32(&rilp);
str = parcel_r_string(&rilp);
if (str) {
strncpy(list[i].phone_number.number,
str,
OFONO_MAX_PHONE_NUMBER_LENGTH);
list[i].phone_number.number[
OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
list[i].time = parcel_r_int32(&rilp);
g_free(str);
}
list[i].time = parcel_r_int32(&rilp);
}
CALLBACK_WITH_SUCCESS(cb, 1, list, cbd->data);
CALLBACK_WITH_SUCCESS(cb, nmbr_of_resps, list, cbd->data);
g_free(list);
} else {
@@ -272,18 +263,15 @@ static void ril_query(struct ofono_call_forwarding *cf, int type, int cls,
parcel_w_int32(&rilp, type);
/* Modem seems to respond with error to all queries
/*
* Modem seems to respond with error to all queries
* or settings made with bearer class
* BEARER_CLASS_DEFAULT. Design decision: If given
* class is BEARER_CLASS_DEFAULT let's map it to
* SERVICE_CLASS_VOICE effectively making it the
* default bearer. This in line with API which is
* contains only voice anyways. TODO: Checkout
* the behaviour with final modem
* SERVICE_CLASS_NONE as per RIL design.
*/
if (cls == BEARER_CLASS_DEFAULT)
cls = BEARER_CLASS_VOICE;
cls = SERVICE_CLASS_NONE;
parcel_w_int32(&rilp, cls);
@@ -351,10 +339,10 @@ static struct ofono_call_forwarding_driver driver = {
.probe = ril_call_forwarding_probe,
.remove = ril_call_forwarding_remove,
.erasure = ril_erasure,
.deactivation = ril_deactivate,
.deactivation = ril_deactivate,
.query = ril_query,
.registration = ril_registration,
.activation = ril_activate
.registration = ril_registration,
.activation = ril_activate
};
void ril_call_forwarding_init(void)

View File

@@ -42,9 +42,8 @@
#include "rilmodem.h"
/*
* TODO: The functions in this file are stubbed out, and
* will need to be re-worked to talk to the /gril layer
* in order to get real values from RILD.
* TODO: No public RIL api to query manufacturer or model.
* Check where to get, could /system/build.prop be updated to have good values?
*/
guint timer_id;
@@ -52,30 +51,14 @@ static void ril_query_manufacturer(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb,
void *data)
{
const char *attr = "Fake Manufacturer";
struct cb_data *cbd = cb_data_new(cb, data);
struct ofono_error error;
decode_ril_error(&error, "OK");
cb(&error, attr, cbd->data);
/* Note: this will need to change if cbd passed to gril layer */
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, "", data);
}
static void ril_query_model(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb,
void *data)
{
const char *attr = "Fake Modem Model";
struct cb_data *cbd = cb_data_new(cb, data);
struct ofono_error error;
decode_ril_error(&error, "OK");
cb(&error, attr, cbd->data);
/* Note: this will need to change if cbd passed to gril layer */
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, "", data);
}
static void query_revision_cb(struct ril_msg *message, gpointer user_data)
@@ -98,6 +81,7 @@ static void query_revision_cb(struct ril_msg *message, gpointer user_data)
revision = parcel_r_string(&rilp);
cb(&error, revision, cbd->data);
g_free(revision);
}
static void ril_query_revision(struct ofono_devinfo *info,
@@ -137,10 +121,10 @@ static void query_serial_cb(struct ril_msg *message, gpointer user_data)
}
ril_util_init_parcel(message, &rilp);
imei = parcel_r_string(&rilp);
cb(&error, imei, cbd->data);
g_free(imei);
}
static void ril_query_serial(struct ofono_devinfo *info,

View File

@@ -43,8 +43,16 @@
#include "grilrequest.h"
#include "grilunsol.h"
#include "common.h"
#include "rilmodem.h"
enum data_call_state {
DATA_CALL_INACTIVE,
DATA_CALL_LINK_DOWN,
DATA_CALL_ACTIVE,
};
enum state {
STATE_IDLE,
STATE_ENABLING,
@@ -58,24 +66,111 @@ struct gprs_context_data {
gint active_rild_cid;
enum state state;
guint regid;
struct unsol_data_call_list *old_list;
guint prev_active_status;
};
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
unsigned int id,
ofono_gprs_context_cb_t cb, void *data);
static void set_context_disconnected(struct gprs_context_data *gcd)
{
DBG("");
gcd->active_ctx_cid = -1;
gcd->active_rild_cid = -1;
gcd->state = STATE_IDLE;
}
static void disconnect_context(struct ofono_gprs_context *gc)
static void ril_gprs_split_ip_by_protocol(char **ip_array,
char ***split_ip_addr,
char ***split_ipv6_addr,
char **ip_addr)
{
ril_gprs_context_deactivate_primary(gc, 0, NULL, NULL);
const char ipv6_delimiter = ':';
const char ip_delimiter = '.';
int i;
*split_ipv6_addr = *split_ip_addr = NULL;
for (i=0; i< g_strv_length(ip_array); i++) {
if (strchr(ip_array[i], ipv6_delimiter)) {
if (*split_ipv6_addr == NULL) {
*split_ipv6_addr = g_strsplit(
ip_array[i], "/",2);
}
} else if (strchr(ip_array[i], ip_delimiter)) {
if (*split_ip_addr == NULL) {
*ip_addr = g_strdup(ip_array[i]);
*split_ip_addr = g_strsplit(
ip_array[i], "/", 2);
}
}
}
}
static void ril_gprs_split_gw_by_protocol(char **gw_array, char **ip_gw,
char **ipv6_gw)
{
const char ipv6_delimiter = ':';
const char ip_delimiter = '.';
int i;
*ip_gw = *ipv6_gw = NULL;
for (i=0; i< g_strv_length(gw_array); i++) {
if (strchr(gw_array[i],ipv6_delimiter)) {
if (*ipv6_gw == NULL) {
*ipv6_gw = g_strdup(gw_array[i]);
}
} else if (strchr(gw_array[i],ip_delimiter)) {
if (*ip_gw == NULL)
*ip_gw = g_strdup(gw_array[i]);
}
}
}
static void ril_gprs_split_dns_by_protocol(char **dns_array, char ***dns_addr,
char ***dns_ipv6_addr)
{
const char ipv6_delimiter = ':';
const char ip_delimiter = '.';
char *temp = NULL;
char *temp1 = NULL;
char *dnsip = NULL;
char *dnsipv6 = NULL;
int i, dnsip_len, dnsipv6_len;
dnsip_len = dnsipv6_len = 0;
for (i=0; i< g_strv_length(dns_array); i++) {
if (strchr(dns_array[i],ipv6_delimiter)) {
if (dnsipv6 == NULL) {
dnsipv6 = g_strdup(dns_array[i]);
} else {
temp = g_strconcat(dnsipv6, ",", NULL);
g_free(dnsipv6);
temp1 = g_strconcat(temp, dns_array[i], NULL);
g_free(temp);
dnsipv6 = temp1;
}
dnsipv6_len++;
} else if (strchr(dns_array[i],ip_delimiter)) {
if (dnsip == NULL) {
dnsip = g_strdup(dns_array[i]);
} else {
temp = g_strconcat(dnsip, ",", NULL);
g_free(dnsip);
temp1 = g_strconcat(temp, dns_array[i], NULL);
g_free(temp);
dnsip = temp1;
}
dnsip_len++;
}
}
if (dnsip)
*dns_addr = g_strsplit(dnsip, ",", dnsip_len);
if (dnsipv6)
*dns_ipv6_addr = g_strsplit(dnsipv6, ",", dnsipv6_len);
g_free(dnsip);
g_free(dnsipv6);
}
static void ril_gprs_context_call_list_changed(struct ril_msg *message,
@@ -85,8 +180,8 @@ static void ril_gprs_context_call_list_changed(struct ril_msg *message,
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
struct data_call *call = NULL;
struct unsol_data_call_list *unsol;
gboolean active_cid_found = FALSE;
gboolean disconnect = FALSE;
gboolean signal = FALSE;
GSList *iterator = NULL;
struct ofono_error error;
@@ -95,28 +190,164 @@ static void ril_gprs_context_call_list_changed(struct ril_msg *message,
if (error.type != OFONO_ERROR_TYPE_NO_ERROR)
goto error;
if (g_ril_unsol_cmp_dcl(unsol,gcd->old_list,gcd->active_rild_cid))
goto error;
g_ril_unsol_free_data_call_list(gcd->old_list);
gcd->old_list = unsol;
DBG("number of call in call_list_changed is: %d", unsol->num);
for (iterator = unsol->call_list; iterator; iterator = iterator->next) {
call = (struct data_call *) iterator->data;
if (call->cid == gcd->active_rild_cid) {
active_cid_found = TRUE;
/*
* Every context receives notifications about all data calls
* but should only handle its own.
*/
if (call->cid != gcd->active_rild_cid)
continue;
if (call->active == 0) {
disconnect = TRUE;
ofono_gprs_context_deactivated(gc, gcd->active_ctx_cid);
if (call->active == DATA_CALL_LINK_DOWN)
gcd->prev_active_status = call->active;
if (call->status != 0)
ofono_info("data call status:%d", call->status);
if (call->active == DATA_CALL_INACTIVE) {
disconnect = TRUE;
gcd->prev_active_status = call->active;
ofono_gprs_context_deactivated(gc, gcd->active_ctx_cid);
break;
}
if (call->active == DATA_CALL_ACTIVE) {
int protocol = -1;
if (gcd->prev_active_status != DATA_CALL_LINK_DOWN)
signal = TRUE;
gcd->prev_active_status = call->active;
if (call->type)
protocol = ril_protocol_string_to_ofono_protocol(call->type);
if (call->ifname)
ofono_gprs_context_set_interface(gc,
call->ifname);
if (call->addresses) {
char **split_ip_addr = NULL;
char **ip_array = NULL;
char **split_ipv6_addr = NULL;
char *ip_addr = NULL;
/*addresses to an array*/
ip_array = g_strsplit(call->addresses, " ",-1);
/*pick 1 address of each protocol*/
ril_gprs_split_ip_by_protocol(ip_array,
&split_ip_addr,
&split_ipv6_addr,
&ip_addr);
if ((protocol == OFONO_GPRS_PROTO_IPV4V6 ||
protocol == OFONO_GPRS_PROTO_IPV6)
&& split_ipv6_addr != NULL){
ofono_gprs_context_set_ipv6_address(gc,
split_ipv6_addr[0]);
}
if ((protocol == OFONO_GPRS_PROTO_IPV4V6 ||
protocol == OFONO_GPRS_PROTO_IP)
&& split_ip_addr != NULL) {
ofono_gprs_context_set_ipv4_netmask(gc,
ril_util_get_netmask(ip_addr));
ofono_gprs_context_set_ipv4_address(gc,
split_ip_addr[0], TRUE);
}
g_strfreev(split_ip_addr);
g_strfreev(split_ipv6_addr);
g_strfreev(ip_array);
g_free(ip_addr);
}
if (call->gateways) {
char **gw_array = NULL;
char *ip_gw = NULL;
char *ipv6_gw = NULL;
/*addresses to an array*/
gw_array = g_strsplit(call->gateways, " ", -1);
/*pick 1 gw for each protocol*/
ril_gprs_split_gw_by_protocol(gw_array, &ip_gw,
&ipv6_gw);
if ((protocol == OFONO_GPRS_PROTO_IPV4V6 ||
protocol == OFONO_GPRS_PROTO_IPV6)
&& ipv6_gw != NULL)
ofono_gprs_context_set_ipv6_gateway(gc,
ipv6_gw);
if ((protocol == OFONO_GPRS_PROTO_IPV4V6 ||
protocol == OFONO_GPRS_PROTO_IP)
&& ip_gw != NULL)
ofono_gprs_context_set_ipv4_gateway(gc,
ip_gw);
g_strfreev(gw_array);
g_free(ip_gw);
g_free(ipv6_gw);
}
if (call->dnses) {
char **dns_array = NULL;
char **dns_ip = NULL;
char **dns_ipv6 = NULL;
/*addresses to an array*/
dns_array = g_strsplit(call->dnses, " ", -1);
/*split based on protocol*/
ril_gprs_split_dns_by_protocol(dns_array,
&dns_ip,
&dns_ipv6);
if ((protocol == OFONO_GPRS_PROTO_IPV4V6 ||
protocol == OFONO_GPRS_PROTO_IPV6)
&& dns_ipv6 != NULL)
ofono_gprs_context_set_ipv6_dns_servers(
gc, (const char **) dns_ipv6);
if ((protocol == OFONO_GPRS_PROTO_IPV4V6 ||
protocol == OFONO_GPRS_PROTO_IP)
&& dns_ip != NULL)
ofono_gprs_context_set_ipv4_dns_servers(
gc, (const char**)dns_ip);
g_strfreev(dns_ip);
g_strfreev(dns_ipv6);
g_strfreev(dns_array);
}
break;
}
}
if (disconnect || active_cid_found == FALSE) {
if (disconnect) {
ofono_error("Clearing active context");
set_context_disconnected(gcd);
gcd->old_list = NULL;
goto error;
}
if (signal)
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
return;
error:
g_ril_unsol_free_data_call_list(unsol);
}
@@ -130,6 +361,12 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer user_data)
struct ofono_error error;
struct reply_setup_data_call *reply = NULL;
char **split_ip_addr = NULL;
char **split_ipv6_addr = NULL;
char* ip_addr = NULL;
char* ip_gw = NULL;
char* ipv6_gw = NULL;
char** dns_addr = NULL;
char** dns_ipv6_addr = NULL;
ofono_info("setting up data call");
@@ -149,10 +386,7 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer user_data)
gcd->active_rild_cid = reply->cid;
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
if (gcd->active_rild_cid != -1) {
ofono_error("no active context. disconnect");
disconnect_context(gc);
}
ofono_error("no active context. disconnect");
goto error;
}
@@ -164,24 +398,16 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer user_data)
error.type = OFONO_ERROR_TYPE_FAILURE;
error.error = reply->status;
set_context_disconnected(gcd);
goto error;
}
/*
* TODO: consier moving this into parse_data_reply
*
* Note - the address may optionally include a prefix size
* ( Eg. "/30" ). As this confuses NetworkManager, we
* explicitly strip any prefix after calculating the netmask.
*/
split_ip_addr = g_strsplit(reply->ip_addrs[0], "/", 2);
/*check the ip address protocol*/
ril_gprs_split_ip_by_protocol(reply->ip_addrs, &split_ip_addr,
&split_ipv6_addr, &ip_addr);
/* TODO: see note above re: invalid messages... */
if (split_ip_addr[0] == NULL) {
ofono_error("%s: invalid IP address field returned: %s",
__func__,
reply->ip_addrs[0]);
if (split_ip_addr == NULL && split_ipv6_addr == NULL) {
ofono_error("%s: No IP address returned",
__func__);
error.type = OFONO_ERROR_TYPE_FAILURE;
error.error = EINVAL;
@@ -194,33 +420,55 @@ static void ril_setup_data_call_cb(struct ril_msg *message, gpointer user_data)
ofono_gprs_context_set_interface(gc, reply->ifname);
ril_gprs_split_gw_by_protocol(reply->gateways, &ip_gw, &ipv6_gw);
ril_gprs_split_dns_by_protocol(reply->dns_addresses, &dns_addr,
&dns_ipv6_addr);
/* TODO:
* RILD can return multiple addresses; oFono only supports
* setting a single IPv4 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.
* 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.
*/
ofono_gprs_context_set_ipv4_netmask(gc,
ril_util_get_netmask(reply->ip_addrs[0]));
ofono_gprs_context_set_ipv4_address(gc, split_ip_addr[0], TRUE);
ofono_gprs_context_set_ipv4_gateway(gc, reply->gateways[0]);
if (split_ipv6_addr != NULL &&
(reply->protocol == OFONO_GPRS_PROTO_IPV6 ||
reply->protocol == OFONO_GPRS_PROTO_IPV4V6)) {
ofono_gprs_context_set_ipv4_dns_servers(gc,
(const char **) reply->dns_addresses);
ofono_gprs_context_set_ipv6_address(gc, split_ipv6_addr[0]);
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
ofono_gprs_context_set_ipv6_dns_servers(gc,
(const char **) dns_ipv6_addr);
}
if (split_ip_addr != NULL &&
(reply->protocol == OFONO_GPRS_PROTO_IP ||
reply->protocol == OFONO_GPRS_PROTO_IPV4V6)) {
ofono_gprs_context_set_ipv4_netmask(gc,
ril_util_get_netmask(ip_addr));
ofono_gprs_context_set_ipv4_address(gc, split_ip_addr[0], TRUE);
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
ofono_gprs_context_set_ipv4_dns_servers(gc,
(const char **) dns_addr);
}
error:
g_ril_reply_free_setup_data_call(reply);
g_strfreev(split_ip_addr);
g_strfreev(split_ipv6_addr);
g_strfreev(dns_addr);
g_strfreev(dns_ipv6_addr);
g_free(ip_addr);
g_free(ip_gw);
g_free(ipv6_gw);
cb(&error, cbd->data);
}
static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
const struct ofono_gprs_primary_context *ctx,
ofono_gprs_context_cb_t cb, void *data)
const struct ofono_gprs_primary_context *ctx,
ofono_gprs_context_cb_t cb, void *data)
{
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
struct cb_data *cbd = cb_data_new(cb, data);
@@ -229,9 +477,19 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
struct ofono_error error;
int reqid = RIL_REQUEST_SETUP_DATA_CALL;
int ret = 0;
int netreg_status;
int roaming = NETWORK_REGISTRATION_STATUS_ROAMING;
ofono_info("Activating context: %d", ctx->cid);
/* Let's make sure that we aren't connecting when roaming not allowed */
netreg_status = get_current_network_status();
if (netreg_status == roaming) {
if (!ril_roaming_allowed() && (roaming
== check_if_really_roaming(netreg_status)))
goto exit;
}
cbd->user = gc;
/* TODO: implement radio technology selection. */
@@ -245,6 +503,7 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
request.username = g_strdup(ctx->username);
request.password = g_strdup(ctx->password);
request.auth_type = RIL_AUTH_BOTH;
request.protocol = ctx->proto;
if (g_ril_request_setup_data_call(gcd->ril,
@@ -273,7 +532,7 @@ error:
g_free(request.apn);
g_free(request.username);
g_free(request.password);
exit:
if (ret <= 0) {
ofono_error("Send RIL_REQUEST_SETUP_DATA_CALL failed.");
@@ -284,7 +543,8 @@ error:
}
}
static void ril_deactivate_data_call_cb(struct ril_msg *message, gpointer user_data)
static void ril_deactivate_data_call_cb(struct ril_msg *message,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_gprs_context_cb_t cb = cbd->cb;
@@ -322,7 +582,8 @@ static void ril_deactivate_data_call_cb(struct ril_msg *message, gpointer user_d
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
unsigned int id,
ofono_gprs_context_cb_t cb, void *data)
ofono_gprs_context_cb_t cb,
void *data)
{
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
struct cb_data *cbd = NULL;
@@ -375,6 +636,7 @@ error:
if (ret <= 0) {
ofono_error("Send RIL_REQUEST_DEACTIVATE_DATA_CALL failed.");
g_free(cbd);
if (cb)
CALLBACK_WITH_FAILURE(cb, data);
}
@@ -402,7 +664,6 @@ static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
set_context_disconnected(gcd);
ofono_gprs_context_set_data(gc, gcd);
gcd->regid = -1;
gcd->regid = g_ril_register(gcd->ril, RIL_UNSOL_DATA_CALL_LIST_CHANGED,
ril_gprs_context_call_list_changed, gc);
@@ -415,14 +676,15 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
DBG("");
if (gcd->state != STATE_IDLE) {
g_ril_unsol_free_data_call_list(gcd->old_list);
if (gcd->state != STATE_IDLE)
ril_gprs_context_detach_shutdown(gc, 0);
}
ofono_gprs_context_set_data(gc, NULL);
if (gcd->regid != -1)
g_ril_unregister(gcd->ril,gcd->regid);
g_ril_unregister(gcd->ril, gcd->regid);
g_ril_unref(gcd->ril);
g_free(gcd);
@@ -432,9 +694,9 @@ static struct ofono_gprs_context_driver driver = {
.name = RILMODEM,
.probe = ril_gprs_context_probe,
.remove = ril_gprs_context_remove,
.activate_primary = ril_gprs_context_activate_primary,
.deactivate_primary = ril_gprs_context_deactivate_primary,
.detach_shutdown = ril_gprs_context_detach_shutdown,
.activate_primary = ril_gprs_context_activate_primary,
.deactivate_primary = ril_gprs_context_deactivate_primary,
.detach_shutdown = ril_gprs_context_detach_shutdown,
};
void ril_gprs_context_init(void)

View File

@@ -45,6 +45,8 @@
#include "rilmodem.h"
#include <ofono/netreg.h>
#include <ofono/sim.h>
#include "storage.h"
/*
* This module is the ofono_gprs_driver implementation for rilmodem.
@@ -67,12 +69,18 @@ struct gprs_data {
GRil *ril;
gboolean ofono_attached;
int max_cids;
int rild_status;
gboolean notified;
int rild_status; /* Driver Status */
guint registerid;
guint timer_id;
};
/* Following constants are purely to improve readability */
static const int roaming = NETWORK_REGISTRATION_STATUS_ROAMING;
static const int registered = NETWORK_REGISTRATION_STATUS_REGISTERED;
/*if we have called ofono_gprs_register or not*/
static gboolean ofono_registered;
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
ofono_gprs_status_cb_t cb,
void *data);
@@ -81,7 +89,10 @@ static void ril_gprs_state_change(struct ril_msg *message, gpointer user_data)
{
struct ofono_gprs *gprs = user_data;
g_assert(message->req == RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
g_assert(message->req ==
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
DBG("");
/* We need to notify core always to cover situations when
* connection drops temporarily for example when user is
@@ -97,6 +108,7 @@ static gboolean ril_gprs_set_attached_callback(gpointer user_data)
ofono_gprs_cb_t cb = cbd->cb;
struct ofono_gprs *gprs = cbd->user;
struct gprs_data *gd = ofono_gprs_get_data(gprs);
DBG("");
gd->timer_id = 0;
@@ -133,7 +145,6 @@ static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
cbd->user = gprs;
ril_gprs_registration_status(gprs, NULL, NULL);
/*
* However we cannot respond immediately, since core sets the
* value of driver_attached after calling set_attached and that
@@ -144,6 +155,30 @@ static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
cbd);
}
gboolean ril_roaming_allowed()
{
GError *error;
error = NULL;
GKeyFile *settings;
struct ofono_sim *sim;
sim = get_sim();
const char *imsi = ofono_sim_get_imsi(sim);
settings = storage_open(imsi, "gprs");
gboolean roaming_allowed = g_key_file_get_boolean(settings,
"Settings",
"RoamingAllowed",
&error);
if (error)
g_error_free(error);
storage_close(imsi, "gprs", settings, FALSE);
DBG("roaming_allowed: %d", roaming_allowed);
return roaming_allowed;
}
static void ril_data_reg_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -151,9 +186,9 @@ static void ril_data_reg_cb(struct ril_msg *message, gpointer user_data)
struct ofono_gprs *gprs = cbd->user;
struct gprs_data *gd = ofono_gprs_get_data(gprs);
struct ofono_error error;
int status, lac, ci, tech;
int lac, ci, tech;
int max_cids = 1;
int id = RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED;
int status = -1;
if (gd && message->error == RIL_E_SUCCESS) {
decode_ril_error(&error, "OK");
@@ -162,24 +197,22 @@ static void ril_data_reg_cb(struct ril_msg *message, gpointer user_data)
ril_error_to_string(message->error));
decode_ril_error(&error, "FAIL");
error.error = message->error;
status = -1;
goto error;
goto exit;
}
if (ril_util_parse_reg(gd->ril, message, &status,
&lac, &ci, &tech, &max_cids) == FALSE) {
ofono_error("Failure parsing data registration response.");
decode_ril_error(&error, "FAIL");
status = -1;
goto error;
goto exit;
}
if (gd->rild_status == -1) {
ofono_gprs_register(gprs);
if (status > 10)
status = status - 10;
DBG("Starting to listen network status");
gd->registerid = g_ril_register(gd->ril,
id, ril_gprs_state_change, gprs);
if (!ofono_registered) {
ofono_gprs_register(gprs);
ofono_registered = TRUE;
}
if (max_cids > gd->max_cids) {
@@ -188,70 +221,129 @@ static void ril_data_reg_cb(struct ril_msg *message, gpointer user_data)
ofono_gprs_set_cid_range(gprs, 1, max_cids);
}
ofono_info("data registration status is %d", status);
if (status == NETWORK_REGISTRATION_STATUS_ROAMING)
if (status == roaming)
status = check_if_really_roaming(status);
if (gd->ofono_attached && !gd->notified) {
if (status == NETWORK_REGISTRATION_STATUS_ROAMING ||
status == NETWORK_REGISTRATION_STATUS_REGISTERED) {
DBG("connection becomes available");
/* Let's minimize logging */
if (status != gd->rild_status)
ofono_info("data reg changes %d (%d), attached %d",
status, gd->rild_status, gd->ofono_attached);
/* Must be attached if registered or roaming */
if ((gd->rild_status != registered) && (gd->rild_status != roaming)) {
if (status == registered)
gd->ofono_attached = TRUE;
else if ((status == roaming) && (ril_roaming_allowed() == TRUE))
gd->ofono_attached = TRUE;
ofono_gprs_status_notify(gprs, status);
gd->notified = TRUE;
gd->rild_status = status;
}
goto error;
}
if (gd->ofono_attached &&
status != NETWORK_REGISTRATION_STATUS_SEARCHING) {
DBG("ofono attached, start faking responses");
if (status != NETWORK_REGISTRATION_STATUS_ROAMING) {
if (!ofono_modem_get_online(ofono_gprs_get_modem(gprs)))
gd->ofono_attached = FALSE;
/* if unsolicitated and no state change let's not notify core */
if ((status == gd->rild_status) && gd->ofono_attached)
goto cb_out;
if (!gd->ofono_attached) {
if (!cb) {
if (status == roaming) {
if (ril_roaming_allowed() == FALSE)
ofono_gprs_detached_notify(gprs);
/*
* This prevents core ending
* into eternal loop with driver
*/
decode_ril_error(&error, "FAIL");
}
ofono_gprs_status_notify(gprs, status);
} else {
/*
* Only core can succesfully drop the connection
* If we drop the connection from here it leads
* to race situation where core asks context
* deactivation and at the same time we get
* Registered notification from modem.
*/
status = NETWORK_REGISTRATION_STATUS_REGISTERED;
* This prevents core ending
* into eternal loop with driver
*/
decode_ril_error(&error, "FAIL");
}
if (gd->registerid != -1)
g_ril_unregister(gd->ril, gd->registerid);
gd->registerid = -1;
} else {
/*
* Client is not approving succesful result
* This covers the situation when context is
* active in roaming situation and client closes
* it directly by calling RoamingAllowed in API
*/
DBG("data registration status is %d", status);
if (status != NETWORK_REGISTRATION_STATUS_SEARCHING) {
DBG("ofono not attached, notify core");
status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
ofono_gprs_detached_notify(gprs);
gd->notified = FALSE;
gd->ofono_attached = FALSE;
} else if (gd->notified) {
DBG("hide the searching state");
status = NETWORK_REGISTRATION_STATUS_REGISTERED;
ofono_gprs_status_notify(gprs, status);
gd->ofono_attached = TRUE;
}
gd->rild_status = status;
goto exit;
}
if (!cb)
ofono_gprs_status_notify(gprs, status);
gd->rild_status = status;
error:
exit:
DBG("data reg status %d, rild_status %d, attached %d",
status, gd->rild_status, gd->ofono_attached);
cb_out:
if (cb)
cb(&error, status, cbd->data);
}
static void ril_data_probe_reg_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
struct ofono_gprs *gprs = cbd->user;
struct gprs_data *gd = ofono_gprs_get_data(gprs);
struct ofono_error error;
int status, lac, ci, tech;
int max_cids = 1;
int id = RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED;
DBG("");
if (!(gd && message->error == RIL_E_SUCCESS)) {
ofono_error("ril_data_reg_cb: reply failure: %s",
ril_error_to_string(message->error));
decode_ril_error(&error, "FAIL");
error.error = message->error;
status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
goto out;
}
decode_ril_error(&error, "OK");
status = -1;
if (ril_util_parse_reg(gd->ril, message, &status,
&lac, &ci, &tech, &max_cids) == FALSE) {
ofono_error("Failure parsing data registration response.");
decode_ril_error(&error, "FAIL");
if (status == -1)
status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
goto out;
}
if (status > 10)
status = status - 10;
ofono_gprs_register(gprs);
ofono_registered = TRUE;
if (max_cids > gd->max_cids) {
DBG("Setting max cids to %d", max_cids);
gd->max_cids = max_cids;
ofono_gprs_set_cid_range(gprs, 1, max_cids);
}
if (status == roaming)
status = check_if_really_roaming(status);
out:
ofono_info("data reg status probed %d", status);
gd->registerid = g_ril_register(gd->ril,
id, ril_gprs_state_change, gprs);
gd->rild_status = status;
}
static void ril_gprs_registration_status(struct ofono_gprs *gprs,
ofono_gprs_status_cb_t cb,
void *data)
@@ -261,20 +353,27 @@ static void ril_gprs_registration_status(struct ofono_gprs *gprs,
int request = RIL_REQUEST_DATA_REGISTRATION_STATE;
guint ret;
DBG("");
if (gd == NULL || cbd == NULL)
return;
cbd->user = gprs;
ret = g_ril_send(gd->ril, request,
NULL, 0, ril_data_reg_cb, cbd, g_free);
NULL, 0,
((gd->rild_status == -1)
? ril_data_probe_reg_cb
: ril_data_reg_cb), cbd, g_free);
g_ril_print_request_no_args(gd->ril, ret, request);
if (ret <= 0) {
ofono_error("Send RIL_REQUEST_DATA_RESTISTRATION_STATE failed.");
ofono_error("Send RIL_REQUEST_DATA_RESTISTRATION_STATE fail.");
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, -1, data);
if (cb)
CALLBACK_WITH_FAILURE(cb, -1, data);
}
}
@@ -292,9 +391,11 @@ static int ril_gprs_probe(struct ofono_gprs *gprs,
gd->ofono_attached = FALSE;
gd->max_cids = 0;
gd->rild_status = -1;
gd->notified = FALSE;
gd->registerid = -1;
gd->timer_id = 0;
ofono_registered = FALSE;
ofono_gprs_set_data(gprs, gd);
ril_gprs_registration_status(gprs, NULL, NULL);

View File

@@ -55,14 +55,7 @@ struct netreg_data {
guint nitz_timeout;
unsigned int vendor;
guint timer_id;
};
/* 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,
int corestatus; /* Registration status previously reported to core */
};
struct ofono_netreg *current_netreg;
@@ -78,25 +71,20 @@ static void extract_mcc_mnc(const char *str, char *mcc, char *mnc)
mnc[OFONO_MAX_MNC_LENGTH] = '\0';
}
/*
* TODO: The functions in this file are stubbed out, and
* will need to be re-worked to talk to the /gril layer
* in order to get real values from RILD.
*/
static void ril_creg_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_netreg_status_cb_t cb = cbd->cb;
struct netreg_data *nd = cbd->user;
struct ofono_error error;
int status, lac, ci, tech;
int status, logstatus, lac, ci, tech;
DBG("");
if (message->error != RIL_E_SUCCESS) {
decode_ril_error(&error, "FAIL");
ofono_error("Failed to pull registration state");
ofono_error("voice registration status query fail");
nd->corestatus = -1;
cb(&error, -1, -1, -1, -1, cbd->data);
return;
}
@@ -105,20 +93,31 @@ static void ril_creg_cb(struct ril_msg *message, gpointer user_data)
if (ril_util_parse_reg(nd->ril, message, &status,
&lac, &ci, &tech, NULL) == FALSE) {
DBG("voice registration status parsing fail");
nd->corestatus = -1;
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, cbd->data);
return;
}
DBG("voice registration status is %d", status);
if (status > 10)
status = status - 10;
logstatus = status;
if (status == NETWORK_REGISTRATION_STATUS_ROAMING)
status = check_if_really_roaming(status);
ofono_info("voice registration status is %d", status);
DBG("status:%d corestatus:%d", status, nd->corestatus);
if (status != logstatus)
ofono_info("voice registration modified %d (%d)",
status, logstatus);
if (nd->corestatus != status)
ofono_info("voice registration changes %d (%d)",
status, nd->corestatus);
nd->corestatus = status;
nd->tech = tech;
cb(&error, status, lac, ci, tech, cbd->data);
}
@@ -128,15 +127,16 @@ static void ril_creg_notify(struct ofono_error *error, int status, int lac,
{
struct ofono_netreg *netreg = user_data;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error during status notification");
return;
}
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error during status notification");
return;
}
ofono_netreg_status_notify(netreg, status, lac, ci, tech);
}
static void ril_network_state_change(struct ril_msg *message, gpointer user_data)
static void ril_network_state_change(struct ril_msg *message,
gpointer user_data)
{
struct ofono_netreg *netreg = user_data;
struct netreg_data *nd = ofono_netreg_get_data(netreg);
@@ -364,6 +364,7 @@ static void ril_cops_list_cb(struct ril_msg *message, gpointer user_data)
cb(&error, noperators, list, cbd->data);
g_free(list);
return;
error:
@@ -405,7 +406,8 @@ static void ril_register_cb(struct ril_msg *message, gpointer user_data)
g_ril_print_response_no_args(nd->ril, message);
} else {
ofono_error("registration failed");
ofono_error("registration failed, ril result %d",
message->error);
decode_ril_error(&error, "FAIL");
}
@@ -421,6 +423,8 @@ static void ril_register_auto(struct ofono_netreg *netreg,
int ret;
cbd->user = nd;
ofono_info("nw select automatic");
ret = g_ril_send(nd->ril, request,
NULL, 0, ril_register_cb, cbd, g_free);
@@ -444,6 +448,8 @@ static void ril_register_manual(struct ofono_netreg *netreg,
int request = RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL;
int ret;
ofono_info("nw select manual: %s%s", mcc, mnc);
/* add *netreg_data to callback */
cbd->user = nd;
@@ -573,6 +579,17 @@ error:
ofono_error("Unable to notify ofono about nitz");
}
gboolean check_if_ok_to_attach()
{
int status = NETWORK_REGISTRATION_STATUS_SEARCHING;
status = ofono_netreg_get_status(current_netreg);
if (status == NETWORK_REGISTRATION_STATUS_SEARCHING
|| status == NETWORK_REGISTRATION_STATUS_ROAMING
|| status == NETWORK_REGISTRATION_STATUS_REGISTERED)
return TRUE;
return FALSE;
}
gint check_if_really_roaming(gint status)
{
const char *net_mcc = ofono_netreg_get_mcc(current_netreg);
@@ -580,14 +597,20 @@ gint check_if_really_roaming(gint status)
struct sim_spdi *spdi = ofono_netreg_get_spdi(current_netreg);
if (spdi && net_mcc && net_mnc) {
if (sim_spdi_lookup(spdi, net_mcc, net_mnc))
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
ofono_info("voice reg: not roaming based on spdi");
return NETWORK_REGISTRATION_STATUS_REGISTERED;
else
} else
return status;
} else
return status;
}
gint get_current_network_status()
{
return ofono_netreg_get_status(current_netreg);
}
static gboolean ril_delayed_register(gpointer user_data)
{
struct ofono_netreg *netreg = user_data;
@@ -632,6 +655,7 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
nd->time.year = -1;
nd->time.dst = 0;
nd->time.utcoff = 0;
nd->corestatus = -1;
current_netreg = netreg;
ofono_netreg_set_data(netreg, nd);
@@ -658,6 +682,7 @@ static void ril_netreg_remove(struct ofono_netreg *netreg)
g_source_remove(nd->nitz_timeout);
ofono_netreg_set_data(netreg, NULL);
current_netreg = NULL;
if (nd->timer_id > 0)
g_source_remove(nd->timer_id);

View File

@@ -38,14 +38,18 @@
struct oem_raw_data {
GRil *ril;
unsigned int vendor;
guint timer_id;
};
static gboolean ril_oemraw_delayed_register(gpointer user_data)
{
struct ofono_oem_raw *raw = user_data;
struct oem_raw_data *od = ofono_oem_raw_get_data(raw);
DBG("");
od->timer_id = 0;
ofono_oem_raw_dbus_register(raw);
return FALSE; /* This makes the timeout a single-shot */
}
@@ -64,7 +68,8 @@ static int ril_oemraw_probe(struct ofono_oem_raw *raw, unsigned int vendor,
od->vendor = vendor;
ofono_oem_raw_set_data(raw, od);
g_timeout_add_seconds(1, ril_oemraw_delayed_register, raw);
od->timer_id = g_timeout_add_seconds(1, ril_oemraw_delayed_register,
raw);
return 0;
}
@@ -79,6 +84,9 @@ static void ril_oemraw_remove(struct ofono_oem_raw *raw)
ofono_oem_raw_set_data(raw, NULL);
if (od->timer_id)
g_source_remove(od->timer_id);
g_ril_unref(od->ril);
g_free(od);
}

View File

@@ -6,7 +6,6 @@
* Copyright (C) ST-Ericsson SA 2010.
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013 Jolla Ltd
* Contact: Jussi Kangas <jussi.kangas@tieto.com>
*
* 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
@@ -162,11 +161,18 @@ void handle_adn(size_t len, char *name, const unsigned char *msg,
char *number, struct pb_file_info *next_file,
struct pb_data *pbd)
{
const uint8_t name_length = len - 14;
const uint8_t number_start = name_length;
uint8_t name_length;
uint8_t number_start;
uint8_t number_length = 0;
uint8_t extension_record = UNUSED;
uint8_t i, prefix;
if (len < 14)
return;
name_length = len - 14;
number_start = name_length;
name = sim_string_to_utf8(msg, name_length);
/* Length contains also TON&NPI */
number_length = msg[number_start];
@@ -256,15 +262,19 @@ void handle_adn(size_t len, char *name, const unsigned char *msg,
}
}
void handle_sne(size_t len,
const unsigned char *msg,
char *sne)
void handle_sne(size_t len, const unsigned char *msg, char *sne)
{
const uint8_t sne_length = len - 2;
uint8_t phonebook_entry_nbr = msg[len - 1];
uint8_t sne_length;
uint8_t phonebook_entry_nbr;
DBG("SNE");
if (len < 2)
return;
sne_length = len - 2;
phonebook_entry_nbr = msg[len - 1];
sne = sim_string_to_utf8(msg, sne_length);
if (sne) {
@@ -282,37 +292,40 @@ void handle_sne(size_t len,
list_entry->data;
if (entry) {
/* If one already exists,
delete it */
if (entry->sne)
g_free(entry->sne);
DBG("Adding SNE to entry %d",
phonebook_entry_nbr);
DBG("name %s", entry->name);
g_free(entry->sne);
entry->sne = sne;
} else {
g_free(sne);
return;
}
}
g_free(sne);
}
}
void handle_anr(size_t len,
const unsigned char *msg,
char *anr,
struct pb_file_info *next_file,
struct pb_data *pbd)
void handle_anr(size_t len,const unsigned char *msg,char *anr,
struct pb_file_info *next_file, struct pb_data *pbd)
{
uint8_t number_length = 0;
uint8_t extension_record = UNUSED;
uint8_t aas_record = UNUSED;
uint8_t i, prefix;
uint8_t phonebook_entry_nbr = msg[len - 1];
uint8_t phonebook_entry_nbr;
GSList *list_entry;
DBG("ANR");
if (!msg)
return;
if (len < 1)
return;
phonebook_entry_nbr = msg[len - 1];
if (msg[0] == UNUSED)
return;
@@ -328,7 +341,7 @@ void handle_anr(size_t len,
prefix = 0;
if ((msg[2] & TON_MASK) ==
TON_INTERNATIONAL) {
TON_INTERNATIONAL) {
anr[0] = '+';
prefix = 1;
}
@@ -398,11 +411,18 @@ void handle_anr(size_t len,
}
}
void handle_email(size_t len,
const unsigned char *msg,
char *email)
void handle_email(size_t len, const unsigned char *msg, char *email)
{
uint8_t phonebook_entry_nbr = msg[len - 1];
uint8_t phonebook_entry_nbr;
if (!msg)
return;
if (len < 1)
return;
phonebook_entry_nbr = msg[len - 1];
email = sim_string_to_utf8(msg, len - 2);
/* GSlist nth counts from 0, PB entries from 1 */
@@ -434,13 +454,13 @@ void handle_email(size_t len,
}
}
void handle_ext1(struct pb_data *pbd,
const unsigned char *msg,
char *ext_number,
struct pb_file_info *next_file)
void handle_ext1(struct pb_data *pbd, const unsigned char *msg,
char *ext_number, struct pb_file_info *next_file)
{
uint8_t number_length, i, next_extension_record;
if (!msg)
return;
number_length = msg[1];
@@ -494,7 +514,7 @@ void handle_ext1(struct pb_data *pbd,
list_entry->data;
if (entry) {
strcat(entry->anr,
ext_number);
ext_number);
}
}
}
@@ -610,8 +630,10 @@ static void pb_adn_sim_data_cb(const struct ofono_error *error,
file_info = cbd_outer->user;
cbd = cbd_outer->data;
if (!cbd)
if (!cbd) {
g_free(cbd_outer);
return;
}
pb = cbd->user;
cb = cbd->cb;
@@ -694,8 +716,10 @@ static void pb_adn_sim_data_cb(const struct ofono_error *error,
g_slist_free(phonebook_entry_start);
g_slist_free(pb_files);
g_free(cbd_outer);
void *pb = cbd->data;
g_free(cbd);
DBG("Finally all PB data read");
CALLBACK_WITH_SUCCESS(cb, cbd->data);
CALLBACK_WITH_SUCCESS(cb, pb);
return;
}
}
@@ -720,9 +744,6 @@ static void pb_adn_sim_info_cb(const struct ofono_error *error,
if (!cbd)
goto error;
pb = cbd->user;
cb = cbd->cb;
pbd = ofono_phonebook_get_data(pb);
file_info = NULL;
if (!pbd)
@@ -765,8 +786,12 @@ static void pb_adn_sim_info_cb(const struct ofono_error *error,
return;
error:
if (cb && cbd)
CALLBACK_WITH_FAILURE(cb, cbd->data);
if (cbd){
void *pb = cbd->data;
g_free(cbd);
if(cb)
CALLBACK_WITH_FAILURE(cb, pb);
}
}
static gboolean is_reading_required(uint8_t file_type)
@@ -799,9 +824,28 @@ static void pb_content_data_cb(const struct ofono_error *error,
if (extension_file_info)
file_info = decode_read_response(extension_file_info, sdata,
length, pb);
else
else {
/*
* These checks are crash hacks.
* AFAIK there's a possibility that we end up here and pb_next is NULL
* in case remove has been called while phonebook reading is in
* process. If you find better solution to this issue feel free to
* change this.
*/
if (pb_next == NULL) {
ofono_error("phonebook reading failed");
if (cbd){
void *pb = cbd->data;
g_free(cbd);
if(cb && pbd)
CALLBACK_WITH_FAILURE(cb, pb);
}
return;
}
file_info =
decode_read_response(pb_next->data, sdata, length, pb);
}
if (file_info) {
DBG("Reading extension file %04X, record %d, structure %d",
@@ -818,7 +862,7 @@ static void pb_content_data_cb(const struct ofono_error *error,
file_info = pb_next->data;
if (((file_info->structure ==
OFONO_SIM_FILE_STRUCTURE_FIXED) ||
OFONO_SIM_FILE_STRUCTURE_FIXED) ||
(file_info->structure ==
OFONO_SIM_FILE_STRUCTURE_CYCLIC))
&& (file_info->record <
@@ -855,7 +899,7 @@ static void pb_content_data_cb(const struct ofono_error *error,
DBG("All data requested, start vCard creation");
while (list_entry) {
struct phonebook_entry *entry =
list_entry->data;
list_entry->data;
if (entry) {
DBG("vCard:\nname=%s\n",
@@ -892,8 +936,10 @@ static void pb_content_data_cb(const struct ofono_error *error,
g_slist_free(phonebook_entry_start);
g_slist_free(pb_files);
void *pb = cbd->data;
g_free(cbd);
DBG("Finally all PB data read");
CALLBACK_WITH_SUCCESS(cb, cbd->data);
CALLBACK_WITH_SUCCESS(cb, pb);
return;
}
@@ -958,8 +1004,12 @@ static void pb_content_data_read(struct pb_data *pbd,
return;
error:
if (cb && cbd)
CALLBACK_WITH_FAILURE(cb, cbd->data);
if (cbd){
void *pb = cbd->data;
g_free(cbd);
if(cb)
CALLBACK_WITH_FAILURE(cb, pb);
}
out:
DBG("Exiting");
@@ -1032,9 +1082,11 @@ static void pb_content_info_cb(const struct ofono_error *error,
return;
error:
if (cb && cbd) {
DBG("Error cbd=%p, pbd=%p, file_info=%p", cbd, pbd, file_info);
CALLBACK_WITH_FAILURE(cb, cbd->data);
if (cbd){
void *pb = cbd->data;
g_free(cbd);
if(cb)
CALLBACK_WITH_FAILURE(cb, pb);
}
}
@@ -1107,15 +1159,27 @@ static void pb_reference_data_cb(const struct ofono_error *error,
pbd->pb_reference_file_info.record_length)) {
pbd->pb_reference_file_info.record++;
DBG("Next EFpbr record %d", pbd->pb_reference_file_info.record);
pbd->sim_driver->read_file_linear(get_sim(),
pbd->pb_reference_file_info.
file_id,
pbd->pb_reference_file_info.
record,
pbd->pb_reference_file_info.
record_length,
NULL, 0,
pb_reference_data_cb, cbd);
if (RIL_APPTYPE_SIM == ril_get_app_type()) {
pbd->sim_driver->read_file_linear(get_sim(),
pbd->pb_reference_file_info.
file_id,
pbd->pb_reference_file_info.
record,
pbd->pb_reference_file_info.
record_length,
sim_path, sizeof(sim_path),
pb_reference_data_cb, cbd);
} else {
pbd->sim_driver->read_file_linear(get_sim(),
pbd->pb_reference_file_info.
file_id,
pbd->pb_reference_file_info.
record,
pbd->pb_reference_file_info.
record_length,
usim_path, sizeof(usim_path),
pb_reference_data_cb, cbd);
}
} else {
struct pb_file_info *file_info;
DBG("All EFpbr records read");
@@ -1137,8 +1201,12 @@ static void pb_reference_data_cb(const struct ofono_error *error,
return;
error:
if (cb && cbd)
CALLBACK_WITH_FAILURE(cb, cbd->data);
if (cbd){
void *pb = cbd->data;
g_free(cbd);
if(cb)
CALLBACK_WITH_FAILURE(cb, pb);
}
}
static void pb_reference_info_cb(const struct ofono_error *error,
@@ -1189,8 +1257,12 @@ static void pb_reference_info_cb(const struct ofono_error *error,
pb_reference_data_cb, cbd);
return;
error:
if (cb && cbd)
CALLBACK_WITH_FAILURE(cb, cbd->data);
if (cbd){
void *pb = cbd->data;
g_free(cbd);
if(cb)
CALLBACK_WITH_FAILURE(cb, pb);
}
}
static void ril_export_entries(struct ofono_phonebook *pb,
@@ -1229,10 +1301,12 @@ static void ril_export_entries(struct ofono_phonebook *pb,
error:
if (cb && cbd)
CALLBACK_WITH_FAILURE(cb, cbd->data);
g_free(cbd);
if (cbd){
void *pb = cbd->data;
g_free(cbd);
if(cb)
CALLBACK_WITH_FAILURE(cb, pb);
}
}
static gboolean ril_delayed_register(gpointer user_data)
@@ -1280,7 +1354,7 @@ static struct ofono_phonebook_driver driver = {
.name = "rilmodem",
.probe = ril_phonebook_probe,
.remove = ril_phonebook_remove,
.export_entries = ril_export_entries
.export_entries = ril_export_entries
};
void ril_phonebook_init(void)

View File

@@ -35,6 +35,7 @@
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/radio-settings.h>
#include <ofono/sim.h>
#include "gril.h"
#include "grilutil.h"
@@ -74,7 +75,7 @@ static void ril_set_rat_mode(struct ofono_radio_settings *rs,
int pref = rd->ratmode;
int ret = 0;
ofono_info("setting rat mode");
ofono_info("rat mode set %d", mode);
parcel_init(&rilp);
@@ -115,6 +116,8 @@ static void ril_force_rat_mode(struct radio_data *rd, int pref)
if (pref == rd->ratmode)
return;
DBG("pref ril rat mode %d, ril current %d", pref, rd->ratmode);
parcel_init(&rilp);
parcel_w_int32(&rilp, 1);
parcel_w_int32(&rilp, rd->ratmode);
@@ -136,7 +139,7 @@ static void ril_rat_mode_cb(struct ril_msg *message, gpointer user_data)
if (message->error == RIL_E_SUCCESS) {
ril_util_init_parcel(message, &rilp);
/*first item in int[] is len so let's skip that*/
/* first item in int[] is len so let's skip that */
parcel_r_int32(&rilp);
pref = parcel_r_int32(&rilp);
@@ -166,6 +169,7 @@ static void ril_rat_mode_cb(struct ril_msg *message, gpointer user_data)
default:
break;
}
ofono_info("rat mode %d (ril %d)", mode, pref);
if (cb)
CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
} else {
@@ -200,11 +204,17 @@ static gboolean ril_get_net_config(struct radio_data *rsd)
{
GKeyFile *keyfile;
GError *err = NULL;
char *path = RIL_CONFIG;
char *config_path = RIL_CONFIG_DIR;
char **alreadyset = NULL;
gboolean needsconfig = FALSE;
gboolean value = FALSE;
gboolean found = FALSE;
rsd->ratmode = PREF_NET_TYPE_GSM_WCDMA_AUTO;
GDir *config_dir;
const gchar *config_file;
gsize length;
gchar **codes = NULL;
int i;
/*
* First we need to check should the LTE be on
@@ -215,15 +225,45 @@ static gboolean ril_get_net_config(struct radio_data *rsd)
g_key_file_set_list_separator(keyfile, ',');
if (g_key_file_load_from_file(keyfile, path, 0, &err)) {
config_dir = g_dir_open(config_path, 0, NULL);
while ((config_file = g_dir_read_name(config_dir)) != NULL) {
char *path = g_strconcat(RIL_CONFIG_DIR "/", config_file, NULL);
DBG("Rilconfig handling %s", path);
gboolean ok = g_key_file_load_from_file(keyfile, path, 0, &err);
g_free(path);
if (!ok) {
g_error_free(err);
DBG("Rilconfig file skipped");
continue;
}
if (g_key_file_has_group(keyfile, LTE_FLAG))
found = TRUE;
else if (g_key_file_has_group(keyfile, MCC_LIST)) {
codes = g_key_file_get_string_list(keyfile, MCC_LIST,
MCC_KEY, &length, NULL);
if (codes) {
for (i = 0; codes[i]; i++) {
if (g_str_equal(codes[i],
ofono_sim_get_mcc(get_sim()))
== TRUE) {
found = TRUE;
break;
}
}
g_strfreev(codes);
}
}
if (found) {
rsd->ratmode = PREF_NET_TYPE_LTE_GSM_WCDMA;
} else {
g_error_free(err);
needsconfig = TRUE;
break;
}
}
g_key_file_free(keyfile);
g_dir_close(config_dir);
/* Then we need to check if it already set */
@@ -250,6 +290,7 @@ static gboolean ril_get_net_config(struct radio_data *rsd)
storage_close(NULL, RIL_STORE, keyfile, TRUE);
DBG("needsconfig %d, rat mode %d", needsconfig, rsd->ratmode);
return needsconfig;
}

View File

@@ -53,8 +53,10 @@ static int rilmodem_init(void)
ril_ussd_init();
ril_call_settings_init();
ril_call_forwarding_init();
ril_call_barring_init();
ril_cbs_init();
ril_oemraw_init();
ril_stk_init();
return 0;
}
@@ -76,8 +78,10 @@ static void rilmodem_exit(void)
ril_ussd_exit();
ril_call_settings_exit();
ril_call_forwarding_exit();
ril_call_barring_exit();
ril_cbs_exit();
ril_oemraw_exit();
ril_stk_exit();
}
OFONO_PLUGIN_DEFINE(rilmodem, "RIL modem driver", VERSION,

View File

@@ -28,9 +28,14 @@
/* Shared constants */
#define EF_STATUS_INVALIDATED 0
#define EF_STATUS_VALID 1
#define RIL_CONFIG "/etc/ofono/ril_subscription.conf"
#define RIL_HW_CONFIG "/etc/ofono/ril_subscription.conf"
#define RIL_CONFIG_DIR "/etc/ofono/"
#define RIL_STORE "rilmodem"
#define LTE_FLAG "4gOn"
#define MCC_LIST "MCC-whitelist"
#define MCC_KEY "Countries"
#define UI_LANG "/var/lib/environment/nemo/locale.conf"
#define CFG_LANG "LANG="
extern void ril_devinfo_init(void);
extern void ril_devinfo_exit(void);
@@ -68,6 +73,9 @@ extern void ril_call_settings_exit(void);
extern void ril_call_forwarding_init(void);
extern void ril_call_forwarding_exit(void);
extern void ril_call_barring_init(void);
extern void ril_call_barring_exit(void);
extern void ril_cbs_init(void);
extern void ril_cbs_exit(void);
@@ -76,3 +84,7 @@ extern void ril_phonebook_exit(void);
extern void ril_oemraw_init(void);
extern void ril_oemraw_exit(void);
extern void ril_stk_init(void);
extern void ril_stk_exit(void);

View File

@@ -375,7 +375,14 @@ gboolean ril_util_parse_sim_status(GRil *gril,
* Do we just make a style-guide exception for PrintBuf operations?
*/
g_ril_append_print_buf(gril,
"(card_state=%d,universal_pin_state=%d,gsm_umts_index=%d,cdma_index=%d,ims_index=%d, ",
"card_state=%d,universal_pin_state=%d,gsm_umts_index=%d,cdma_index=%d,ims_index=%d, ",
status->card_state,
status->pin_state,
status->gsm_umts_index,
status->cdma_index,
status->ims_index);
DBG("card_state=%d, universal_pin_state=%d, gsm_umts_index=%d, cdma_index=%d, ims_index=%d",
status->card_state,
status->pin_state,
status->gsm_umts_index,
@@ -387,13 +394,13 @@ gboolean ril_util_parse_sim_status(GRil *gril,
else
goto done;
DBG("sim num_apps: %d", status->num_apps);
if (status->num_apps > MAX_UICC_APPS) {
ofono_error("SIM error; too many apps: %d", status->num_apps);
status->num_apps = MAX_UICC_APPS;
}
for (i = 0; i < status->num_apps; i++) {
DBG("processing app[%d]", i);
apps[i] = g_try_new0(struct sim_app, 1);
if (apps[i] == NULL) {
ofono_error("Can't allocate app_data");
@@ -402,13 +409,25 @@ gboolean ril_util_parse_sim_status(GRil *gril,
apps[i]->app_type = parcel_r_int32(&rilp);
apps[i]->app_state = parcel_r_int32(&rilp);
/*
* Consider RIL_APPSTATE_ILLEGAL also READY. Even if app state
* is RIL_APPSTATE_ILLEGAL (-1), ICC operations must be
* permitted. Network access requests will anyway be rejected
* and ME will be in limited service.
*/
if (apps[i]->app_state == RIL_APPSTATE_ILLEGAL) {
DBG("RIL_APPSTATE_ILLEGAL => RIL_APPSTATE_READY");
apps[i]->app_state = RIL_APPSTATE_READY;
}
apps[i]->perso_substate = parcel_r_int32(&rilp);
/* TODO: we need a way to instruct parcel to skip
* a string, without allocating memory...
*/
apps[i]->aid_str = parcel_r_string(&rilp); /* application ID (AID) */
apps[i]->app_str = parcel_r_string(&rilp); /* application label */
apps[i]->aid_str = parcel_r_string(&rilp); /* app ID (AID) */
apps[i]->app_str = parcel_r_string(&rilp); /* app label */
apps[i]->pin_replaced = parcel_r_int32(&rilp);
apps[i]->pin1_state = parcel_r_int32(&rilp);
@@ -425,6 +444,16 @@ gboolean ril_util_parse_sim_status(GRil *gril,
apps[i]->pin_replaced,
apps[i]->pin1_state,
apps[i]->pin2_state);
DBG("app[%d]: type=%d, state=%d, perso_substate=%d, aid_ptr=%s, app_label_ptr=%s, pin1_replaced=%d, pin1=%d, pin2=%d",
i, apps[i]->app_type,
apps[i]->app_state,
apps[i]->perso_substate,
apps[i]->aid_str,
apps[i]->app_str,
apps[i]->pin_replaced,
apps[i]->pin1_state,
apps[i]->pin2_state);
}
done:
@@ -459,7 +488,8 @@ gboolean ril_util_parse_reg(GRil *gril,
* >= 4 for VOICE_REG reply
* >= 5 for DATA_REG reply
*/
if ((tmp = parcel_r_int32(&rilp)) < 4) {
tmp = parcel_r_int32(&rilp);
if (tmp < 4) {
DBG("Size of response array is too small: %d", tmp);
goto error;
}
@@ -482,10 +512,12 @@ gboolean ril_util_parse_reg(GRil *gril,
* voice & data response.
*/
if (tmp--) {
sreason = parcel_r_string(&rilp); /* TODO: different use for CDMA */
/* TODO: different use for CDMA */
sreason = parcel_r_string(&rilp);
if (tmp--) {
smax = parcel_r_string(&rilp); /* TODO: different use for CDMA */
/* TODO: different use for CDMA */
smax = parcel_r_string(&rilp);
if (smax && max_calls)
*max_calls = atoi(smax);
@@ -518,7 +550,7 @@ gboolean ril_util_parse_reg(GRil *gril,
if (tech) {
if (stech) {
switch(atoi(stech)) {
switch (atoi(stech)) {
case RADIO_TECH_UNKNOWN:
*tech = -1;
break;
@@ -591,8 +623,10 @@ gint ril_util_parse_sms_response(GRil *gril, struct ril_msg *message)
*/
mr = parcel_r_int32(&rilp);
ack_pdu = parcel_r_string(&rilp);
error = parcel_r_int32(&rilp);
/* error: 3GPP 27.005, 3.2.5, -1 if unknown or not applicable */
error = parcel_r_int32(&rilp);
DBG("sms msg ref: %d, error: %d, ack_pdu: %s", mr, error, ack_pdu);
g_ril_append_print_buf(gril, "{%d,%s,%d}",
mr, ack_pdu, error);
@@ -659,7 +693,8 @@ gint ril_util_get_signal(GRil *gril, struct ril_msg *message)
return -1;
}
void ril_util_free_sim_apps(struct sim_app **apps, guint num_apps) {
void ril_util_free_sim_apps(struct sim_app **apps, guint num_apps)
{
guint i;
for (i = 0; i < num_apps; i++) {

View File

@@ -62,29 +62,6 @@ enum at_util_charset {
RIL_UTIL_CHARSET_8859_H = 0x10000,
};
/* TODO: consider moving these to ril_constants.h */
enum app_state {
APPSTATE_UNKNOWN,
APPSTATE_DETECTED,
APPSTATE_PIN,
APPSTATE_PUK,
APPSTATE_SUBSCRIPTION_PERSO,
APPSTATE_READY,
};
enum perso_state {
PERSOSUBSTATE_SIM_NETWORK = 3,
PERSOSUBSTATE_SIM_NETWORK_SUBSET,
PERSOSUBSTATE_SIM_CORPORATE,
PERSOSUBSTATE_SIM_SERVICE_PROVIDER,
PERSOSUBSTATE_SIM_SIM,
PERSOSUBSTATE_SIM_NETWORK_PUK,
PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK,
PERSOSUBSTATE_SIM_CORPORATE_PUK,
PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK,
PERSOSUBSTATE_SIM_SIM_PUK,
};
#define MAX_UICC_APPS 16
struct sim_status {
@@ -146,6 +123,12 @@ struct ofono_sim *get_sim();
gint check_if_really_roaming(gint status);
gboolean ril_roaming_allowed();
gboolean check_if_ok_to_attach();
gint get_current_network_status();
void ril_util_free_sim_apps(struct sim_app **apps, guint num_apps);
struct cb_data {
@@ -170,7 +153,7 @@ static inline struct cb_data *cb_data_new2(void *user, void *cb,
{
struct cb_data *ret;
ret = g_try_new0(struct cb_data, 1);
ret = g_new0(struct cb_data, 1);
if (ret) {
ret->cb = cb;
@@ -193,7 +176,7 @@ static inline int ril_util_convert_signal_strength(int strength)
return result;
}
#define DECLARE_FAILURE(e) \
#define DECLARE_FAILURE(e) \
struct ofono_error e; \
e.type = OFONO_ERROR_TYPE_FAILURE; \
e.error = 0 \

View File

@@ -4,6 +4,7 @@
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013 Canonical, Ltd. All rights reserved.
* Copyright (C) 2014 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -42,6 +43,7 @@
#include "util.h"
#include "gril.h"
#include "grilrequest.h"
#include "grilutil.h"
#include "parcel.h"
#include "ril_constants.h"
@@ -74,10 +76,6 @@
#define ENTER_SIM_PUK_PARAMS 3
#define CHANGE_SIM_PIN_PARAMS 3
/* RIL_FACILITY_LOCK parameters */
#define RIL_FACILITY_UNLOCK "0"
#define RIL_FACILITY_LOCK "1"
/* Current SIM */
static struct ofono_sim *current_sim;
/* Current active app */
@@ -100,12 +98,12 @@ struct sim_data {
guint app_type;
gchar *app_str;
guint app_index;
gboolean sim_registered;
enum ofono_sim_password_type passwd_type;
int retries[OFONO_SIM_PASSWORD_INVALID];
enum ofono_sim_password_type passwd_state;
guint card_state;
guint idle_id;
gboolean initialized;
gboolean removed;
};
static void ril_pin_change_state_cb(struct ril_msg *message,
@@ -129,7 +127,8 @@ static void set_path(struct sim_data *sd, struct parcel *rilp,
} else if (sd->app_type == RIL_APPTYPE_SIM) {
len = sim_ef_db_get_path_2g(fileid, db_path);
} else {
ofono_error("Unsupported app_type: 0%x", sd->app_type);
ofono_error("%s Unsupported app_type: 0%x", __func__,
sd->app_type);
}
if (len > 0) {
@@ -183,6 +182,15 @@ static void ril_file_info_cb(struct ril_msg *message, gpointer user_data)
DBG("");
/* In case sim card has been removed prior to this callback has been
* called we must not call the core call back method as otherwise the
* core will crash.
*/
if (sd->removed == TRUE) {
ofono_error("%s RIL_CARDSTATE_ABSENT", __func__);
return;
}
if (message->error == RIL_E_SUCCESS) {
decode_ril_error(&error, "OK");
} else {
@@ -197,14 +205,15 @@ static void ril_file_info_cb(struct ril_msg *message, gpointer user_data)
&sw1,
&sw2,
&response_len)) == NULL) {
ofono_error("Can't parse SIM IO response from RILD");
ofono_error("%s Can't parse SIM IO response", __func__);
decode_ril_error(&error, "FAIL");
goto error;
}
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
(sw1 == 0x90 && sw2 != 0x00)) {
ofono_error("invalid values: sw1: %02x sw2: %02x", sw1, sw2);
ofono_error("%s invalid values: sw1: %02x sw2: %02x", __func__,
sw1, sw2);
memset(&error, 0, sizeof(error));
/* TODO: fix decode_ril_error to take type & error */
@@ -217,15 +226,17 @@ static void ril_file_info_cb(struct ril_msg *message, gpointer user_data)
if (response_len) {
if (response[0] == 0x62) {
ok = sim_parse_3g_get_response(response, response_len,
&flen, &rlen, &str, access, NULL);
ok = sim_parse_3g_get_response(
response, response_len,
&flen, &rlen, &str, access, NULL);
} else
ok = sim_parse_2g_get_response(response, response_len,
&flen, &rlen, &str, access, &file_status);
ok = sim_parse_2g_get_response(
response, response_len,
&flen, &rlen, &str, access, &file_status);
}
if (!ok) {
ofono_error("parse response failed");
ofono_error("%s parse response failed", __func__);
decode_ril_error(&error, "FAIL");
goto error;
}
@@ -240,7 +251,8 @@ error:
}
static void ril_sim_read_info(struct ofono_sim *sim, int fileid,
const unsigned char *path, unsigned int path_len,
const unsigned char *path,
unsigned int path_len,
ofono_sim_file_info_cb_t cb,
void *data)
{
@@ -314,8 +326,8 @@ static void ril_file_io_cb(struct ril_msg *message, gpointer user_data)
if (message->error == RIL_E_SUCCESS) {
decode_ril_error(&error, "OK");
} else {
ofono_error("RILD reply failure: %s",
ril_error_to_string(message->error));
ofono_error("%s RILD reply failure: %s", __func__,
ril_error_to_string(message->error));
goto error;
}
@@ -325,7 +337,7 @@ static void ril_file_io_cb(struct ril_msg *message, gpointer user_data)
&sw1,
&sw2,
&response_len)) == NULL) {
ofono_error("Error parsing IO response");
ofono_error("%s Error parsing IO response", __func__);
goto error;
}
@@ -340,7 +352,8 @@ error:
static void ril_sim_read_binary(struct ofono_sim *sim, int fileid,
int start, int length,
const unsigned char *path, unsigned int path_len,
const unsigned char *path,
unsigned int path_len,
ofono_sim_read_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
@@ -393,7 +406,8 @@ static void ril_sim_read_binary(struct ofono_sim *sim, int fileid,
static void ril_sim_read_record(struct ofono_sim *sim, int fileid,
int record, int length,
const unsigned char *path, unsigned int path_len,
const unsigned char *path,
unsigned int path_len,
ofono_sim_read_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
@@ -457,7 +471,7 @@ static void ril_imsi_cb(struct ril_msg *message, gpointer user_data)
DBG("GET IMSI reply - OK");
decode_ril_error(&error, "OK");
} else {
ofono_error("Reply failure: %s",
ofono_error("%s Reply failure: %s", __func__,
ril_error_to_string(message->error));
decode_ril_error(&error, "FAIL");
cb(&error, NULL, cbd->data);
@@ -506,88 +520,58 @@ static void ril_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
}
}
void set_pin_lock_state(struct ofono_sim *sim,struct sim_app *app)
{
DBG("pin1:%u,pin2:%u",app->pin1_state,app->pin2_state);
/*
* Updates only pin and pin2 state. Other locks are not dealt here. For
* that a RIL_REQUEST_QUERY_FACILITY_LOCK request should be used.
*/
switch (app->pin1_state) {
case RIL_PINSTATE_ENABLED_NOT_VERIFIED:
case RIL_PINSTATE_ENABLED_VERIFIED:
case RIL_PINSTATE_ENABLED_BLOCKED:
case RIL_PINSTATE_ENABLED_PERM_BLOCKED:
ofono_set_pin_lock_state(sim,OFONO_SIM_PASSWORD_SIM_PIN,TRUE);
break;
case RIL_PINSTATE_DISABLED:
ofono_set_pin_lock_state(sim,OFONO_SIM_PASSWORD_SIM_PIN,FALSE);
break;
default:
break;
}
switch (app->pin2_state) {
case RIL_PINSTATE_ENABLED_NOT_VERIFIED:
case RIL_PINSTATE_ENABLED_VERIFIED:
case RIL_PINSTATE_ENABLED_BLOCKED:
case RIL_PINSTATE_ENABLED_PERM_BLOCKED:
ofono_set_pin_lock_state(sim,OFONO_SIM_PASSWORD_SIM_PIN2,TRUE);
break;
case RIL_PINSTATE_DISABLED:
ofono_set_pin_lock_state(sim,OFONO_SIM_PASSWORD_SIM_PIN2,FALSE);
break;
default:
break;
}
}
static void configure_active_app(struct sim_data *sd,
struct sim_app *app,
guint index)
{
sd->app_type = app->app_type;
g_free(sd->aid_str);
sd->aid_str = g_strdup(app->aid_str);
g_free(sd->app_str);
sd->app_str = g_strdup(app->app_str);
sd->app_index = index;
DBG("setting aid_str (AID) to: %s", sd->aid_str);
switch (app->app_state) {
case APPSTATE_PIN:
case RIL_APPSTATE_PIN:
sd->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
break;
case APPSTATE_PUK:
case RIL_APPSTATE_PUK:
sd->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
break;
case APPSTATE_SUBSCRIPTION_PERSO:
case RIL_APPSTATE_SUBSCRIPTION_PERSO:
switch (app->perso_substate) {
case PERSOSUBSTATE_SIM_NETWORK:
case RIL_PERSOSUBSTATE_SIM_NETWORK:
sd->passwd_state = OFONO_SIM_PASSWORD_PHNET_PIN;
break;
case PERSOSUBSTATE_SIM_NETWORK_SUBSET:
case RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET:
sd->passwd_state = OFONO_SIM_PASSWORD_PHNETSUB_PIN;
break;
case PERSOSUBSTATE_SIM_CORPORATE:
case RIL_PERSOSUBSTATE_SIM_CORPORATE:
sd->passwd_state = OFONO_SIM_PASSWORD_PHCORP_PIN;
break;
case PERSOSUBSTATE_SIM_SERVICE_PROVIDER:
case RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER:
sd->passwd_state = OFONO_SIM_PASSWORD_PHSP_PIN;
break;
case PERSOSUBSTATE_SIM_SIM:
case RIL_PERSOSUBSTATE_SIM_SIM:
sd->passwd_state = OFONO_SIM_PASSWORD_PHSIM_PIN;
break;
case PERSOSUBSTATE_SIM_NETWORK_PUK:
case RIL_PERSOSUBSTATE_SIM_NETWORK_PUK:
sd->passwd_state = OFONO_SIM_PASSWORD_PHNET_PUK;
break;
case PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK:
case RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK:
sd->passwd_state = OFONO_SIM_PASSWORD_PHNETSUB_PUK;
break;
case PERSOSUBSTATE_SIM_CORPORATE_PUK:
case RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK:
sd->passwd_state = OFONO_SIM_PASSWORD_PHCORP_PUK;
break;
case PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK:
case RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK:
sd->passwd_state = OFONO_SIM_PASSWORD_PHSP_PUK;
break;
case PERSOSUBSTATE_SIM_SIM_PUK:
case RIL_PERSOSUBSTATE_SIM_SIM_PUK:
sd->passwd_state = OFONO_SIM_PASSWORD_PHFSIM_PUK;
break;
default:
@@ -595,54 +579,124 @@ static void configure_active_app(struct sim_data *sd,
break;
};
break;
case APPSTATE_READY:
case RIL_APPSTATE_READY:
sd->passwd_state = OFONO_SIM_PASSWORD_NONE;
break;
case APPSTATE_UNKNOWN:
case APPSTATE_DETECTED:
case RIL_APPSTATE_UNKNOWN:
case RIL_APPSTATE_DETECTED:
default:
sd->passwd_state = OFONO_SIM_PASSWORD_INVALID;
break;
}
}
static void free_sim_state(struct sim_data *sd)
{
guint i = 0;
sd->passwd_state = OFONO_SIM_PASSWORD_INVALID;
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
sd->retries[i] = -1;
sd->removed = TRUE;
sd->initialized = FALSE;
}
static void sim_send_set_uicc_subscription(struct sim_data *sd, int slot_id,
int app_index, int sub_id, int sub_status)
{
struct parcel rilp;
DBG("");
g_ril_request_set_uicc_subscription(sd->ril, slot_id, app_index,
sub_id, sub_status, &rilp);
g_ril_send(sd->ril, RIL_REQUEST_SET_UICC_SUBSCRIPTION, rilp.data,
rilp.size, NULL, NULL, NULL);
}
static int sim_select_uicc_subscription(struct sim_data *sim,
struct sim_status *status, struct sim_app **apps)
{
int slot_id = 0;
int selected_app = -1;
unsigned int i;
for (i = 0; i < status->num_apps; i++) {
switch (apps[i]->app_type) {
case RIL_APPTYPE_UNKNOWN:
continue;
case RIL_APPTYPE_USIM:
case RIL_APPTYPE_RUIM:
if (selected_app != -1) {
switch (apps[selected_app]->app_type) {
case RIL_APPTYPE_USIM:
case RIL_APPTYPE_RUIM:
break;
default:
selected_app = i;
}
} else {
selected_app = i;
}
break;
default:
if (selected_app == -1)
selected_app = i;
}
}
DBG("Select app %d for subscription.", selected_app);
if (selected_app != -1)
/* Number 1 means activates that app */
sim_send_set_uicc_subscription(sim, slot_id, selected_app,
slot_id, 1);
return selected_app;
}
static void sim_status_cb(struct ril_msg *message, gpointer user_data)
{
struct ofono_sim *sim = user_data;
struct sim_data *sd = ofono_sim_get_data(sim);
struct sim_app *apps[MAX_UICC_APPS];
struct sim_status status;
guint i = 0;
guint search_index = -1;
struct parcel rilp;
DBG("");
if (ril_util_parse_sim_status(sd->ril, message, &status, apps) &&
if (ril_util_parse_sim_status(sd->ril, message, &status, apps) &&
status.num_apps) {
DBG("num_apps: %d gsm_umts_index: %d", status.num_apps,
status.gsm_umts_index);
/* TODO(CDMA): need some kind of logic to
* set the correct app_index,
*/
search_index = status.gsm_umts_index;
int app_index = status.gsm_umts_index;
for (i = 0; i < status.num_apps; i++) {
if (i == search_index &&
apps[i]->app_type != RIL_APPTYPE_UNKNOWN) {
current_active_app = apps[i]->app_type;
configure_active_app(sd, apps[i], i);
set_pin_lock_state(sim, apps[i]);
break;
}
if (app_index < 0) {
app_index = sim_select_uicc_subscription(sd,
&status, apps);
}
if (app_index >= 0 && app_index < (int)status.num_apps &&
apps[app_index]->app_type != RIL_APPTYPE_UNKNOWN) {
current_active_app = apps[app_index]->app_type;
configure_active_app(sd, apps[app_index], app_index);
}
if (sd->sim_registered == FALSE) {
ofono_sim_register(sim);
sd->sim_registered = TRUE;
} else
sd->removed = FALSE;
if (sd->passwd_state != OFONO_SIM_PASSWORD_INVALID) {
/*
* ril_util_parse_sim_status returns true only when
* card status is RIL_CARDSTATE_PRESENT,
* ofono_sim_inserted_notify returns if status doesn't
* change. So can notify core always in this branch.
*/
ofono_sim_inserted_notify(sim, TRUE);
/* TODO: There doesn't seem to be any other
* way to force the core SIM code to
* recheck the PIN.
@@ -650,46 +704,16 @@ static void sim_status_cb(struct ril_msg *message, gpointer user_data)
* more appropriate call here??
* __ofono_sim_refresh(sim, NULL, TRUE, TRUE);
*/
DBG("sd->card_state:%u",sd->card_state);
if (sd->card_state != RIL_CARDSTATE_PRESENT) {
ofono_sim_inserted_notify(sim, TRUE);
sd->card_state = RIL_CARDSTATE_PRESENT;
}
if (current_passwd) {
if (!strcmp(current_passwd, defaultpasswd)) {
__ofono_sim_recheck_pin(sim);
} else if (sd->passwd_state !=
OFONO_SIM_PASSWORD_SIM_PIN) {
__ofono_sim_recheck_pin(sim);
} else if (sd->passwd_state ==
OFONO_SIM_PASSWORD_SIM_PIN) {
parcel_init(&rilp);
parcel_w_int32(&rilp,
ENTER_SIM_PIN_PARAMS);
parcel_w_string(&rilp, current_passwd);
parcel_w_string(&rilp, sd->aid_str);
g_ril_send(sd->ril,
RIL_REQUEST_ENTER_SIM_PIN,
rilp.data, rilp.size, NULL,
NULL, g_free);
parcel_free(&rilp);
}
} else {
__ofono_sim_recheck_pin(sim);
}
if (current_online_state == RIL_ONLINE_PREF) {
parcel_init(&rilp);
parcel_init(&rilp);
parcel_w_int32(&rilp, 1);
parcel_w_int32(&rilp, 1);
ofono_info("RIL_REQUEST_RADIO_POWER ON");
g_ril_send(sd->ril,
RIL_REQUEST_RADIO_POWER,
rilp.data,
@@ -707,17 +731,13 @@ static void sim_status_cb(struct ril_msg *message, gpointer user_data)
current_online_state = RIL_ONLINE_PREF;
if (status.card_state == RIL_CARDSTATE_ABSENT) {
DBG("sd->card_state:%u,status.card_state:%u,",
sd->card_state, status.card_state);
ofono_sim_inserted_notify(sim, FALSE);
sd->card_state = RIL_CARDSTATE_ABSENT;
ofono_info("%s: RIL_CARDSTATE_ABSENT", __func__);
if (current_passwd)
g_stpcpy(current_passwd, defaultpasswd);
free_sim_state(sd);
ofono_sim_inserted_notify(sim, FALSE);
}
}
/* TODO: if no SIM present, handle emergency calling. */
}
static int send_get_sim_status(struct ofono_sim *sim)
@@ -754,16 +774,73 @@ static void ril_query_pin_retries(struct ofono_sim *sim,
CALLBACK_WITH_SUCCESS(cb, sd->retries, data);
}
static void ril_query_passwd_state_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
struct ofono_sim *sim = cbd->user;
struct sim_data *sd = ofono_sim_get_data(sim);
ofono_sim_passwd_cb_t cb = cbd->cb;
void *data = cbd->data;
struct sim_app *apps[MAX_UICC_APPS];
struct sim_status status;
gint state = ofono_sim_get_state(sim);
if (ril_util_parse_sim_status(sd->ril, message, &status, apps) &&
status.num_apps) {
/* TODO(CDMA): need some kind of logic to
* set the correct app_index,
*/
int app_index = status.gsm_umts_index;
if (app_index >= 0 && app_index < (int)status.num_apps &&
apps[app_index]->app_type != RIL_APPTYPE_UNKNOWN) {
current_active_app = apps[app_index]->app_type;
configure_active_app(sd, apps[app_index], app_index);
}
ril_util_free_sim_apps(apps, status.num_apps);
}
DBG("passwd_state %u", sd->passwd_state);
/* if pin code required cannot be initialized yet*/
if (sd->passwd_state == OFONO_SIM_PASSWORD_SIM_PIN)
sd->initialized = FALSE;
/*
* To prevent double call to sim_initialize_after_pin from
* sim_pin_query_cb we must prevent calling sim_pin_query_cb
* when !OFONO_SIM_STATE_READY && OFONO_SIM_PASSWORD_NONE
*/
if ((state == OFONO_SIM_STATE_READY) || (sd->initialized == FALSE) ||
(sd->passwd_state != OFONO_SIM_PASSWORD_NONE)){
if (sd->passwd_state == OFONO_SIM_PASSWORD_NONE)
sd->initialized = TRUE;
if (state == OFONO_SIM_STATE_LOCKED_OUT)
sd->initialized = FALSE;
if (sd->passwd_state == OFONO_SIM_PASSWORD_INVALID)
CALLBACK_WITH_FAILURE(cb, -1, data);
else
CALLBACK_WITH_SUCCESS(cb, sd->passwd_state, data);
}
}
static void ril_query_passwd_state(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
DBG("passwd_state %u", sd->passwd_state);
struct cb_data *cbd = cb_data_new2(sim, cb, data);
int request = RIL_REQUEST_GET_SIM_STATUS;
guint ret;
ret = g_ril_send(sd->ril, request,
NULL, 0, ril_query_passwd_state_cb, cbd, g_free);
g_ril_print_request_no_args(sd->ril, ret, request);
if (sd->passwd_state == OFONO_SIM_PASSWORD_INVALID)
CALLBACK_WITH_FAILURE(cb, -1, data);
else
CALLBACK_WITH_SUCCESS(cb, sd->passwd_state, data);
}
static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
@@ -773,8 +850,9 @@ static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
struct sim_data *sd = cbd->user;
struct parcel rilp;
int retry_count;
int retries[OFONO_SIM_PASSWORD_INVALID];
int passwd_type;
int i;
/* There is no reason to ask SIM status until
* unsolicited sim status change indication
* Looks like state does not change before that.
@@ -784,18 +862,19 @@ static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
ril_util_init_parcel(message, &rilp);
parcel_r_int32(&rilp);
retry_count = parcel_r_int32(&rilp);
retries[passwd_type] = retry_count;
sd->retries[passwd_type] = retries[passwd_type];
/* TODO: re-bfactor to not use macro for FAILURE; doesn't return error! */
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
sd->retries[i] = -1;
sd->retries[passwd_type] = retry_count;
DBG("result=%d passwd_type=%d retry_count=%d",
message->error, passwd_type, retry_count);
if (message->error == RIL_E_SUCCESS) {
CALLBACK_WITH_SUCCESS(cb, cbd->data);
g_ril_print_response_no_args(sd->ril, message);
} else {
if (current_passwd)
g_stpcpy(current_passwd, defaultpasswd);
CALLBACK_WITH_FAILURE(cb, cbd->data);
}
@@ -813,9 +892,6 @@ static void ril_pin_send(struct ofono_sim *sim, const char *passwd,
sd->passwd_type = OFONO_SIM_PASSWORD_SIM_PIN;
cbd->user = sd;
if (current_passwd)
g_stpcpy(current_passwd, passwd);
parcel_init(&rilp);
parcel_w_int32(&rilp, ENTER_SIM_PIN_PARAMS);
@@ -837,11 +913,53 @@ static void ril_pin_send(struct ofono_sim *sim, const char *passwd,
}
}
static void ril_pin_change_state(struct ofono_sim *sim,
enum ofono_sim_password_type passwd_type,
int enable, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
static int ril_perso_change_state(struct ofono_sim *sim,
enum ofono_sim_password_type passwd_type,
int enable, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
struct parcel rilp;
int request = 0;
int ret = 0;
sd->passwd_type = passwd_type;
cbd->user = sd;
parcel_init(&rilp);
switch (passwd_type) {
case OFONO_SIM_PASSWORD_PHNET_PIN:
if (enable) {
DBG("Not supported, enable=%d", enable);
goto end;
}
request = RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION;
parcel_w_int32(&rilp, RIL_PERSOSUBSTATE_SIM_NETWORK);
parcel_w_string(&rilp, (char *) passwd);
break;
default:
DBG("Not supported, type=%d", passwd_type);
goto end;
}
ret = g_ril_send(sd->ril, request,
rilp.data, rilp.size, ril_pin_change_state_cb,
cbd, g_free);
g_ril_print_request(sd->ril, ret, request);
end:
parcel_free(&rilp);
return ret;
}
static void ril_pin_change_state(struct ofono_sim *sim,
enum ofono_sim_password_type passwd_type,
int enable, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
DBG("passwd_type=%d", passwd_type);
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
struct parcel rilp;
@@ -861,8 +979,6 @@ static void ril_pin_change_state(struct ofono_sim *sim,
*/
switch (passwd_type) {
case OFONO_SIM_PASSWORD_SIM_PIN:
if (current_passwd)
g_stpcpy(current_passwd, passwd);
g_ril_append_print_buf(sd->ril, "(SC,");
parcel_w_string(&rilp, "SC");
break;
@@ -879,9 +995,9 @@ static void ril_pin_change_state(struct ofono_sim *sim,
parcel_w_string(&rilp, "P2");
break;
case OFONO_SIM_PASSWORD_PHNET_PIN:
g_ril_append_print_buf(sd->ril, "(PN,");
parcel_w_string(&rilp, "PN");
break;
ret = ril_perso_change_state(sim, passwd_type, enable, passwd,
cb, data);
goto end;
case OFONO_SIM_PASSWORD_PHNETSUB_PIN:
g_ril_append_print_buf(sd->ril, "(PU,");
parcel_w_string(&rilp, "PU");
@@ -895,8 +1011,7 @@ static void ril_pin_change_state(struct ofono_sim *sim,
parcel_w_string(&rilp, "PC");
break;
default:
CALLBACK_WITH_FAILURE(cb, data);
return;
goto end;
}
if (enable)
@@ -923,6 +1038,7 @@ static void ril_pin_change_state(struct ofono_sim *sim,
g_ril_print_request(sd->ril, ret, request);
end:
parcel_free(&rilp);
if (ret <= 0) {
@@ -944,9 +1060,6 @@ static void ril_pin_send_puk(struct ofono_sim *sim,
sd->passwd_type = OFONO_SIM_PASSWORD_SIM_PUK;
cbd->user = sd;
if (current_passwd)
g_stpcpy(current_passwd, passwd);
parcel_init(&rilp);
parcel_w_int32(&rilp, ENTER_SIM_PUK_PARAMS);
@@ -995,8 +1108,6 @@ static void ril_change_passwd(struct ofono_sim *sim,
if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
request = RIL_REQUEST_CHANGE_SIM_PIN2;
else if (current_passwd)
g_stpcpy(current_passwd, new_passwd);
ret = g_ril_send(sd->ril, request, rilp.data, rilp.size,
ril_pin_change_state_cb, cbd, g_free);
@@ -1022,15 +1133,14 @@ static gboolean ril_sim_register(gpointer user)
DBG("");
sd->idle_id = 0;
ofono_sim_register(sim);
send_get_sim_status(sim);
g_ril_register(sd->ril, RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
sd->idle_id = 0;
g_ril_register(sd->ril,
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
(GRilNotifyFunc) ril_sim_status_changed, sim);
/* TODO: should we also register for RIL_UNSOL_SIM_REFRESH? */
return FALSE;
}
@@ -1045,13 +1155,6 @@ static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
sd = g_new0(struct sim_data, 1);
sd->ril = g_ril_clone(ril);
sd->aid_str = NULL;
sd->app_str = NULL;
sd->app_type = RIL_APPTYPE_UNKNOWN;
sd->passwd_state = OFONO_SIM_PASSWORD_NONE;
sd->passwd_type = OFONO_SIM_PASSWORD_NONE;
sd->sim_registered = FALSE;
sd->card_state = RIL_CARDSTATE_ABSENT;
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
sd->retries[i] = -1;
@@ -1078,13 +1181,18 @@ static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
static void ril_sim_remove(struct ofono_sim *sim)
{
DBG("");
struct sim_data *sd = ofono_sim_get_data(sim);
ofono_sim_set_data(sim, NULL);
if (sd->idle_id > 0)
if (sd->idle_id > 0) {
g_source_remove(sd->idle_id);
sd->idle_id = 0;
}
g_free(sd->aid_str);
g_free(sd->app_str);
g_ril_unref(sd->ril);
g_free(sd);
}
@@ -1105,17 +1213,6 @@ static struct ofono_sim_driver driver = {
.change_passwd = ril_change_passwd,
.query_pin_retries = ril_query_pin_retries,
/*
* TODO: Implmenting PIN/PUK support requires defining
* the following driver methods.
*
* In the meanwhile, as long as the SIM card is present,
* and unlocked, the core SIM code will check for the
* presence of query_passwd_state, and if null, then the
* function sim_initialize_after_pin() is called.
*
* .query_pin_retries = ril_pin_retries_query,
* .query_locked = ril_pin_query_enabled,
*
* TODO: Implementing SIM write file IO support requires
* the following functions to be defined.
*

View File

@@ -38,10 +38,18 @@
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/sms.h>
#include <ofono/types.h>
#include <ofono/sim.h>
#include "smsutil.h"
#include "util.h"
#include "rilmodem.h"
#include "simutil.h"
#define SIM_EFSMS_FILEID 0x6F3C
#define EFSMS_LENGTH 176
unsigned char path[4] = {0x3F, 0x00, 0x7F, 0x10};
struct sms_data {
GRil *ril;
@@ -131,7 +139,7 @@ static void ril_csca_query_cb(struct ril_msg *message, gpointer user_data)
sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
DBG("csca_query_cb: %s, %d", sca.number, sca.type);
g_free(temp_buf); /*g_utf16_to_utf8 used by parcel_r_string*/
cb(&error, &sca, cbd->data);
} else {
ofono_error("return value invalid");
@@ -168,10 +176,14 @@ static void submit_sms_cb(struct ril_msg *message, gpointer user_data)
int mr;
if (message->error == RIL_E_SUCCESS) {
ofono_info("sms sending succesful");
ofono_info("sms sending successful");
decode_ril_error(&error, "OK");
} else if (message->error == RIL_E_GENERIC_FAILURE) {
ofono_info("not allowed by MO SMS control, do not retry");
error.type = OFONO_ERROR_TYPE_CMS;
error.error = 500;
} else {
ofono_error("sms sending failed");
ofono_error("sms sending failed, retry");
decode_ril_error(&error, "FAIL");
}
@@ -230,6 +242,8 @@ static void ril_cmgs(struct ofono_sms *sms, const unsigned char *pdu,
submit_sms_cb, cbd, g_free);
g_ril_append_print_buf(sd->ril, "(%s)", tpdu);
g_free(tpdu);
tpdu = NULL;
g_ril_print_request(sd->ril, ret, request);
parcel_free(&rilp);
@@ -248,19 +262,21 @@ static void ril_ack_delivery_cb(struct ril_msg *message, gpointer user_data)
"SMS acknowledgement failed: Further SMS reception is not guaranteed");
}
static void ril_ack_delivery(struct ofono_sms *sms)
static void ril_ack_delivery(struct ofono_sms *sms, int error)
{
struct sms_data *sd = ofono_sms_get_data(sms);
struct parcel rilp;
int ret;
int request = RIL_REQUEST_SMS_ACKNOWLEDGE;
int code = 0;
if (!error)
code = 0xFF;
parcel_init(&rilp);
parcel_w_int32(&rilp, 2); /* Number of int32 values in array */
parcel_w_int32(&rilp, 1); /* Successful receipt */
parcel_w_int32(&rilp, 0); /* error code */
/* TODO: should ACK be sent for either of the error cases? */
parcel_w_int32(&rilp, error); /* Successful (1)/Failed (0) receipt */
parcel_w_int32(&rilp, code); /* error code */
/* ACK the incoming NEW_SMS */
ret = g_ril_send(sd->ril, request,
@@ -285,6 +301,9 @@ static void ril_sms_notify(struct ril_msg *message, gpointer user_data)
long ril_buf_len;
guchar *ril_data;
ril_pdu = NULL;
ril_data = NULL;
DBG("req: %d; data_len: %d", message->req, message->buf_len);
switch (message->req) {
@@ -317,6 +336,8 @@ static void ril_sms_notify(struct ril_msg *message, gpointer user_data)
ofono_info("sms received, smsc_len is %d", smsc_len);
g_ril_append_print_buf(sd->ril, "(%s)", ril_pdu);
g_free(ril_pdu);
ril_pdu = NULL;
g_ril_print_unsol(sd->ril, message);
if (message->req == RIL_UNSOL_RESPONSE_NEW_SMS) {
@@ -329,14 +350,116 @@ static void ril_sms_notify(struct ril_msg *message, gpointer user_data)
ril_buf_len - smsc_len);
}
ril_ack_delivery(sms);
g_free(ril_data);
ril_data = NULL;
ril_ack_delivery(sms, TRUE);
return;
error:
g_free(ril_pdu);
ril_pdu = NULL;
g_free(ril_data);
ril_data = NULL;
ril_ack_delivery(sms, FALSE);
ofono_error("Unable to parse NEW_SMS notification");
}
static void ril_new_sms_on_sim_cb(struct ril_msg *message, gpointer user_data)
{
DBG("");
if (message->error == RIL_E_SUCCESS)
ofono_info("sms deleted from sim");
else
ofono_error("deleting sms from sim failed");
}
static void ril_request_delete_sms_om_sim(struct ofono_sms *sms,int record)
{
struct sms_data *data = ofono_sms_get_data(sms);
struct parcel rilp;
int request = RIL_REQUEST_DELETE_SMS_ON_SIM;
int ret;
DBG("Deleting record: %d", record);
parcel_init(&rilp);
parcel_w_int32(&rilp, 1); /* Number of int32 values in array */
parcel_w_int32(&rilp, record);
ret = g_ril_send(data->ril, request, rilp.data,
rilp.size, ril_new_sms_on_sim_cb, NULL, NULL);
parcel_free(&rilp);
if (ret <= 0)
ofono_error("cannot delete sms from sim");
}
static void ril_read_sms_on_sim_cb(const struct ofono_error *error,
const unsigned char *sdata,
int length, void *data)
{
struct cb_data *cbd = data;
struct ofono_sms *sms = cbd->user;
int record;
unsigned int smsc_len;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
ofono_error("cannot read sms from sim");
goto exit;
}
/*
* It seems when reading EFsms RIL returns the whole record including
* the first status byte therefore we ignore that as we are only
* interested of the following pdu
*/
/* The first octect in the pdu contains the SMSC address length
* which is the X following octects it reads. We add 1 octet to
* the read length to take into account this read octet in order
* to calculate the proper tpdu length.
*/
smsc_len = sdata[1] + 1;
ofono_sms_deliver_notify(sms, sdata + 1, length - 1,
length - smsc_len - 1);
record = (int)cbd->data;
ril_request_delete_sms_om_sim(sms,record);
exit:
g_free(cbd);
}
static void ril_new_sms_on_sim(struct ril_msg *message, gpointer user_data)
{
struct ofono_sms *sms = user_data;
struct parcel rilp;
int record;
ofono_info("new sms on sim");
ril_util_init_parcel(message, &rilp);
/* data length of the response */
record = parcel_r_int32(&rilp);
if (record > 0) {
record = parcel_r_int32(&rilp);
struct cb_data *cbd = cb_data_new2(sms, NULL, (void*)record);
DBG(":%d", record);
get_sim_driver()->read_file_linear(get_sim(), SIM_EFSMS_FILEID,
record, EFSMS_LENGTH, path,
sizeof(path),
ril_read_sms_on_sim_cb, cbd);
}
}
static gboolean ril_delayed_register(gpointer user_data)
{
struct ofono_sms *sms = user_data;
@@ -352,6 +475,8 @@ static gboolean ril_delayed_register(gpointer user_data)
ril_sms_notify, sms);
g_ril_register(data->ril, RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
ril_sms_notify, sms);
g_ril_register(data->ril, RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM,
ril_new_sms_on_sim, sms);
/* This makes the timeout a single-shot */
return FALSE;

View File

@@ -0,0 +1,342 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2014 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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <glib.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/stk.h>
#include "gril.h"
#include "util.h"
#include "rilmodem.h"
#include "ril_constants.h"
struct stk_data {
GRil *ril;
};
gboolean subscribed;
static void ril_envelope_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_stk_envelope_cb_t cb = cbd->cb;
struct ofono_error error;
DBG("");
if (message->error == RIL_E_SUCCESS) {
decode_ril_error(&error, "OK");
} else {
DBG("Envelope reply failure: %s",
ril_error_to_string(message->error));
decode_ril_error(&error, "FAIL");
}
cb(&error, NULL, 0, cbd->data);
}
static void ril_stk_envelope(struct ofono_stk *stk, int length,
const unsigned char *command,
ofono_stk_envelope_cb_t cb, void *data)
{
struct stk_data *sd = ofono_stk_get_data(stk);
struct cb_data *cbd = cb_data_new(cb, data);
struct parcel rilp;
char *hex_envelope = NULL;
int request = RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND;
guint ret;
DBG("");
hex_envelope = encode_hex(command, length, 0);
DBG("rilmodem envelope: %s", hex_envelope);
parcel_init(&rilp);
parcel_w_string(&rilp, hex_envelope);
g_free(hex_envelope);
hex_envelope = NULL;
ret = g_ril_send(sd->ril, request,
rilp.data, rilp.size, ril_envelope_cb,
cbd, g_free);
parcel_free(&rilp);
if (ret <= 0) {
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, NULL, -1, data);
}
}
static void ril_tr_cb(struct ril_msg *message, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_stk_generic_cb_t cb = cbd->cb;
struct ofono_error error;
DBG("");
if (message->error == RIL_E_SUCCESS) {
decode_ril_error(&error, "OK");
} else {
DBG("Error in sending terminal response");
ofono_error("Error in sending terminal response");
decode_ril_error(&error, "FAIL");
}
cb(&error, cbd->data);
}
static void ril_stk_terminal_response(struct ofono_stk *stk, int length,
const unsigned char *resp,
ofono_stk_generic_cb_t cb, void *data)
{
struct stk_data *sd = ofono_stk_get_data(stk);
struct cb_data *cbd = cb_data_new(cb, data);
struct parcel rilp;
char *hex_tr = NULL;
int request = RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE;
guint ret;
DBG("");
hex_tr = encode_hex(resp, length, 0);
DBG("rilmodem terminal response: %s", hex_tr);
parcel_init(&rilp);
parcel_w_string(&rilp, hex_tr);
g_free(hex_tr);
hex_tr = NULL;
ret = g_ril_send(sd->ril, request,
rilp.data, rilp.size, ril_tr_cb,
cbd, g_free);
parcel_free(&rilp);
if (ret <= 0) {
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
}
static void ril_stk_user_confirmation(struct ofono_stk *stk,
ofono_bool_t confirm)
{
struct stk_data *sd = ofono_stk_get_data(stk);
struct parcel rilp;
int request = RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM;
int ret;
DBG("");
/* Only pcmd needing user confirmation is call set up
* RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM
*/
parcel_init(&rilp);
parcel_w_int32(&rilp, 1); /* size of array */
parcel_w_int32(&rilp, confirm); /* yes/no */
/* fire and forget i.e. not waiting for the callback*/
ret = g_ril_send(sd->ril, request, rilp.data,
rilp.size, NULL, NULL, NULL);
g_ril_print_request_no_args(sd->ril, ret, request);
parcel_free(&rilp);
}
static void ril_stk_pcmd_notify(struct ril_msg *message, gpointer user_data)
{
struct ofono_stk *stk = user_data;
struct parcel rilp;
char *pcmd = NULL;
guchar *pdu = NULL;
long len;
DBG("");
ril_util_init_parcel(message, &rilp);
pcmd = parcel_r_string(&rilp);
DBG("pcmd: %s", pcmd);
pdu = decode_hex((const char *) pcmd,
strlen(pcmd),
&len, -1);
g_free(pcmd);
ofono_stk_proactive_command_notify(stk, len, (const guchar *)pdu);
g_free(pdu);
}
static void ril_stk_event_notify(struct ril_msg *message, gpointer user_data)
{
struct ofono_stk *stk = user_data;
struct parcel rilp;
char *pcmd = NULL;
guchar *pdu = NULL;
long len;
DBG("");
/* Proactive command has been handled by the modem. */
ril_util_init_parcel(message, &rilp);
pcmd = parcel_r_string(&rilp);
DBG("pcmd: %s", pcmd);
pdu = decode_hex((const char *) pcmd,
strlen(pcmd),
&len, -1);
g_free(pcmd);
pcmd = NULL;
ofono_stk_proactive_command_handled_notify(stk, len,
(const guchar *)pdu);
g_free(pdu);
}
static void ril_stk_session_end_notify(struct ril_msg *message,
gpointer user_data)
{
struct ofono_stk *stk = user_data;
DBG("");
ofono_stk_proactive_session_end_notify(stk);
}
static void ril_stk_agent_ready(struct ofono_stk *stk)
{
struct stk_data *sd = ofono_stk_get_data(stk);
int request = RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING;
int ret;
DBG("");
if (!subscribed) {
DBG("Subscribing notifications");
g_ril_register(sd->ril, RIL_UNSOL_STK_PROACTIVE_COMMAND,
ril_stk_pcmd_notify, stk);
g_ril_register(sd->ril, RIL_UNSOL_STK_SESSION_END,
ril_stk_session_end_notify, stk);
g_ril_register(sd->ril, RIL_UNSOL_STK_EVENT_NOTIFY,
ril_stk_event_notify, stk);
subscribed = TRUE;
}
/* fire and forget i.e. not waiting for the callback*/
ret = g_ril_send(sd->ril, request, NULL, 0,
NULL, NULL, NULL);
g_ril_print_request_no_args(sd->ril, ret, request);
}
void ril_stk_set_lang()
{
gchar *contents;
GError *err = NULL;
if (!g_file_get_contents(UI_LANG, &contents, NULL, &err)) {
if (err)
ofono_error("cannot open %s error: %d: message: %s",
UI_LANG, err->code, err->message);
g_error_free(err);
} else {
gchar *pch = g_strrstr(contents, CFG_LANG);
/* Set System UI lang to env LANG */
if (pch) {
setenv("LANG", pch + strlen(CFG_LANG), 1);
DBG("LANG %s", getenv("LANG"));
}
g_free(contents);
}
}
static int ril_stk_probe(struct ofono_stk *stk, unsigned int vendor, void *data)
{
GRil *ril = data;
struct stk_data *sd;
DBG("");
sd = g_try_new0(struct stk_data, 1);
if (sd == NULL)
return -ENOMEM;
sd->ril = g_ril_clone(ril);
ofono_stk_set_data(stk, sd);
/* Register interface in this phase for stk agent */
ofono_stk_register(stk);
subscribed = FALSE;
/* UI language for local info */
ril_stk_set_lang();
return 0;
}
static void ril_stk_remove(struct ofono_stk *stk)
{
struct stk_data *sd = ofono_stk_get_data(stk);
DBG("");
ofono_stk_set_data(stk, NULL);
g_ril_unref(sd->ril);
g_free(sd);
}
static struct ofono_stk_driver driver = {
.name = "rilmodem",
.probe = ril_stk_probe,
.remove = ril_stk_remove,
.envelope = ril_stk_envelope,
.terminal_response = ril_stk_terminal_response,
.user_confirmation = ril_stk_user_confirmation,
.ready = ril_stk_agent_ready
};
void ril_stk_init(void)
{
ofono_stk_driver_register(&driver);
}
void ril_stk_exit(void)
{
ofono_stk_driver_unregister(&driver);
}

View File

@@ -68,19 +68,37 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
enum sms_charset charset;
int ret = -1;
ofono_info("send ussd");
ofono_info("send ussd, len:%d", len);
if (cbs_dcs_decode(dcs, NULL, NULL, &charset,
NULL, NULL, NULL)) {
if (charset == SMS_CHARSET_7BIT) {
unsigned char unpacked_buf[182] = "";
long written;
int length;
unpack_7bit_own_buf(pdu, len, 0, TRUE,
sizeof(unpacked_buf), &written, 0,
unpacked_buf);
if (written >= 1) {
/*
* When USSD was packed, additional CR
might have been added (according to
23.038 6.1.2.3.1). So if the last
character is CR, it should be removed
here. And in addition written doesn't
contain correct length...
Over 2 characters long USSD string must
end with # (checked in
valid_ussd_string() ), so it should be
safe to remove extra CR.
*/
length = strlen((char *)unpacked_buf);
if (length > 2 &&
unpacked_buf[length-1] == '\r')
unpacked_buf[length-1] = 0;
struct parcel rilp;
parcel_init(&rilp);
parcel_w_string(&rilp, (char *)unpacked_buf);
@@ -149,9 +167,9 @@ static void ril_ussd_notify(struct ril_msg *message, gpointer user_data)
{
struct ofono_ussd *ussd = user_data;
struct parcel rilp;
gchar *ussd_from_network;
gchar *type;
gint ussdtype;
gchar *ussd_from_network = NULL;
gchar *type = NULL;
gint ussdtype = 0;
ofono_info("ussd_received");
@@ -159,13 +177,17 @@ static void ril_ussd_notify(struct ril_msg *message, gpointer user_data)
parcel_r_int32(&rilp);
type = parcel_r_string(&rilp);
ussdtype = g_ascii_xdigit_value(*type);
g_free(type);
type = NULL;
ussd_from_network = parcel_r_string(&rilp);
if (ussd_from_network)
/* ussd_from_network not freed because core does that if dcs is 0xFF */
if (ussd_from_network) {
DBG("ussd_received, length %d", strlen(ussd_from_network));
ofono_ussd_notify(ussd, ussdtype, 0xFF,
(const unsigned char *)ussd_from_network,
strlen(ussd_from_network));
else
} else
ofono_ussd_notify(ussd, ussdtype, 0, NULL, 0);
return;

View File

@@ -4,7 +4,7 @@
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2012 Canonical Ltd.
* Copyright (C) 2013 Jolla Ltd.
* Copyright (C) 2014 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
@@ -45,9 +45,7 @@
/* Amount of ms we wait between CLCC calls */
#define POLL_CLCC_INTERVAL 300
#define FLAG_NEED_CLIP 1
#define MAX_DTMF_BUFFER 32
struct voicecall_data {
@@ -86,6 +84,21 @@ struct lastcause_req {
static void send_one_dtmf(struct voicecall_data *vd);
static void clear_dtmf_queue(struct voicecall_data *vd);
/*
* structs ofono_voicecall and voicecall are fully defined
* in src/voicecall.c; we need (read) access to the
* call objects, so partially redefine them here.
*/
struct ofono_voicecall {
GSList *call_list;
/* ... */
};
struct voicecall {
struct ofono_call *call;
/* ... */
};
static void lastcause_cb(struct ril_msg *message, gpointer user_data)
{
struct lastcause_req *reqdata = user_data;
@@ -99,11 +112,38 @@ static void lastcause_cb(struct ril_msg *message, gpointer user_data)
if (parcel_r_int32(&rilp) > 0)
last_cause = parcel_r_int32(&rilp);
/*
* Not all call control cause values specified in 3GPP TS 24.008
* "Mobile radio interface Layer 3 specification; Core network protocols",
* Annex H, are properly reflected in the RIL API. For example, cause
* #21 "call rejected" is mapped to CALL_FAIL_ERROR_UNSPECIFIED, and
* thus indistinguishable from a network failure.
* We signal disconnect reason "remote" for cause values
* - #16 "normal call clearing"
* - #17 "user busy"
* - UNSPECIFIED for MO calls that are not yet connected
* , and disconnect reason "network" otherwise.
*/
ofono_info("Call %d ended with RIL cause %d", id, last_cause);
if (last_cause == CALL_FAIL_NORMAL || last_cause == CALL_FAIL_BUSY) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
}
if (last_cause == CALL_FAIL_ERROR_UNSPECIFIED) {
GSList *l;
struct voicecall *v;
for (l = vc->call_list; l; l = l->next) {
v = l->data;
if (v->call->id == id) {
if (v->call->status == CALL_STATUS_DIALING
|| v->call->status == CALL_STATUS_ALERTING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
}
break;
}
}
}
ofono_voicecall_disconnected(vc, id, reason, NULL);
}
@@ -236,6 +276,8 @@ static void generic_cb(struct ril_msg *message, gpointer user_data)
int request = RIL_REQUEST_GET_CURRENT_CALLS;
int ret;
ofono_info("request:%d",message->req);
if (message->error == RIL_E_SUCCESS) {
decode_ril_error(&error, "OK");
} else {
@@ -340,15 +382,17 @@ static void ril_dial(struct ofono_voicecall *vc,
struct parcel rilp;
int request = RIL_REQUEST_DIAL;
int ret;
char *phstr = NULL;
ofono_info("dialing");
phstr = (char *) phone_number_to_string(ph);
ofono_info("dialing \"%s\"", phstr);
cbd->user = vc;
parcel_init(&rilp);
/* Number to dial */
parcel_w_string(&rilp, (char *) phone_number_to_string(ph));
parcel_w_string(&rilp, phstr);
/* CLIR mode */
parcel_w_int32(&rilp, clir);
/* USS, need it twice for absent */
@@ -481,6 +525,7 @@ static void ril_ss_notify(struct ril_msg *message, gpointer user_data)
strncpy(number.number, tmp_number,
OFONO_MAX_PHONE_NUMBER_LENGTH);
g_free(tmp_number);
DBG("RIL data: MT/MO: %i, code: %i, index: %i",
notification_type, code, index);
break;
@@ -634,6 +679,13 @@ static void ril_create_multiparty(struct ofono_voicecall *vc,
cb(&error, data);
}
static void ril_transfer(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_template(RIL_REQUEST_EXPLICIT_CALL_TRANSFER, vc, generic_cb, 0,
NULL, 0, cb, data);
}
static void private_chat_cb(struct ril_msg *message, gpointer user_data)
{
struct ofono_error error;
@@ -727,6 +779,23 @@ static gboolean enable_supp_svc(gpointer user_data)
return FALSE;
}
static void ril_ringback_tone_notify(struct ril_msg *message,
gpointer user_data)
{
struct parcel rilp;
struct ofono_voicecall *vc = user_data;
gboolean playTone = FALSE;
ril_util_init_parcel(message, &rilp);
if (message->req == RIL_UNSOL_RINGBACK_TONE) {
if (parcel_r_int32(&rilp) > 0)
playTone = parcel_r_int32(&rilp);
DBG("play ringback tone: %d", playTone);
ofono_voicecall_ringback_tone_notify(vc, playTone);
}
}
static gboolean ril_delayed_register(gpointer user_data)
{
struct ofono_voicecall *vc = user_data;
@@ -747,6 +816,10 @@ static gboolean ril_delayed_register(gpointer user_data)
g_ril_register(vd->ril, RIL_UNSOL_SUPP_SVC_NOTIFICATION,
ril_ss_notify, vc);
/* Register for ringback tone notifications */
g_ril_register(vd->ril, RIL_UNSOL_RINGBACK_TONE,
ril_ringback_tone_notify, vc);
/* request supplementary service notifications*/
enable_supp_svc(vc);
@@ -803,6 +876,7 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
if (vd->timer_id > 0)
g_source_remove(vd->timer_id);
g_free(vd->tone_queue);
g_ril_unref(vd->ril);
g_free(vd);
}
@@ -817,12 +891,13 @@ static struct ofono_voicecall_driver driver = {
.release_specific = ril_hangup_specific,
.send_tones = ril_send_dtmf,
.create_multiparty = ril_create_multiparty,
.transfer = ril_transfer,
.private_chat = ril_private_chat,
.swap_without_accept = ril_swap_without_accept,
.hold_all_active = ril_hold_all_active,
.release_all_held = ril_release_all_held,
.set_udub = ril_set_udub,
.release_all_active = ril_release_all_active,
.release_all_active = ril_release_all_active,
};
void ril_voicecall_init(void)

View File

@@ -0,0 +1,315 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2014 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <glib.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/location-reporting.h>
#include "gatchat.h"
#include "gatresult.h"
#include "gattty.h"
#include "telitmodem.h"
static const char *none_prefix[] = { NULL };
static const char *portcfg_prefix[] = { "#PORTCFG:", NULL };
static const char *gpsctl_prefix[] = { "$GPSP:", NULL };
struct gps_data {
GAtChat *chat;
};
static void telit_gps_disable_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
struct ofono_location_reporting *lr = cbd->user;
ofono_location_reporting_disable_cb_t cb = cbd->cb;
DBG("lr=%p, ok=%d", lr, ok);
if (!ok) {
struct ofono_error error;
decode_at_error(&error, g_at_result_final_response(result));
cb(&error, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void telit_location_reporting_disable(
struct ofono_location_reporting *lr,
ofono_location_reporting_disable_cb_t cb,
void *data)
{
struct gps_data *gd = ofono_location_reporting_get_data(lr);
struct cb_data *cbd = cb_data_new(cb, data);
DBG("lr=%p", lr);
cbd->user = lr;
if (g_at_chat_send(gd->chat, "AT$GPSP=0", none_prefix,
telit_gps_disable_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
}
static int enable_data_stream(struct ofono_location_reporting *lr)
{
struct ofono_modem *modem;
const char *gps_dev;
GHashTable *options;
GIOChannel *channel;
int fd;
modem = ofono_location_reporting_get_modem(lr);
gps_dev = ofono_modem_get_string(modem, "GPS");
options = g_hash_table_new(g_str_hash, g_str_equal);
if (options == NULL)
return -1;
g_hash_table_insert(options, "Baud", "115200");
channel = g_at_tty_open(gps_dev, options);
g_hash_table_destroy(options);
if (channel == NULL)
return -1;
fd = g_io_channel_unix_get_fd(channel);
g_io_channel_set_close_on_unref(channel, FALSE);
g_io_channel_unref(channel);
return fd;
}
static void telit_gps_ctl_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_location_reporting_enable_cb_t cb = cbd->cb;
struct ofono_location_reporting *lr = cbd->user;
struct ofono_error error;
int fd;
DBG("lr=%p ok=%d", lr, ok);
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, -1, cbd->data);
return;
}
fd = enable_data_stream(lr);
if (fd < 0) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
return;
}
cb(&error, fd, cbd->data);
close(fd);
}
static void telit_gps_enable_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_location_reporting_enable_cb_t cb = cbd->cb;
struct ofono_location_reporting *lr = cbd->user;
struct gps_data *gd = ofono_location_reporting_get_data(lr);
struct ofono_error error;
DBG("lr=%p ok=%d", lr, ok);
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, -1, cbd->data);
g_free(cbd);
return;
}
if (g_at_chat_send(gd->chat, "AT$GPSNMUN=1,0,0,0,0,0,0",
none_prefix, telit_gps_ctl_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
g_free(cbd);
}
static void telit_portcfg_check_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_location_reporting_enable_cb_t cb = cbd->cb;
struct ofono_location_reporting *lr = cbd->user;
struct gps_data *gd = ofono_location_reporting_get_data(lr);
struct ofono_error error;
int requested_portcfg, current_portcfg;
GAtResultIter iter;
DBG("lr=%p ok=%d", lr, ok);
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, -1, cbd->data);
g_free(cbd);
return;
}
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "#PORTCFG:"))
goto fail;
if (!g_at_result_iter_next_number(&iter, &requested_portcfg))
goto fail;
if (!g_at_result_iter_next_number(&iter, &current_portcfg))
goto fail;
if (current_portcfg != 8) {
ofono_warn("Unable to start GPS, modem configuration invalid");
ofono_warn("Refer to doc/telit-modem.txt section HE910/GPS");
goto fail;
}
if (g_at_chat_send(gd->chat, "AT$GPSP=1", none_prefix,
telit_gps_enable_cb, cbd, NULL) > 0)
return;
fail:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
g_free(cbd);
}
static void telit_location_reporting_enable(struct ofono_location_reporting *lr,
ofono_location_reporting_enable_cb_t cb,
void *data)
{
struct gps_data *gd = ofono_location_reporting_get_data(lr);
struct cb_data *cbd = cb_data_new(cb, data);
DBG("lr=%p", lr);
cbd->user = lr;
if (g_at_chat_send(gd->chat, "AT#PORTCFG?", portcfg_prefix,
telit_portcfg_check_cb, cbd, NULL) > 0)
return;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
g_free(cbd);
}
static void telit_location_reporting_support_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct ofono_location_reporting *lr = user_data;
if (!ok) {
ofono_location_reporting_remove(lr);
return;
}
ofono_location_reporting_register(lr);
}
static int telit_location_reporting_probe(struct ofono_location_reporting *lr,
unsigned int vendor, void *data)
{
GAtChat *chat = data;
struct gps_data *gd;
gd = g_try_new0(struct gps_data, 1);
if (gd == NULL)
return -ENOMEM;
gd->chat = g_at_chat_clone(chat);
ofono_location_reporting_set_data(lr, gd);
g_at_chat_send(gd->chat, "AT$GPSP=?", gpsctl_prefix,
telit_location_reporting_support_cb,
lr, NULL);
return 0;
}
static void telit_location_reporting_remove(struct ofono_location_reporting *lr)
{
struct gps_data *gd = ofono_location_reporting_get_data(lr);
ofono_location_reporting_set_data(lr, NULL);
g_at_chat_unref(gd->chat);
g_free(gd);
}
static struct ofono_location_reporting_driver driver = {
.name = "telitmodem",
.type = OFONO_LOCATION_REPORTING_TYPE_NMEA,
.probe = telit_location_reporting_probe,
.remove = telit_location_reporting_remove,
.enable = telit_location_reporting_enable,
.disable = telit_location_reporting_disable,
};
void telit_location_reporting_init()
{
ofono_location_reporting_driver_register(&driver);
}
void telit_location_reporting_exit()
{
ofono_location_reporting_driver_unregister(&driver);
}

View File

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

View File

@@ -0,0 +1,25 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <drivers/atmodem/atutil.h>
extern void telit_location_reporting_init();
extern void telit_location_reporting_exit();

View File

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

View File

@@ -1,6 +1,7 @@
[Unit]
Description=DUN service
After=syslog.target
Requires=dbus.service
After=dbus.service
[Service]
Type=dbus

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