Compare commits

...

94 Commits

Author SHA1 Message Date
Slava Monich
1d35a2dc2d Merge pull request #8 from monich/signals
Fix a problem with D-Bus signal not being emitted
2021-09-17 12:42:08 +03:00
Slava Monich
352bdf5a39 [unit] Test DefaultDataModemChanged signal. JB#55575 2021-09-17 02:25:57 +03:00
Slava Monich
d73d3e2e7f [ofono] Fixed a problem with D-Bus signal not being emitted. JB#55575
Whenever slot_manager_update_modem_paths() returns something non-zero,
corresponding D-Bus signals must be emitted.
2021-09-17 02:25:43 +03:00
Slava Monich
38a83d3c18 [ofono] Added debug trace 2021-09-16 20:28:42 +03:00
Slava Monich
5b175c2877 [unit] Fixed coverage script
It was broken by removal of ril plugin.
2021-09-16 19:59:06 +03:00
Slava Monich
52bb7b3295 [unit] Added back test-conf
It was accidentally removed earlier.
2021-09-16 19:57:18 +03:00
Slava Monich
09e6f35a23 [ofono] Replace built-in ril plugin with the external one. JB#55027 2021-09-15 03:02:16 +03:00
Slava Monich
6dddf527d5 Merge pull request #7 from monich/double-free
Fix double-free
2021-09-14 17:01:57 +03:00
Slava Monich
a9de07c2bb [ril] Fix double-free. JB#55547 2021-09-14 16:43:36 +03:00
Slava Monich
ecf14f5165 Merge pull request #4 from monich/ril-split
Make more APIs available to external plugins
2021-09-13 17:51:42 +03:00
Slava Monich
bc4c860a86 [ofono] Make more APIs available to external plugins. JB#55027
This allows to build Jolla ril driver as an external dynamically
loadable plugin.
2021-09-13 16:32:33 +03:00
Slava Monich
7684dd4295 Housekeeping 2021-09-13 14:32:44 +03:00
Slava Monich
f24a5be4ec Update upstream hash 2021-09-13 14:32:23 +03:00
Slava Monich
c45e207f12 Merge pull request #6 from PsychoGame/ofono-new
[ofono] Update baseline to 1.24. JB#54354
2021-09-13 14:26:53 +03:00
Marcel Holtmann
005f36bb89 Release 1.24 2021-09-07 21:48:50 +02:00
Marcel Holtmann
3d01485a05 gatchat: Use pragma to mask unknown pragma diagnostic options
gatchat/gatmux.c:33:32: error: unknown option after ‘#pragma GCC diagnostic’ kind [-Werror=pragmas]
 #pragma GCC diagnostic ignored "-Wcast-function-type"
                                ^~~~~~~~~~~~~~~~~~~~~~
2021-09-07 21:43:31 +02:00
Marcel Holtmann
cc7b30414f rilmodem: Use pragma to mask restrict buffer warnings
In file included from drivers/rilmodem/network-registration.c:40:
drivers/rilmodem/network-registration.c: In function ‘ril_cops_list_cb’:
./gril/gril.h:98:11: error: passing argument 1 to restrict-qualified parameter aliases with argument 3 [-Werror=restrict]
   sprintf(print_buf, x);  \
           ^~~~~~~~~
drivers/rilmodem/network-registration.c:583:3: note: in expansion of macro ‘g_ril_append_print_buf’
   g_ril_append_print_buf(nd->ril, "%s [lalpha=%s, salpha=%s, "
   ^~~~~~~~~~~~~~~~~~~~~~
./gril/gril.h:98:11: error: passing argument 1 to restrict-qualified parameter aliases with argument 3 [-Werror=restrict]
   sprintf(print_buf, x);  \
           ^~~~~~~~~
drivers/rilmodem/network-registration.c:593:2: note: in expansion of macro ‘g_ril_append_print_buf’
  g_ril_append_print_buf(nd->ril, "%s}", print_buf);
  ^~~~~~~~~~~~~~~~~~~~~~

In file included from drivers/rilmodem/call-forwarding.c:41:
drivers/rilmodem/call-forwarding.c: In function ‘ril_query_call_fwd_cb’:
./gril/gril.h:98:11: error: passing argument 1 to restrict-qualified parameter aliases with argument 3 [-Werror=restrict]
   sprintf(print_buf, x);  \
           ^~~~~~~~~
drivers/rilmodem/call-forwarding.c:114:3: note: in expansion of macro ‘g_ril_append_print_buf’
   g_ril_append_print_buf(fd->ril, "%s [%d,%d,%d,%s,%d]",
   ^~~~~~~~~~~~~~~~~~~~~~
./gril/gril.h:98:11: error: passing argument 1 to restrict-qualified parameter aliases with argument 3 [-Werror=restrict]
   sprintf(print_buf, x);  \
           ^~~~~~~~~
drivers/rilmodem/call-forwarding.c:124:2: note: in expansion of macro ‘g_ril_append_print_buf’
  g_ril_append_print_buf(fd->ril, "%s}", print_buf);
  ^~~~~~~~~~~~~~~~~~~~~~
2021-09-07 21:42:45 +02:00
Marcel Holtmann
1617b325de gatchat: Use pragma to mask GFunc casting warning
gatchat/gatmux.c: In function ‘watch_dispatch’:
gatchat/gatmux.c:454:17: error: cast between incompatible function types from ‘GSourceFunc’ {aka ‘int (*)(void *)’} to ‘gboolean (*)(GIOChannel *, GIOCondition,  void *)’ {aka ‘int (*)(struct _GIOChannel *, enum <anonymous>,  void *)’} [-Werror=cast-function-type]
  GIOFunc func = (GIOFunc) callback;
                 ^
2021-09-07 21:42:01 +02:00
Antara Borwankar
a8838c2287 atmodem: Support ETWS & CMAS on XMM series modems 2021-09-07 21:40:49 +02:00
Denis Kenzior
c8cd552851 sim: Fix not updating sim pin state
In case we try to enter the PIN/PUK and fail to enter a correct code,
the PIN/PUK retries are not rechecked as they should be.

Reported by: Florent Beillonnet <florent.beillonnet@gmail.com>
2021-09-07 21:39:55 +02:00
Denis Kenzior
6995d8c42c AUTHORS: Mention Florent's contributions 2021-09-07 21:38:21 +02:00
Florent Beillonnet
17052d41de atmodem: Fix at_pin_send_puk userdata use
It seems that the function at_pin_send_puk should have been changed
along with at_pin_send, because it's also refering to the
at_pin_send_cb callback

See this commit : ba9f126716db3ae0bf6a3139088d9657cfb8b851
2021-09-07 21:37:38 +02:00
Denis Kenzior
70a93dcc5b gemalto: Whitespace fixes 2021-09-07 21:36:40 +02:00
Denis Kenzior
e3ea3abaa0 AUTHORS: Mention Varun's contributions 2021-09-07 21:36:00 +02:00
Varun Gargi
f60c44b034 udevng: remove vendor ID to make it generic for intel modem 2021-09-07 21:35:00 +02:00
James Prestwood
a679258b4a plugins: fixed crash in udevng
The return value from ofono_modem_register was not being checked. If this fails
the modem object is not setup and causes a crash. This was specifically seen
when using the mbim driver without having configured with mbim support.

Now the modem object gets destroyed properly if the modem registration fails.
2021-09-07 21:33:59 +02:00
Bob Ham
0ed72bcffa sim7100: Specify vendor ID while creating voicecall driver
This enables the atmodem voicecall driver to handle SIMCom quirks like
not setting AT+COLP=1.
2021-09-07 21:30:55 +02:00
Bob Ham
7d5a660604 atmodem: Don't set AT+COLP=1 on SIMCom modems
On the SIMCom SIM7100E, setting AT+COLP=1 causes there to be no
response at all from "ATD...;" commands until the call is answered.
The results in oFono stalling rather than creating a new VoiceCall
object.

We fix this by adding SIMCOM to the list of vendors for whom we set
AT+COLP=0 rather than AT+COLP=1.
2021-09-07 21:30:08 +02:00
Denis Kenzior
d67240c717 AUTHORS: Mention Bob's contributions 2021-09-07 21:26:39 +02:00
Bob Ham
b12016eb45 plugins: Add support for SIM7100E by SIMCom
Add support for the SIM7100E modem.  We add a new "sim7100" plugin
because there's no other AT-based modem that has support for both GPRS
and voice calls.
2021-09-07 21:25:40 +02:00
Denis Kenzior
bfec98afdf unit: Fix gcc warning
In file included from unit/test-mbim.c:28:0:
unit/test-mbim.c: In function ‘parse_device_caps’:
unit/test-mbim.c:332:9: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
  assert(cellular_class = 1);
2021-09-07 21:14:10 +02:00
Mark van der Putten
7376781211 gemalto: signal sim initialized
Modem type PLS8-E, firmware 03.017
2021-09-07 21:11:23 +02:00
Christophe Ronco
732160519a qmi: report SIM not inserted when unable to get PIN type 2021-09-07 21:08:55 +02:00
Christophe Ronco
f71d2a2b70 qmi: report failure or retry in case of invalid pin type
QMI_UIM_GET_CARD_STATUS is retried in more error cases
when trying to get password type.
In case of failure, driver report an error instead of
OFONO_SIM_PASSWORD_INVALID. This avoids a crash.
2021-09-07 21:08:08 +02:00
Christophe Ronco
793e9fcae4 qmi: use right slot and application during SIM detection
Use right slot and application to get card status, PIN status and PIN
retries. Without this patch, SIMs where selected application and slot
numbers are different are not detected.
2021-09-07 21:07:08 +02:00
Jonas Bonn
ae204ebf82 qmi: make services always shared 2021-09-07 21:05:05 +02:00
Jonas Bonn
30b09b35af gobi: Update to the new version_list changes 2021-09-07 21:03:54 +02:00
Jonas Bonn
1495f222b0 qmi: make version_list private 2021-09-07 21:02:38 +02:00
Jonas Bonn
b9b2765b21 qmi: assume version_list is up to date
The way things are currently coded, the gobi plugin calls
qmi_device_discover and does nothing else until it succeeds.  As such,
we can safely assume that the version_list is set up when we go to
create a service.
2021-09-07 20:59:42 +02:00
Jonas Bonn
29ecf1a59a qmi: drop header output parameter from request_alloc
The only thing this output parameter is being used for now is for
getting the transaction ID.  Return the TID directly from
__submit_requesta and drop the 'head' parameter altogether.
2021-09-07 20:58:52 +02:00
Jonas Bonn
f1d3367e0a qmi: request_alloc has no meaningful failure path
The only way request_alloc can fail is if one of the memory allocation
routines fail to allocate memory.  However, Linux memory allocation
doesn't really fail in this manner; memory can be overcommited and the
out-of-memory reaper will take care of re-establishing the balance when
excess memory is actually accessed.

Given this, request_alloc will never return anything other than success
and the failure paths will never be exercised.
2021-09-07 20:58:07 +02:00
Jonas Bonn
7131403177 qmi: unify common request header setup
The service and control requests differ slightly in their headers, but
this difference is minor enough that we can handle it directly in the
request submission routine.  This patch unifies the header setup for the
two request types.
2021-09-07 20:54:58 +02:00
Jonas Bonn
ff99f16ccb qmi: remove headroom parameter from req_alloc
The headroom can be established from the service type, so it's redundant
to pass it as a parameter.
2021-09-07 20:54:12 +02:00
Jonas Bonn
ccec9504a5 qmi: remove unused fields of service_send_data
After setting up the request structure, qmi_service_send makes no
further use of the 'param' and 'service' fields of the service_send_data
structure.  This patch removes those fields and frees 'param'
immediately after the request has been allocated and the parameter data
thereby copied into the send buffer.
2021-09-07 20:52:21 +02:00
Bassem Boubaker
e37ca6d384 gemalto: Clarify supported modem family name
Some gemalto modem family share almost the same base except some very
specific AT command and some hardware changes like ALSx and PXSx family
2021-09-07 20:49:34 +02:00
Mariem Cherif
ab5b76d6cf gemalto: handle sim is inserted or removed URCs 2021-09-07 20:48:14 +02:00
Denis Kenzior
35ef8fb8a1 qmi: Fix uninitialized value use
==2870== Conditional jump or move depends on uninitialised value(s)
==2870==    at 0x4C2ED31: __memcmp_sse4_1 (vg_replace_strmem.c:972)
==2870==    by 0x4F451A: sim_pin_retries_query_cb (sim.c:462)
==2870==    by 0x459BDD: query_pin_retries_cb (sim.c:544)
==2870==    by 0x45544A: service_send_callback (qmi.c:2143)
==2870==    by 0x452D00: handle_packet (qmi.c:815)
==2870==    by 0x452E85: received_data (qmi.c:863)
==2870==    by 0x508DB6C: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x508DF47: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x508E271: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x4C680B: main (main.c:256)
==2870==  Uninitialised value was created by a stack allocation
==2870==    at 0x459B1A: query_pin_retries_cb (sim.c:531)
==2870==
==2870== Conditional jump or move depends on uninitialised value(s)
==2870==    at 0x4F451D: sim_pin_retries_query_cb (sim.c:462)
==2870==    by 0x459BDD: query_pin_retries_cb (sim.c:544)
==2870==    by 0x45544A: service_send_callback (qmi.c:2143)
==2870==    by 0x452D00: handle_packet (qmi.c:815)
==2870==    by 0x452E85: received_data (qmi.c:863)
==2870==    by 0x508DB6C: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x508DF47: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x508E271: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x4C680B: main (main.c:256)
==2870==  Uninitialised value was created by a stack allocation
==2870==    at 0x459B1A: query_pin_retries_cb (sim.c:531)
==2870==
==2870== Conditional jump or move depends on uninitialised value(s)
==2870==    at 0x4F3DFB: get_pin_retries (sim.c:278)
==2870==    by 0x4F4553: sim_pin_retries_query_cb (sim.c:467)
==2870==    by 0x459BDD: query_pin_retries_cb (sim.c:544)
==2870==    by 0x45544A: service_send_callback (qmi.c:2143)
==2870==    by 0x452D00: handle_packet (qmi.c:815)
==2870==    by 0x452E85: received_data (qmi.c:863)
==2870==    by 0x508DB6C: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x508DF47: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x508E271: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x4C680B: main (main.c:256)
==2870==  Uninitialised value was created by a stack allocation
==2870==    at 0x459B1A: query_pin_retries_cb (sim.c:531)
==2870==
==2870== Conditional jump or move depends on uninitialised value(s)
==2870==    at 0x4F3E65: get_pin_retries (sim.c:288)
==2870==    by 0x4F4553: sim_pin_retries_query_cb (sim.c:467)
==2870==    by 0x459BDD: query_pin_retries_cb (sim.c:544)
==2870==    by 0x45544A: service_send_callback (qmi.c:2143)
==2870==    by 0x452D00: handle_packet (qmi.c:815)
==2870==    by 0x452E85: received_data (qmi.c:863)
==2870==    by 0x508DB6C: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x508DF47: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x508E271: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4200.1)
==2870==    by 0x4C680B: main (main.c:256)
==2870==  Uninitialised value was created by a stack allocation
==2870==    at 0x459B1A: query_pin_retries_cb (sim.c:531)
2021-09-07 20:46:23 +02:00
Denis Kenzior
d0a617d469 qmi: Fix memory leak
==14399== 28 bytes in 4 blocks are definitely lost in loss record 151 of 390
==14399==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==14399==    by 0x209065: convert_gsm_to_utf8_with_lang (util.c:651)
==14399==    by 0x2091D1: convert_gsm_to_utf8 (util.c:690)
==14399==    by 0x22DDA7: ussd_decode (smsutil.c:4738)
==14399==    by 0x18BF71: qmi_ussd_request (ussd.c:233)
==14399==    by 0x2183EA: ussd_initiate (ussd.c:614)
==14399==    by 0x27B6C8: process_message (object.c:259)
==14399==    by 0x27D1CD: generic_message (object.c:1070)
==14399==    by 0x5170732: ??? (in /lib/x86_64-linux-gnu/libdbus-1.so.3.14.14)
==14399==    by 0x5161D83: dbus_connection_dispatch (in /lib/x86_64-linux-gnu/libdbus-1.so.3.14.14)
==14399==    by 0x27907C: message_dispatch (mainloop.c:72)
==14399==    by 0x4E826A9: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.5000.3)
2021-09-07 20:06:26 +02:00
Denis Kenzior
1ba3b32273 qmi: Fix memory leak
==14399== 16 bytes in 8 blocks are definitely lost in loss record 132 of 390
==14399==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==14399==    by 0x59E03D9: strndup (strndup.c:43)
==14399==    by 0x18277E: qmi_result_get_string (qmi.c:1794)
==14399==    by 0x184221: get_ids_cb (devinfo.c:129)
==14399==    by 0x18353B: service_send_callback (qmi.c:2286)
==14399==    by 0x18093C: handle_packet (qmi.c:831)
==14399==    by 0x180ADD: received_data (qmi.c:880)
==14399==    by 0x4E826A9: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.5000.3)
==14399==    by 0x4E82A5F: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.5000.3)
==14399==    by 0x4E82D81: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.5000.3)
==14399==    by 0x201900: main (main.c:306)
2021-09-07 20:05:00 +02:00
Gabriel Lucas
14b764ac64 gemalto: support ALS3 in gemalto's plugin
Force serial port opening options
Wait for modem to be ready to start
initializing it
Handle LTE
2021-09-07 20:03:52 +02:00
Bassem Boubaker
b808bfad17 gemalto: Add more details in setup_gemalto comment
ALS3, PLS8-E and PLS8-X have same vid/pid with same enumeration process
2021-09-07 19:53:46 +02:00
Denis Kenzior
82d62a8f50 AUTHORS: Mention Bassem's contributions 2021-09-07 19:52:07 +02:00
Bassem Boubaker
23d6263e3c cdma-netreg: Fix emission of PropertyChanged 2021-09-07 19:51:01 +02:00
Denis Kenzior
ac3192204c AUTHORS: Mention Mariem's contributions 2021-09-07 19:49:54 +02:00
Mariem Cherif
5ad2617ecd gemalto: acquire the network technology 2021-09-07 19:48:21 +02:00
Gabriel Lucas
890842b3af gemalto: add detection of ALS3 modem
The product ID is added to the list of
modems to be detected by Ofono.
The gemalto plugin is used to handle the
ALS3 modem.
2021-09-07 19:47:25 +02:00
Denis Kenzior
06de44299a plugins: Update to the new LTE API 2021-09-07 19:39:51 +02:00
Denis Kenzior
77b2eec613 ubloxmodem: Update to the new LTE API 2021-09-07 19:37:07 +02:00
Denis Kenzior
12ccd7cd46 rilmodem: Update to the new LTE API 2021-09-07 19:35:59 +02:00
Denis Kenzior
8f09880d52 qmimodem: Update to the new LTE API 2021-09-07 19:31:48 +02:00
Denis Kenzior
ee5f91221b atmodem: Update to the new lte API 2021-09-07 19:29:08 +02:00
Denis Kenzior
c03c6f4215 lte: update to the new API 2021-09-07 19:25:27 +02:00
Denis Kenzior
c49e2d8723 include: Add missing vendor parameter to lte atom 2021-09-07 19:13:37 +02:00
Slava Monich
deecd829a6 Merge pull request #5 from sailfishos/jb55388
Remove incorrect hardcoded tech value.
2021-09-07 16:49:39 +03:00
Matti Lehtimäki
3acf91c6a9 [ril] Remove incorrect hardcoded tech value. JB#55388 2021-09-06 20:44:26 +03:00
Marcel Holtmann
85b61c8964 call-forwarding: Increase string buffer to avoid overflow 2021-08-26 03:03:55 +03:00
Jonas Bonn
8986749585 atmodem: enlarge command buffer
The ofono phone number max length is 80 so a buffer size of 64 is
obviously insufficient.  Expanding the buffer to 128 prevents a
potential failure and suppresses the folowing compiler warning:

../drivers/atmodem/sms.c: In function ‘at_csca_set’:
../drivers/atmodem/sms.c:108:40: warning: ‘%s’ directive output may be truncated writing up to 80 bytes into a region of size 55 [-Wformat-truncation=]
  snprintf(buf, sizeof(buf), "AT+CSCA=\"%s\",%d", sca->number, sca->type);
                                        ^~
../drivers/atmodem/sms.c:108:2: note: ‘snprintf’ output between 13 and 103 bytes into a destination of size 64
  snprintf(buf, sizeof(buf), "AT+CSCA=\"%s\",%d", sca->number, sca->type);
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2021-08-26 03:03:55 +03:00
Juho Hämäläinen
1c0f5094a6 Merge pull request #3 from jusa/jb55276
Be less pedantic about ordering of speech codecs.
2021-08-25 17:00:06 +03:00
Juho Hämäläinen
4208b6d9ea [bluetooth] Be less pedantic about ordering of speech codecs. Fixes JB#55276
HFP spec 1.7.1 (4.34.1) says:

The Codec ID for the mandatory narrow band codec (CVSD) shall
always be included.

If wide band speech is supported, then the mandatory codec (mSBC)
shall be included unless it is temporarily unavailable.

Any other optional wide band speech codecs may also be included
in this list as long as the mandatory codec is included first.

---

The wording in spec is slightly vague on what the ordering of
mandatory narrow band codec (CVSD) and - IF wide band speech
is supported - mandatory wide band coded (mSBC) should be.
oFono's take is that the mandatory narrow band codec should
be listed first, and when mSBC is there oFono will abort the
connection.

To fix this we can be less pedantic about the ordering of
codecs - as long as the mandatory ones are there.
2021-08-25 16:32:55 +03:00
Frajo
59e304d474 Merge pull request #2 from krnlyng/jb55233
[packaging] Use transfiletriggerin to restart ofono when a plugin is installed. JB#55233
2021-08-25 16:02:24 +03:00
Frajo Haider
30a2424507 [packaging] Use transfiletriggerin to restart ofono when a plugin is installed. JB#55233 2021-08-24 13:29:18 +03:00
Slava Monich
e4f3ec6322 Merge pull request #1 from monich/start_block
Fix SIM I/O mess
2021-07-30 15:12:59 +03:00
Slava Monich
95fd4efc37 [simfs] Fix SIM I/O mess. JB#54380
Apparently all simfs reads from any blocks other than the very first one
were badly broken and could even cause a crash :|
2021-07-30 01:50:07 +03:00
Slava Monich
ef5ee98508 [ofono] Set destination for Unsubscribed signal. JB#50816 2021-06-10 18:00:39 +03:00
Slava Monich
4220e7d5e8 Merge branch 'dbus-clients-fixes' into 'master'
Resolve a few issues with cell info notifications

See merge request mer-core/ofono!286
2021-06-10 13:54:42 +00:00
Slava Monich
33c067a75f [ofono] Resolved a few issues with cell info notifications. JB#50816
1. Disable notifications from modem on unsibscribe
2. Made all signals unicast
3. Fixed a memory leak
2021-06-10 16:23:52 +03:00
Slava Monich
29616c04d0 [ofono] Fixed signal emission, reworked D-Bus client list. JB#50816
1. Exposed D-Bus clients list to plugin as ofono_dbus_clients
2. Signal has to be properly declared, otherwise it's not emitted
3. Added missing unit tests
2021-06-10 05:10:16 +03:00
Slava Monich
beb997d914 Merge branch 'jb50608-ondemand' into 'master'
Disable cell info updates when no one listens for them

See merge request mer-core/ofono!274
2021-06-10 01:58:05 +00:00
Slava Monich
cefc03e5ed Merge branch 'pcscf' into 'master'
Expose P-CSCF address(es) over D-Bus

See merge request mer-core/ofono!285
2021-06-03 21:29:06 +00:00
Slava Monich
85d99536ee Merge branch 'mtu' into 'master'
Don't limit MTU for non-MMS contexts

See merge request mer-core/ofono!284
2021-06-03 21:28:08 +00:00
Slava Monich
ea36baa4c1 [ril] Don't limit MTU for non-MMS contexts
Larger MTU means better throughput, and the original problem for which
this workaround was implemented was specific to MMS. There's no reason
to limit MTU for other data connections.
2021-06-03 19:49:38 +03:00
Slava Monich
b95a089c00 [ril] Provide P-CSCF address to the core. JB#48905
Also optimized reporting of DNS addresses by not setting empty lists.
If nothing else, that slightly reduces the amount of D-Bus traffic.
2021-06-03 19:36:52 +03:00
Slava Monich
c8dbf5494b [ofono] Expose P-CSCF address(es) via D-Bus. JB#48905 2021-06-03 19:01:01 +03:00
Slava Monich
cfb75f473d [sim] Fixed AID comparison. JB#54048
It worked only because aid was the first field in the struct.
2021-06-03 04:24:46 +03:00
Slava Monich
edd91c94eb Merge branch 'auth' into 'master'
Implement org.ofono.SimAuthentication interface

See merge request mer-core/ofono!283
2021-06-02 14:15:27 +00:00
Slava Monich
af0ab142e1 [ril] Implement org.ofono.SimAuthentication interface. JB#54048 2021-06-01 02:12:35 +03:00
Slava Monich
dffc04d404 [sim-auth] Support short AIDs. JB#54048
They can be shorter than 16 bytes.
2021-06-01 02:11:36 +03:00
Slava Monich
97b5fcbd87 [sim-auth] Parse auth response according to TS 31.102 2021-05-30 14:09:32 +03:00
Slava Monich
d7e740347f [sim-auth] Fill unused part of AID with FFs 2021-05-30 14:09:32 +03:00
Slava Monich
1116ca2481 [ril] Append ROOTMF path by default
Empty path never works and some RILs/modems don't like it so much
that it causes a reset.
2021-05-30 14:01:02 +03:00
Denis Grigorev
3d147843c4 [ril] Make cell info updates unicast. JB#50608 2021-05-28 16:25:42 +03:00
Denis Grigorev
c01dc63cbc [ril] Cell info consumer can unsubscribe from updates. JB#50608
Add a new org.nemomobile.ofono.CellInfo.Unsubscribe method. If it is called
ofono excludes the client from cell info consumers. The updates will be
disabled if no one client left.
2021-05-28 16:25:42 +03:00
Denis Grigorev
297926ed24 [ril] Enable cell info updates only when requested. JB#50608 2021-05-28 16:25:42 +03:00
Denis Grigorev
6ef1174ea8 [ril] Cell info updates can be disabled. JB#50608 2021-05-28 16:25:42 +03:00
183 changed files with 10027 additions and 33099 deletions

15
ofono/.gitignore vendored
View File

@@ -9,7 +9,7 @@ Makefile.in
aclocal.m4
config.guess
config.h
config.h.in
config.h.in*
config.log
config.status
config.sub
@@ -42,9 +42,13 @@ unit/test-sms-root
unit/test-simutil
unit/test-mux
unit/test-caif
unit/test-cell-info
unit/test-cell-info-dbus
unit/test-stkutil
unit/test-cdmasms
unit/test-conf
unit/test-dbus-access
unit/test-dbus-clients
unit/test-dbus-queue
unit/test-gprs-filter
unit/test-ril_config
@@ -57,13 +61,10 @@ unit/test-rilmodem-cs
unit/test-rilmodem-gprs
unit/test-rilmodem-sms
unit/test-sailfish_access
unit/test-sailfish_cell_info
unit/test-sailfish_cell_info_dbus
unit/test-sailfish_manager
unit/test-sailfish_sim_info
unit/test-sailfish_sim_info_dbus
unit/test-config
unit/test-slot-manager
unit/test-watch
unit/test-sim-info
unit/test-sim-info-dbus
unit/test-sms-filter
unit/test-voicecall-filter
unit/test-*.log

View File

@@ -130,3 +130,8 @@ Joey Hewitt <joey@joeyhewitt.com>
Richard Röjfors <richard.rojfors@gmail.com>
Philippe De Swert <philippe.deswert@nomovok.com>
Gabriel Lucas <gabriel.lucas@smile.fr>
Mariem Cherif <mariem.cherif@ardia.com.tn>
Bassem Boubaker <bassem.boubaker@actia.fr>
Bob Ham <bob.ham@puri.sm>
Varun Gargi <varun.gargi@intel.com>
Florent Beillonnet <florent.beillonnet@gmail.com>

View File

@@ -1,3 +1,16 @@
ver 1.24:
Fix issue with property changed signals and CDMA networks.
Fix issue with handling SIM filesystem and SIM removal.
Fix issue with handling PIN state and incorrect codes.
Fix issue with handling of parsing AID type.
Fix issue with SIM detection and QMI devices.
Fix issue with PIN handling and QMI devices.
Fix issue with USSD handling and QMI devices.
Fix issue with handling USSD TERMINATED response.
Fix issue with handling USSD reset and STK REFRESH.
Add support for detecting Gemalto ALS3 modems.
Add support for SIMCom based SIM7100E modems.
ver 1.23:
Fix issue with handling SIM AID sessions.
Add support for QMI LTE bearer handling.

View File

@@ -26,9 +26,11 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
include/sms-filter.h include/gprs-filter.h \
include/voicecall-filter.h include/dbus-access.h \
include/ril-constants.h include/ril-transport.h \
include/watch.h gdbus/gdbus.h \
include/watch.h gdbus/gdbus.h include/dbus-clients.h \
include/netmon.h include/lte.h include/ims.h \
include/storage.h
include/slot.h include/cell-info.h \
include/storage.h include/conf.h include/misc.h \
include/mtu-limit.h
nodist_pkginclude_HEADERS = include/version.h
@@ -119,74 +121,12 @@ builtin_modules += udevng
builtin_sources += plugins/udevng.c
endif
if SAILFISH_MANAGER
builtin_modules += sailfish_manager
builtin_sources += plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
plugins/sailfish_manager/sailfish_manager.c \
plugins/sailfish_manager/sailfish_manager_dbus.c \
plugins/sailfish_manager/sailfish_sim_info.c \
plugins/sailfish_manager/sailfish_sim_info_dbus.c
endif
if SAILFISH_ACCESS
builtin_modules += sailfish_access
builtin_sources += plugins/sailfish_access.c
endif
if RILMODEM
if SAILFISH_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_config.c \
drivers/ril/ril_connman.c \
drivers/ril/ril_cbs.c \
drivers/ril/ril_data.c \
drivers/ril/ril_devinfo.c \
drivers/ril/ril_devmon.c \
drivers/ril/ril_devmon_auto.c \
drivers/ril/ril_devmon_combine.c \
drivers/ril/ril_devmon_ds.c \
drivers/ril/ril_devmon_ss.c \
drivers/ril/ril_devmon_ur.c \
drivers/ril/ril_ecclist.c \
drivers/ril/ril_gprs.c \
drivers/ril/ril_gprs_context.c \
drivers/ril/ril_modem.c \
drivers/ril/ril_netmon.c \
drivers/ril/ril_netreg.c \
drivers/ril/ril_network.c \
drivers/ril/ril_oem_raw.c \
drivers/ril/ril_phonebook.c \
drivers/ril/ril_plugin.c \
drivers/ril/ril_radio.c \
drivers/ril/ril_radio_caps.c \
drivers/ril/ril_radio_settings.c \
drivers/ril/ril_sim.c \
drivers/ril/ril_sim_card.c \
drivers/ril/ril_sim_settings.c \
drivers/ril/ril_sms.c \
drivers/ril/ril_stk.c \
drivers/ril/ril_ussd.c \
drivers/ril/ril_util.c \
drivers/ril/ril_vendor.c \
drivers/ril/ril_voicecall.c
# Vendor specific extensions
builtin_sources += drivers/ril/ril_vendor_mtk.c
if DATAFILES
dist_conf_DATA += drivers/ril/ril_subscription.conf
endif
else
builtin_sources += $(gril_sources)
builtin_modules += rildev
@@ -227,7 +167,6 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
drivers/infineonmodem/infineon_constants.h \
drivers/rilmodem/lte.c
endif
endif
if ISIMODEM
builtin_modules += isimodem
@@ -497,7 +436,7 @@ builtin_sources += drivers/cdmamodem/cdmamodem.h \
drivers/cdmamodem/connman.c
endif
if !RILMODEM
if EXTRA_MODEMS
builtin_modules += g1
builtin_sources += plugins/g1.c
@@ -573,6 +512,9 @@ builtin_sources += plugins/samsung.c
builtin_modules += sim900
builtin_sources += plugins/sim900.c
builtin_modules += sim7100
builtin_sources += plugins/sim7100.c
builtin_modules += telit
builtin_sources += plugins/telit.c
@@ -748,7 +690,6 @@ endif
sbin_PROGRAMS = src/ofonod
src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/mtu-watch.c \
src/main.c src/ofono.h src/log.c src/plugin.c \
src/modem.c src/common.h src/common.c \
src/manager.c src/dbus.c src/util.h src/util.c \
@@ -775,11 +716,15 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/handsfree-audio.c src/bluetooth.h \
src/sim-mnclength.c src/voicecallagent.c \
src/sms-filter.c src/gprs-filter.c \
src/dbus-queue.c src/dbus-access.c src/config.c \
src/dbus-clients.c src/dbus-queue.c src/dbus-access.c \
src/voicecall-filter.c src/ril-transport.c \
src/hfp.h src/siri.c src/watchlist.c \
src/netmon.c src/lte.c src/ims.c \
src/netmonagent.c src/netmonagent.h
src/netmonagent.c src/netmonagent.h \
src/slot-manager.c src/slot-manager-dbus.c \
src/cell-info.c src/cell-info-dbus.c \
src/sim-info.c src/sim-info-dbus.c \
src/conf.c src/mtu-limit.c
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
@@ -806,8 +751,7 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ $(builtin_cflags) \
AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/src \
-I$(srcdir)/gdbus -I$(srcdir)/gisi -I$(srcdir)/gatchat \
-I$(srcdir)/btio -I$(srcdir)/gril \
-I$(srcdir)/plugins/sailfish_manager
-I$(srcdir)/btio -I$(srcdir)/gril
doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
doc/manager-api.txt doc/modem-api.txt doc/network-api.txt \
@@ -967,61 +911,56 @@ unit_tests = unit/test-common unit/test-util unit/test-idmap \
unit/test-simutil unit/test-stkutil \
unit/test-sms unit/test-cdmasms
if SAILFISH_MANAGER
unit_test_conf_SOURCES = unit/test-conf.c src/conf.c src/log.c
unit_test_conf_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
unit_test_conf_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_conf_OBJECTS)
unit_tests += unit/test-conf
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
unit_tests += unit/test-sailfish_cell_info
unit_test_cell_info_SOURCES = unit/test-cell-info.c src/cell-info.c src/log.c
unit_test_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
unit_test_cell_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_cell_info_OBJECTS)
unit_tests += unit/test-cell-info
unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
unit/test-sailfish_cell_info_dbus.c \
unit/fake_sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
gdbus/object.c \
unit_test_cell_info_dbus_SOURCES = unit/test-dbus.c \
unit/test-cell-info-dbus.c unit/fake_cell_info.c \
src/cell-info.c src/cell-info-dbus.c \
gdbus/object.c src/dbus-clients.c \
src/dbus.c src/log.c
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
unit_test_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
@DBUS_GLIB_CFLAGS@
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
unit_tests += unit/test-sailfish_cell_info_dbus
unit_test_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_cell_info_dbus_OBJECTS)
unit_tests += unit/test-cell-info-dbus
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
unit/fake_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
src/storage.c src/watchlist.c src/log.c
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
unit_test_sim_info_SOURCES = unit/test-sim-info.c unit/fake_watch.c \
src/sim-info.c src/storage.c src/watchlist.c src/log.c
unit_test_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
-DSTORAGEDIR='"/tmp/ofono"'
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
unit_tests += unit/test-sailfish_sim_info
unit_test_sim_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sim_info_OBJECTS)
unit_tests += unit/test-sim-info
unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
unit_test_sim_info_dbus_SOURCES = unit/test-sim-info-dbus.c \
unit/test-dbus.c unit/fake_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
src/sim-info.c src/sim-info-dbus.c \
gdbus/object.c \
src/dbus.c src/storage.c src/watchlist.c src/log.c
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
unit_test_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"'
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
unit_tests += unit/test-sailfish_sim_info_dbus
unit_test_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sim_info_dbus_OBJECTS)
unit_tests += unit/test-sim-info-dbus
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
unit/fake_watch.c \
plugins/sailfish_manager/sailfish_manager.c \
plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_sim_info.c \
unit_test_slot_manager_SOURCES = unit/test-slot-manager.c unit/fake_watch.c \
src/slot-manager.c src/cell-info.c src/sim-info.c \
src/storage.c src/log.c
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
unit_test_slot_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-DSTORAGEDIR='"/tmp/ofono"'
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
unit_tests += unit/test-sailfish_manager
unit_test_slot_manager_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_slot_manager_OBJECTS)
unit_tests += unit/test-slot-manager
unit_test_watch_SOURCES = unit/test-watch.c src/watch.c \
src/log.c src/watchlist.c
@@ -1031,15 +970,6 @@ unit_test_watch_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_watch_OBJECTS)
unit_tests += unit/test-watch
endif
unit_test_config_SOURCES = unit/test-config.c drivers/ril/ril_util.c \
src/config.c src/log.c
unit_test_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_config_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_config_OBJECTS)
unit_tests += unit/test-config
if SAILFISH_ACCESS
unit_test_sailfish_access_SOURCES = unit/test-sailfish_access.c \
plugins/sailfish_access.c src/dbus-access.c src/log.c
@@ -1057,38 +987,6 @@ unit_objects += $(unit_test_dbus_access_OBJECTS)
unit_tests += unit/test-dbus-access
if RILMODEM
if SAILFISH_RILMODEM
unit_test_ril_config_SOURCES = unit/test-ril_config.c drivers/ril/ril_util.c \
drivers/ril/ril_config.c src/log.c
unit_test_ril_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_config_OBJECTS)
unit_tests += unit/test-ril_config
unit_test_ril_ecclist_SOURCES = unit/test-ril_ecclist.c \
drivers/ril/ril_ecclist.c src/log.c
unit_test_ril_ecclist_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_ecclist_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_ecclist_OBJECTS)
unit_tests += unit/test-ril_ecclist
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
src/log.c
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_util_OBJECTS)
unit_tests += unit/test-ril_util
unit_test_ril_vendor_SOURCES = unit/test-ril_vendor.c unit/fake_watch.c \
drivers/ril/ril_vendor.c drivers/ril/ril_vendor_mtk.c \
drivers/ril/ril_util.c src/log.c
unit_test_ril_vendor_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_vendor_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_vendor_OBJECTS)
unit_tests += unit/test-ril_vendor
else
unit_tests += unit/test-rilmodem-cs \
unit/test-rilmodem-cs \
unit/test-rilmodem-sms \
@@ -1096,7 +994,6 @@ unit_tests += unit/test-rilmodem-cs \
unit/test-rilmodem-gprs
endif
endif
if ELL
if MBIMMODEM
@@ -1164,6 +1061,14 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_caif_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_caif_OBJECTS)
unit_test_dbus_clients_SOURCES = unit/test-dbus-clients.c unit/test-dbus.c \
src/dbus-clients.c gdbus/object.c \
src/dbus.c src/log.c
unit_test_dbus_clients_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_dbus_clients_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_dbus_clients_OBJECTS)
unit_tests += unit/test-dbus-clients
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
src/dbus-queue.c gdbus/object.c \
src/dbus.c src/log.c

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(ofono, 1.23)
AC_INIT(ofono, 1.24)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)
@@ -177,33 +177,17 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
[enable_rilmodem=${enableval}])
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
[enable Sailfish RIL modem]),
[enable_sailfish_rilmodem=${enableval}],
[enable_sailfish_rilmodem="no"])
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
AC_ARG_ENABLE(extra-modems,
AC_HELP_STRING([--enable-extra-modems],
[enable modems not used by Sailfish OS]),
[enable_extra_modems=${enableval}])
AM_CONDITIONAL(EXTRA_MODEMS, test "${enable_extra_modems}" = "yes")
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.35, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.35 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.49, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.49 is required))
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
LIBS="$LIBS $GLIBUTIL_LIBS"
if (test "${enable_sailfish_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.38, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.38 is required))
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.6, dummy=yes,
AC_MSG_ERROR(libmce-glib >= 1.0.6 is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
enable_sailfish_manager=yes
fi
AC_ARG_ENABLE(sailfish-manager,
AC_HELP_STRING([--enable-sailfish-manager],
[enable Sailfish OS modem manager plugin]),
[enable_sailfish_manager=${enableval}])
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
AC_MSG_ERROR(dbus-glib is required by unit tests))
AC_SUBST(DBUS_GLIB_CFLAGS)

View File

@@ -278,6 +278,13 @@ Properties boolean Active [readwrite]
via this proxy. All other values are left
out in this case.
array{string} ProxyCSCF [readonly, optional]
Holds the list of P-CSCF (SIP proxy) for this
context. Only used by IMS connections.
This is a Sailfish OS specific extension.
dict IPv6.Settings [readonly, optional]
Holds all the IPv6 network settings
@@ -304,6 +311,13 @@ Properties boolean Active [readwrite]
Holds the gateway IP for this connection.
array{string} ProxyCSCF [readonly, optional]
Holds the list of P-CSCF (SIP proxy) for this
context. Only used by IMS connections.
This is a Sailfish OS specific extension.
string MessageProxy [readwrite, MMS only]
Holds the MMS Proxy setting.

View File

@@ -48,6 +48,51 @@ struct cbs_data {
unsigned int vendor;
};
static void at_xmm_etw_sec_notify(GAtResult *result, gpointer user_data)
{
struct ofono_cbs *cbs = user_data;
const char *hexpdu;
int pdulen;
GAtResultIter iter;
unsigned char pdu[88];
long hexpdulen;
DBG("");
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+XETWSECWARN:"))
return;
if (!g_at_result_iter_next_number(&iter, &pdulen))
return;
if (pdulen != 88) {
ofono_error("Got a CBM message with invalid PDU size!");
return;
}
hexpdu = g_at_result_pdu(result);
if (hexpdu == NULL) {
ofono_error("Got a CBM, but no PDU. Are we in text mode?");
return;
}
DBG("Got new Cell Broadcast via XETWSECWARN: %s, %d", hexpdu, pdulen);
if (decode_hex_own_buf(hexpdu, -1, &hexpdulen, 0, pdu) == NULL) {
ofono_error("Unable to hex-decode the PDU");
return;
}
if (hexpdulen != pdulen) {
ofono_error("hexpdu length not equal to reported pdu length");
return;
}
ofono_cbs_notify(cbs, pdu, pdulen);
}
static void at_cbm_notify(GAtResult *result, gpointer user_data)
{
struct ofono_cbs *cbs = user_data;
@@ -124,6 +169,10 @@ static void at_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
g_at_chat_send(data->chat, "AT+CSCB=0", none_prefix,
NULL, NULL, NULL);
break;
case OFONO_VENDOR_XMM:
g_at_chat_send(data->chat, "AT+XETWNTFYSTART=2", none_prefix,
NULL, NULL, NULL);
break;
default:
break;
}
@@ -151,6 +200,10 @@ static void at_cbs_clear_topics(struct ofono_cbs *cbs,
DBG("");
if (data->vendor == OFONO_VENDOR_XMM)
g_at_chat_send(data->chat, "AT+XETWNTFYSTOP=2", none_prefix,
NULL, NULL, NULL);
if (g_at_chat_send(data->chat, "AT+CSCB=0", none_prefix,
at_cscb_set_cb, cbd, g_free) > 0)
return;
@@ -175,6 +228,10 @@ static void at_cbs_register(gboolean ok, GAtResult *result, gpointer user)
*/
g_at_chat_register(data->chat, "+CBM:", at_cbm_notify, TRUE, cbs, NULL);
if (data->vendor == OFONO_VENDOR_XMM)
g_at_chat_register(data->chat, "+XETWSECWARN:",
at_xmm_etw_sec_notify, TRUE, cbs, NULL);
ofono_cbs_register(cbs);
}
@@ -223,6 +280,13 @@ static int at_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
ofono_cbs_set_data(cbs, data);
if (vendor == OFONO_VENDOR_XMM) {
g_at_chat_send(data->chat, "AT+XCMAS=1", cscb_prefix,
NULL, NULL, NULL);
g_at_chat_send(data->chat, "AT+XETWCFG=1,1,0,0; ", none_prefix,
NULL, NULL, NULL);
}
g_at_chat_send(data->chat, "AT+CSCB=?", cscb_prefix,
at_cscb_support_cb, cbs, NULL);

View File

@@ -91,7 +91,7 @@ static gboolean lte_delayed_register(gpointer user_data)
return FALSE;
}
static int at_lte_probe(struct ofono_lte *lte, void *data)
static int at_lte_probe(struct ofono_lte *lte, unsigned int vendor, void *data)
{
GAtChat *chat = data;
struct lte_driver_data *ldd;

View File

@@ -48,6 +48,7 @@ static const char *cops_prefix[] = { "+COPS:", NULL };
static const char *csq_prefix[] = { "+CSQ:", NULL };
static const char *cind_prefix[] = { "+CIND:", NULL };
static const char *cmer_prefix[] = { "+CMER:", NULL };
static const char *smoni_prefix[] = { "^SMONI:", NULL };
static const char *zpas_prefix[] = { "+ZPAS:", NULL };
static const char *option_tech_prefix[] = { "_OCTI:", "_OUWCTI:", NULL };
@@ -178,6 +179,31 @@ static int option_parse_tech(GAtResult *result)
return tech;
}
static int cinterion_parse_tech(GAtResult *result)
{
int tech = -1;
GAtResultIter iter;
const char *technology;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "^SMONI: "))
return tech;
if (!g_at_result_iter_next_unquoted_string(&iter, &technology))
return tech;
if (strcmp(technology, "2G") == 0) {
tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
} else if (strcmp(technology, "3G") == 0) {
tech = ACCESS_TECHNOLOGY_UTRAN;
} else if (strcmp(technology, "4G") == 0) {
tech = ACCESS_TECHNOLOGY_EUTRAN;
}
return tech;
}
static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -205,6 +231,18 @@ static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
cb(&error, status, lac, ci, tech, cbd->data);
}
static void cinterion_query_tech_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct tech_query *tq = user_data;
int tech;
tech = cinterion_parse_tech(result);
ofono_netreg_status_notify(tq->netreg,
tq->status, tq->lac, tq->ci, tech);
}
static void zte_tech_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -1518,6 +1556,12 @@ static void creg_notify(GAtResult *result, gpointer user_data)
option_query_tech_cb, tq, g_free) > 0)
return;
break;
case OFONO_VENDOR_CINTERION:
if (g_at_chat_send(nd->chat, "AT^SMONI",
smoni_prefix,
cinterion_query_tech_cb, tq, g_free) > 0)
return;
break;
}
g_free(tq);

View File

@@ -1359,12 +1359,12 @@ static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
char buf[64];
int ret;
cbd->user = sd;
cbd->user = sim;
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd);
ret = g_at_chat_send(sd->chat, buf, none_prefix,
at_pin_send_cb, cbd, NULL);
at_pin_send_cb, cbd, g_free);
memset(buf, 0, sizeof(buf));

View File

@@ -104,7 +104,7 @@ static void at_csca_set(struct ofono_sms *sms,
{
struct sms_data *data = ofono_sms_get_data(sms);
struct cb_data *cbd = cb_data_new(cb, user_data);
char buf[64];
char buf[128];
snprintf(buf, sizeof(buf), "AT+CSCA=\"%s\",%d", sca->number, sca->type);

View File

@@ -1120,6 +1120,7 @@ static int at_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
switch (vd->vendor) {
case OFONO_VENDOR_QUALCOMM_MSM:
case OFONO_VENDOR_SIMCOM:
g_at_chat_send(vd->chat, "AT+COLP=0", NULL, NULL, NULL, NULL);
break;
default:

View File

@@ -129,6 +129,7 @@ static void get_ids_cb(struct qmi_result *result, void *user_data)
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
/* Telit qmi modems return a "0" string when ESN is not available. */
if (!str || strcmp(str, "0") == 0) {
qmi_free(str);
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
if (!str) {
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);

View File

@@ -212,7 +212,8 @@ error:
ofono_lte_register(lte);
}
static int qmimodem_lte_probe(struct ofono_lte *lte, void *data)
static int qmimodem_lte_probe(struct ofono_lte *lte,
unsigned int vendor, void *data)
{
struct qmi_device *device = data;
struct lte_data *ldd;

View File

@@ -47,6 +47,13 @@ struct discovery {
qmi_destroy_func_t destroy;
};
struct qmi_version {
uint8_t type;
uint16_t major;
uint16_t minor;
const char *name;
};
struct qmi_device {
int ref_count;
int fd;
@@ -80,7 +87,6 @@ struct qmi_device {
struct qmi_service {
int ref_count;
struct qmi_device *device;
bool shared;
uint8_t type;
uint16_t major;
uint16_t minor;
@@ -161,25 +167,25 @@ void qmi_free(void *ptr)
static struct qmi_request *__request_alloc(uint8_t service,
uint8_t client, uint16_t message,
uint16_t headroom, const void *data,
const void *data,
uint16_t length, qmi_message_func_t func,
void *user_data, void **head)
void *user_data)
{
struct qmi_request *req;
struct qmi_mux_hdr *hdr;
struct qmi_message_hdr *msg;
uint16_t headroom;
req = g_try_new0(struct qmi_request, 1);
if (!req)
return NULL;
req = g_new0(struct qmi_request, 1);
if (service == QMI_SERVICE_CONTROL)
headroom = QMI_CONTROL_HDR_SIZE;
else
headroom = QMI_SERVICE_HDR_SIZE;
req->len = QMI_MUX_HDR_SIZE + headroom + QMI_MESSAGE_HDR_SIZE + length;
req->buf = g_try_malloc(req->len);
if (!req->buf) {
g_free(req);
return NULL;
}
req->buf = g_malloc(req->len);
req->client = client;
@@ -203,8 +209,6 @@ static struct qmi_request *__request_alloc(uint8_t service,
req->callback = func;
req->user_data = user_data;
*head = req->buf + QMI_MUX_HDR_SIZE;
return req;
}
@@ -256,9 +260,6 @@ static gboolean __service_compare_shared(gpointer key, gpointer value,
struct qmi_service *service = value;
uint8_t type = GPOINTER_TO_UINT(user_data);
if (!service->shared)
return FALSE;
if (service->type == type)
return TRUE;
@@ -695,14 +696,37 @@ static void wakeup_writer(struct qmi_device *device)
can_write_data, device, write_watch_destroy);
}
static void __request_submit(struct qmi_device *device,
struct qmi_request *req, uint16_t transaction)
static uint16_t __request_submit(struct qmi_device *device,
struct qmi_request *req)
{
req->tid = transaction;
struct qmi_mux_hdr *mux;
mux = req->buf;
if (mux->service == QMI_SERVICE_CONTROL) {
struct qmi_control_hdr *hdr;
hdr = req->buf + QMI_MUX_HDR_SIZE;
hdr->type = 0x00;
hdr->transaction = device->next_control_tid++;
if (device->next_control_tid == 0)
device->next_control_tid = 1;
req->tid = hdr->transaction;
} else {
struct qmi_service_hdr *hdr;
hdr = req->buf + QMI_MUX_HDR_SIZE;
hdr->type = 0x00;
hdr->transaction = device->next_service_tid++;
if (device->next_service_tid < 256)
device->next_service_tid = 256;
req->tid = hdr->transaction;
}
g_queue_push_tail(device->req_queue, req);
wakeup_writer(device);
return req->tid;
}
static void service_notify(gpointer key, gpointer value, gpointer user_data)
@@ -961,6 +985,9 @@ struct qmi_device *qmi_device_new(int fd)
device->service_list = g_hash_table_new_full(g_direct_hash,
g_direct_equal, NULL, service_destroy);
device->next_control_tid = 1;
device->next_service_tid = 256;
return device;
}
@@ -1078,6 +1105,41 @@ static const void *tlv_get(const void *data, uint16_t size,
return NULL;
}
bool qmi_device_get_service_version(struct qmi_device *device, uint8_t type,
uint16_t *major, uint16_t *minor)
{
struct qmi_version *info;
int i;
for (i = 0, info = device->version_list;
i < device->version_count;
i++, info++) {
if (info->type == type) {
*major = info->major;
*minor = info->minor;
return true;
}
}
return false;
}
bool qmi_device_has_service(struct qmi_device *device, uint8_t type)
{
struct qmi_version *info;
int i;
for (i = 0, info = device->version_list;
i < device->version_count;
i++, info++) {
if (info->type == type) {
return true;
}
}
return false;
}
struct discover_data {
struct discovery super;
struct qmi_device *device;
@@ -1177,7 +1239,7 @@ done:
device->version_count = count;
if (data->func)
data->func(count, list, data->user_data);
data->func(data->user_data);
__qmi_device_discovery_complete(data->device, &data->super);
}
@@ -1213,8 +1275,7 @@ static gboolean discover_reply(gpointer user_data)
}
if (data->func)
data->func(device->version_count,
device->version_list, data->user_data);
data->func(data->user_data);
__qmi_device_discovery_complete(data->device, &data->super);
__request_free(req, NULL);
@@ -1227,7 +1288,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
{
struct discover_data *data;
struct qmi_request *req;
struct qmi_control_hdr *hdr;
uint8_t tid;
if (!device)
return false;
@@ -1251,21 +1312,12 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
}
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_GET_VERSION_INFO, QMI_CONTROL_HDR_SIZE,
NULL, 0, discover_callback, data, (void **) &hdr);
if (!req) {
g_free(data);
return false;
}
QMI_CTL_GET_VERSION_INFO,
NULL, 0, discover_callback, data);
if (device->next_control_tid < 1)
device->next_control_tid = 1;
tid = __request_submit(device, req);
hdr->type = 0x00;
hdr->transaction = device->next_control_tid++;
data->tid = hdr->transaction;
__request_submit(device, req, hdr->transaction);
data->tid = tid;
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
__qmi_device_discovery_started(device, &data->super);
@@ -1279,24 +1331,13 @@ static void release_client(struct qmi_device *device,
{
unsigned char release_req[] = { 0x01, 0x02, 0x00, type, client_id };
struct qmi_request *req;
struct qmi_control_hdr *hdr;
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_RELEASE_CLIENT_ID, QMI_CONTROL_HDR_SIZE,
QMI_CTL_RELEASE_CLIENT_ID,
release_req, sizeof(release_req),
func, user_data, (void **) &hdr);
if (!req) {
func(0x0000, 0x0000, NULL, user_data);
return;
}
func, user_data);
if (device->next_control_tid < 1)
device->next_control_tid = 1;
hdr->type = 0x00;
hdr->transaction = device->next_control_tid++;
__request_submit(device, req, hdr->transaction);
__request_submit(device, req);
}
static void shutdown_destroy(gpointer user_data)
@@ -1374,7 +1415,6 @@ bool qmi_device_sync(struct qmi_device *device,
qmi_sync_func_t func, void *user_data)
{
struct qmi_request *req;
struct qmi_control_hdr *hdr;
struct sync_data *func_data;
if (!device)
@@ -1387,17 +1427,11 @@ bool qmi_device_sync(struct qmi_device *device,
func_data->user_data = user_data;
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_SYNC, QMI_CONTROL_HDR_SIZE,
QMI_CTL_SYNC,
NULL, 0,
qmi_device_sync_callback, func_data, (void **) &hdr);
qmi_device_sync_callback, func_data);
if (device->next_control_tid < 1)
device->next_control_tid = 1;
hdr->type = 0x00;
hdr->transaction = device->next_control_tid++;
__request_submit(device, req, hdr->transaction);
__request_submit(device, req);
return true;
}
@@ -1898,7 +1932,6 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
struct service_create_data {
struct discovery super;
struct qmi_device *device;
bool shared;
uint8_t type;
uint16_t major;
uint16_t minor;
@@ -1969,7 +2002,6 @@ static void service_create_callback(uint16_t message, uint16_t length,
service->ref_count = 1;
service->device = data->device;
service->shared = data->shared;
service->type = data->type;
service->major = data->major;
@@ -1992,100 +2024,52 @@ done:
__qmi_device_discovery_complete(data->device, &data->super);
}
static void service_create_discover(uint8_t count,
const struct qmi_version *list, void *user_data)
{
struct service_create_data *data = user_data;
struct qmi_device *device = data->device;
struct qmi_request *req;
struct qmi_control_hdr *hdr;
unsigned char client_req[] = { 0x01, 0x01, 0x00, data->type };
unsigned int i;
__debug_device(device, "service create [type=%d]", data->type);
for (i = 0; i < count; i++) {
if (list[i].type == data->type) {
data->major = list[i].major;
data->minor = list[i].minor;
break;
}
}
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_GET_CLIENT_ID, QMI_CONTROL_HDR_SIZE,
client_req, sizeof(client_req),
service_create_callback, data, (void **) &hdr);
if (!req) {
if (data->timeout > 0)
g_source_remove(data->timeout);
data->timeout = g_timeout_add_seconds(0,
service_create_reply, data);
__qmi_device_discovery_started(device, &data->super);
return;
}
if (device->next_control_tid < 1)
device->next_control_tid = 1;
hdr->type = 0x00;
hdr->transaction = device->next_control_tid++;
__request_submit(device, req, hdr->transaction);
}
static bool service_create(struct qmi_device *device, bool shared,
static bool service_create(struct qmi_device *device,
uint8_t type, qmi_create_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
struct service_create_data *data;
unsigned char client_req[] = { 0x01, 0x01, 0x00, type };
struct qmi_request *req;
int i;
data = g_try_new0(struct service_create_data, 1);
if (!data)
return false;
if (!device->version_list)
return false;
data->super.destroy = service_create_data_free;
data->device = device;
data->shared = shared;
data->type = type;
data->func = func;
data->user_data = user_data;
data->destroy = destroy;
if (device->version_list) {
service_create_discover(device->version_count,
device->version_list, data);
goto done;
__debug_device(device, "service create [type=%d]", type);
for (i = 0; i < device->version_count; i++) {
if (device->version_list[i].type == data->type) {
data->major = device->version_list[i].major;
data->minor = device->version_list[i].minor;
break;
}
}
if (qmi_device_discover(device, service_create_discover, data, NULL))
goto done;
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_GET_CLIENT_ID,
client_req, sizeof(client_req),
service_create_callback, data);
g_free(data);
__request_submit(device, req);
return false;
done:
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
__qmi_device_discovery_started(device, &data->super);
return true;
}
bool qmi_service_create(struct qmi_device *device,
uint8_t type, qmi_create_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
if (!device || !func)
return false;
if (type == QMI_SERVICE_CONTROL)
return false;
return service_create(device, false, type, func, user_data, destroy);
}
struct service_create_shared_data {
struct discovery super;
struct qmi_service *service;
@@ -2161,7 +2145,15 @@ bool qmi_service_create_shared(struct qmi_device *device,
return 0;
}
return service_create(device, true, type, func, user_data, destroy);
return service_create(device, type, func, user_data, destroy);
}
bool qmi_service_create(struct qmi_device *device,
uint8_t type, qmi_create_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
return qmi_service_create_shared(device, type, func,
user_data, destroy);
}
static void service_release_callback(uint16_t message, uint16_t length,
@@ -2238,8 +2230,6 @@ bool qmi_service_get_version(struct qmi_service *service,
}
struct service_send_data {
struct qmi_service *service;
struct qmi_param *param;
qmi_result_func_t func;
void *user_data;
qmi_destroy_func_t destroy;
@@ -2250,8 +2240,6 @@ static void service_send_free(struct service_send_data *data)
if (data->destroy)
data->destroy(data->user_data);
qmi_param_free(data->param);
g_free(data);
}
@@ -2292,7 +2280,7 @@ uint16_t qmi_service_send(struct qmi_service *service,
struct qmi_device *device;
struct service_send_data *data;
struct qmi_request *req;
struct qmi_service_hdr *hdr;
uint16_t tid;
if (!service)
return 0;
@@ -2308,31 +2296,21 @@ uint16_t qmi_service_send(struct qmi_service *service,
if (!data)
return 0;
data->service = service;
data->param = param;
data->func = func;
data->user_data = user_data;
data->destroy = destroy;
req = __request_alloc(service->type, service->client_id,
message, QMI_SERVICE_HDR_SIZE,
data->param ? data->param->data : NULL,
data->param ? data->param->length : 0,
service_send_callback, data, (void **) &hdr);
if (!req) {
g_free(data);
return 0;
}
message,
param ? param->data : NULL,
param ? param->length : 0,
service_send_callback, data);
if (device->next_service_tid < 256)
device->next_service_tid = 256;
qmi_param_free(param);
hdr->type = 0x00;
hdr->transaction = device->next_service_tid++;
tid = __request_submit(device, req);
__request_submit(device, req, hdr->transaction);
return hdr->transaction;
return tid;
}
bool qmi_service_cancel(struct qmi_service *service, uint16_t id)

View File

@@ -61,13 +61,6 @@ enum qmi_device_expected_data_format {
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP,
};
struct qmi_version {
uint8_t type;
uint16_t major;
uint16_t minor;
const char *name;
};
void qmi_free(void *ptr);
typedef void (*qmi_destroy_func_t)(void *user_data);
@@ -78,8 +71,7 @@ struct qmi_device;
typedef void (*qmi_debug_func_t)(const char *str, void *user_data);
typedef void (*qmi_sync_func_t)(void *user_data);
typedef void (*qmi_shutdown_func_t)(void *user_data);
typedef void (*qmi_discover_func_t)(uint8_t count,
const struct qmi_version *list, void *user_data);
typedef void (*qmi_discover_func_t)(void *user_data);
struct qmi_device *qmi_device_new(int fd);
@@ -96,6 +88,10 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
void *user_data, qmi_destroy_func_t destroy);
bool qmi_device_has_service(struct qmi_device *device, uint8_t type);
bool qmi_device_get_service_version(struct qmi_device *device, uint8_t type,
uint16_t *major, uint16_t *minor);
bool qmi_device_sync(struct qmi_device *device,
qmi_sync_func_t func, void *user_data);
bool qmi_device_is_sync_supported(struct qmi_device *device);

View File

@@ -493,8 +493,15 @@ static bool get_card_status(const struct qmi_uim_slot_info *slot,
case 0x03: /* PUK1 or PUK for UPIN is required */
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
break;
case 0x00: /* Unknown */
case 0x01: /* Detected */
case 0x04: /* Personalization state must be checked. */
/* This is temporary, we could retry and get another result */
case 0x05: /* PIN1 blocked */
case 0x06: /* Illegal */
/*
* This could be temporary, we should retry and
* expect another result
*/
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
need_retry = true;
break;
@@ -557,7 +564,7 @@ static enum get_card_status_result handle_get_card_status_result(
index = GUINT16_FROM_LE(status->index_gw_pri);
if ((index & 0xff) == i && (index >> 8) == n) {
if ((index & 0xff) == n && (index >> 8) == i) {
if (get_card_status(slot, info1, info2,
sim_stat))
res = GET_CARD_STATUS_RESULT_TEMP_ERROR;
@@ -595,20 +602,32 @@ static void query_passwd_state_cb(struct qmi_result *result,
struct sim_status sim_stat;
enum get_card_status_result res;
struct cb_data *retry_cbd;
unsigned int i;
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
sim_stat.retries[i] = -1;
res = handle_get_card_status_result(result, &sim_stat);
switch (res) {
case GET_CARD_STATUS_RESULT_OK:
DBG("passwd state %d", sim_stat.passwd_state);
data->retry_count = 0;
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, cbd->data);
if (sim_stat.passwd_state == OFONO_SIM_PASSWORD_INVALID) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
ofono_sim_inserted_notify(sim, FALSE);
} else
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state,
cbd->data);
break;
case GET_CARD_STATUS_RESULT_TEMP_ERROR:
data->retry_count++;
if (data->retry_count > MAX_RETRY_COUNT) {
DBG("Failed after %d attempts", data->retry_count);
DBG("Failed after %d attempts. Card state:%d",
data->retry_count,
sim_stat.card_state);
data->retry_count = 0;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
ofono_sim_inserted_notify(sim, FALSE);
} else {
DBG("Retry command");
retry_cbd = cb_data_new(cb, cbd->data);
@@ -622,6 +641,7 @@ static void query_passwd_state_cb(struct qmi_result *result,
DBG("Command failed");
data->retry_count = 0;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
ofono_sim_inserted_notify(sim, FALSE);
break;
}
}
@@ -650,9 +670,13 @@ static void query_pin_retries_cb(struct qmi_result *result, void *user_data)
struct cb_data *cbd = user_data;
ofono_sim_pin_retries_cb_t cb = cbd->cb;
struct sim_status sim_stat;
unsigned int i;
DBG("");
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
sim_stat.retries[i] = -1;
if (handle_get_card_status_result(result, &sim_stat) !=
GET_CARD_STATUS_RESULT_OK) {
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);

View File

@@ -251,6 +251,7 @@ static void qmi_ussd_request(struct ofono_ussd *ussd, int dcs,
qmi_ussd->dcs = QMI_USSD_DCS_ASCII;
qmi_ussd->length = len;
memcpy(qmi_ussd->data, utf8, utf8_len);
g_free(utf8);
param = qmi_param_new();
if (param == NULL)
@@ -265,7 +266,6 @@ static void qmi_ussd_request(struct ofono_ussd *ussd, int dcs,
qmi_param_free(param);
error:
g_free(utf8);
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}

View File

@@ -1,280 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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_card.h"
#include "ril_util.h"
#include "ril_log.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_SET_STRING_COUNT 5
#define RIL_SET_PW_STRING_COUNT 3
struct ril_call_barring {
struct ril_sim_card *card;
GRilIoQueue *q;
guint timer_id;
};
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;
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.
*/
req = grilio_request_array_utf8_new(4, lock, "", cls_textual,
ril_sim_card_app_aid(bd->card));
ril_call_barring_submit_request(bd, req,
RIL_REQUEST_QUERY_FACILITY_LOCK,
ril_call_barring_query_cb, cb, data);
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, ril_sim_card_app_aid(bd->card));
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->card = ril_sim_card_ref(modem->sim_card);
bd->q = grilio_queue_new(ril_modem_io(modem));
bd->timer_id = g_idle_add(ril_call_barring_register, b);
ofono_call_barring_set_data(b, bd);
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);
}
ril_sim_card_unref(bd->card);
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

@@ -1,274 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.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

@@ -1,308 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.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

@@ -1,150 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.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:
*/

View File

@@ -1,246 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 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 <gutil_strv.h>
struct ril_cbs {
struct ofono_cbs *cbs;
GRilIoChannel *io;
GRilIoQueue *q;
char *log_prefix;
guint register_id;
gulong event_id;
};
struct ril_cbs_cbd {
struct ril_cbs *cd;
ofono_cbs_set_cb_t cb;
gpointer data;
};
#define RIL_CBS_CHECK_RETRY_MS 1000
#define RIL_CBS_CHECK_RETRY_COUNT 30
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
#define ril_cbs_cbd_free g_free
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
ofono_cbs_set_cb_t cb, void *data)
{
struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
cbd->cd = cd;
cbd->cb = cb;
cbd->data = data;
return cbd;
}
static gboolean ril_cbs_retry(GRilIoRequest *request, int ril_status,
const void *resp_data, guint resp_len, void *user_data)
{
return ril_status == RIL_E_INVALID_STATE;
}
static void ril_cbs_request_activation(struct ril_cbs *cd,
gboolean activate, GRilIoChannelResponseFunc response,
GDestroyNotify destroy, void* user_data)
{
GRilIoRequest* req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, activate ? 0 :1);
DBG_(cd, "%sactivating CB", activate ? "" : "de");
grilio_request_set_retry_func(req, ril_cbs_retry);
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
RIL_CBS_CHECK_RETRY_COUNT);
grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
response, destroy, user_data);
grilio_request_unref(req);
}
static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
GRilIoChannelResponseFunc response,
GDestroyNotify destroy, void* user_data)
{
char **list = topics ? g_strsplit(topics, ",", 0) : NULL;
int i, n = gutil_strv_length(list);
GRilIoRequest* req = grilio_request_new();
grilio_request_append_int32(req, n);
for (i = 0; i < n; i++) {
const char *entry = list[i];
const char *delim = strchr(entry, '-');
int from, to;
if (delim) {
char **range = g_strsplit(topics, "-", 0);
from = atoi(range[0]);
to = atoi(range[1]);
g_strfreev(range);
} else {
from = to = atoi(entry);
}
grilio_request_append_int32(req, from);
grilio_request_append_int32(req, to);
grilio_request_append_int32(req, 0);
grilio_request_append_int32(req, 0xff);
grilio_request_append_int32(req, 1);
}
DBG_(cd, "configuring CB");
grilio_request_set_retry_func(req, ril_cbs_retry);
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
RIL_CBS_CHECK_RETRY_COUNT);
grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
response, destroy, user_data);
grilio_request_unref(req);
g_strfreev(list);
}
static void ril_cbs_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_cbs_cbd *cbd = user_data;
if (cbd->cb) {
struct ofono_error error;
if (ril_status == RIL_E_SUCCESS) {
cbd->cb(ril_error_ok(&error), cbd->data);
} else {
cbd->cb(ril_error_failure(&error), cbd->data);
}
}
}
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
ofono_cbs_set_cb_t cb, void *data)
{
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
DBG_(cd, "%s", topics);
ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
ril_cbs_cbd_new(cd, cb, data));
}
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
ofono_cbs_set_cb_t cb, void *data)
{
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
DBG_(cd, "");
ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
ril_cbs_cbd_new(cd, cb, data));
}
static void ril_cbs_notify(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_cbs *cd = user_data;
GRilIoParser rilp;
guint32 pdu_len;
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &pdu_len)) {
const void* pdu = grilio_parser_get_bytes(&rilp, pdu_len);
/*
* By default assume that it's a length followed by the
* binary PDU data.
*/
if (pdu && grilio_parser_bytes_remaining(&rilp) < 4) {
DBG_(cd, "%u bytes", pdu_len);
ofono_cbs_notify(cd->cbs, pdu, pdu_len);
} else {
/*
* But I've seen cell broadcasts arriving without
* the length, simply as a blob.
*/
ofono_cbs_notify(cd->cbs, data, len);
}
}
}
static gboolean ril_cbs_register(void *user_data)
{
struct ril_cbs *cd = user_data;
DBG_(cd, "registering for CB");
cd->register_id = 0;
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
ofono_cbs_register(cd->cbs);
return G_SOURCE_REMOVE;
}
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);
ofono_cbs_set_data(cbs, cd);
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
cd->cbs = cbs;
DBG_(cd, "");
cd->io = grilio_channel_ref(ril_modem_io(modem));
cd->q = grilio_queue_new(cd->io);
cd->register_id = g_idle_add(ril_cbs_register, cd);
return 0;
}
static void ril_cbs_remove(struct ofono_cbs *cbs)
{
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
DBG_(cd, "");
if (cd->register_id) {
g_source_remove(cd->register_id);
}
ofono_cbs_set_data(cbs, NULL);
grilio_channel_remove_handler(cd->io, cd->event_id);
grilio_channel_unref(cd->io);
grilio_queue_cancel_all(cd->q, FALSE);
grilio_queue_unref(cd->q);
g_free(cd->log_prefix);
g_free(cd);
}
const struct ofono_cbs_driver ril_cbs_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_cbs_probe,
.remove = ril_cbs_remove,
.set_topics = ril_cbs_set_topics,
.clear_topics = ril_cbs_clear_topics
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,584 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* 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_log.h"
#include <grilio_channel.h>
#include <grilio_request.h>
#include <grilio_parser.h>
#include <gutil_idlepool.h>
#include <gutil_misc.h>
#define DEFAULT_UPDATE_RATE_MS (10000) /* 10 sec */
#define MAX_RETRIES (5)
typedef GObjectClass RilCellInfoClass;
typedef struct ril_cell_info RilCellInfo;
struct ril_cell_info {
GObject object;
struct sailfish_cell_info info;
GRilIoChannel *io;
struct ril_radio *radio;
struct ril_sim_card *sim_card;
gulong radio_state_event_id;
gulong sim_status_event_id;
gboolean sim_card_ready;
int update_rate_ms;
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)->log_prefix, ##args)
static inline void ril_cell_free(struct sailfish_cell *cell)
{
g_slice_free(struct sailfish_cell, cell);
}
static void ril_cell_free1(gpointer cell)
{
ril_cell_free(cell);
}
static const char *ril_cell_info_int_format(int value, const char *format)
{
if (value == SAILFISH_CELL_INVALID_VALUE) {
return "";
} else {
static GUtilIdlePool *ril_cell_info_pool = NULL;
GUtilIdlePool *pool = gutil_idle_pool_get(&ril_cell_info_pool);
char *str = g_strdup_printf(format, value);
gutil_idle_pool_add(pool, str, g_free);
return str;
}
}
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
{
while (l1 && l2) {
if (memcmp(l1->data, l2->data, sizeof(struct sailfish_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->info.cells, l)) {
g_slist_free_full(self->info.cells, ril_cell_free1);
self->info.cells = l;
g_signal_emit(self, ril_cell_info_signals
[SIGNAL_CELLS_CHANGED], 0);
} else {
g_slist_free_full(l, ril_cell_free1);
}
}
static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
guint version, gboolean registered)
{
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
/* Optional RIL_CellIdentityGsm_v12 part */
gsm->arfcn = SAILFISH_CELL_INVALID_VALUE;
gsm->bsic = SAILFISH_CELL_INVALID_VALUE;
/* Optional RIL_GSM_SignalStrength_v12 part */
gsm->timingAdvance = SAILFISH_CELL_INVALID_VALUE;
/* RIL_CellIdentityGsm */
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
grilio_parser_get_int32(rilp, &gsm->mnc) &&
grilio_parser_get_int32(rilp, &gsm->lac) &&
grilio_parser_get_int32(rilp, &gsm->cid) &&
(version < 12 || /* RIL_CellIdentityGsm_v12 part */
(grilio_parser_get_int32(rilp, &gsm->arfcn) &&
grilio_parser_get_int32(rilp, &gsm->bsic))) &&
/* RIL_GW_SignalStrength */
grilio_parser_get_int32(rilp, &gsm->signalStrength) &&
grilio_parser_get_int32(rilp, &gsm->bitErrorRate) &&
(version < 12 || /* RIL_GSM_SignalStrength_v12 part */
grilio_parser_get_int32(rilp, &gsm->timingAdvance))) {
DBG("[gsm] reg=%d%s%s%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(gsm->mcc, ",mcc=%d"),
ril_cell_info_int_format(gsm->mnc, ",mnc=%d"),
ril_cell_info_int_format(gsm->lac, ",lac=%d"),
ril_cell_info_int_format(gsm->cid, ",cid=%d"),
ril_cell_info_int_format(gsm->arfcn, ",arfcn=%d"),
ril_cell_info_int_format(gsm->bsic, ",bsic=%d"),
ril_cell_info_int_format(gsm->signalStrength,
",strength=%d"),
ril_cell_info_int_format(gsm->bitErrorRate, ",err=%d"),
ril_cell_info_int_format(gsm->timingAdvance, ",t=%d"));
cell->type = SAILFISH_CELL_TYPE_GSM;
cell->registered = registered;
return cell;
}
ofono_error("failed to parse GSM cell info");
ril_cell_free(cell);
return NULL;
}
static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
guint version, gboolean registered)
{
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
/* Optional RIL_CellIdentityWcdma_v12 part */
wcdma->uarfcn = SAILFISH_CELL_INVALID_VALUE;
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
grilio_parser_get_int32(rilp, &wcdma->lac) &&
grilio_parser_get_int32(rilp, &wcdma->cid) &&
grilio_parser_get_int32(rilp, &wcdma->psc) &&
(version < 12 || /* RIL_CellIdentityWcdma_v12 part */
grilio_parser_get_int32(rilp, &wcdma->uarfcn)) &&
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
DBG("[wcdma] reg=%d%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(wcdma->mcc, ",mcc=%d"),
ril_cell_info_int_format(wcdma->mnc, ",mnc=%d"),
ril_cell_info_int_format(wcdma->lac, ",lac=%d"),
ril_cell_info_int_format(wcdma->cid, ",cid=%d"),
ril_cell_info_int_format(wcdma->psc, ",psc=%d"),
ril_cell_info_int_format(wcdma->signalStrength,
",strength=%d"),
ril_cell_info_int_format(wcdma->bitErrorRate,
",err=%d"));
cell->type = SAILFISH_CELL_TYPE_WCDMA;
cell->registered = registered;
return cell;
}
ofono_error("failed to parse WCDMA cell info");
ril_cell_free(cell);
return NULL;
}
static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
guint version, gboolean registered)
{
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
struct sailfish_cell_info_lte *lte = &cell->info.lte;
/* Optional RIL_CellIdentityLte_v12 part */
lte->earfcn = SAILFISH_CELL_INVALID_VALUE;
if (grilio_parser_get_int32(rilp, &lte->mcc) &&
grilio_parser_get_int32(rilp, &lte->mnc) &&
grilio_parser_get_int32(rilp, &lte->ci) &&
grilio_parser_get_int32(rilp, &lte->pci) &&
grilio_parser_get_int32(rilp, &lte->tac) &&
(version < 12 || /* RIL_CellIdentityLte_v12 part */
grilio_parser_get_int32(rilp, &lte->earfcn)) &&
grilio_parser_get_int32(rilp, &lte->signalStrength) &&
grilio_parser_get_int32(rilp, &lte->rsrp) &&
grilio_parser_get_int32(rilp, &lte->rsrq) &&
grilio_parser_get_int32(rilp, &lte->rssnr) &&
grilio_parser_get_int32(rilp, &lte->cqi) &&
grilio_parser_get_int32(rilp, &lte->timingAdvance)) {
DBG("[lte] reg=%d%s%s%s%s%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(lte->mcc, ",mcc=%d"),
ril_cell_info_int_format(lte->mnc, ",mnc=%d"),
ril_cell_info_int_format(lte->ci, ",ci=%d"),
ril_cell_info_int_format(lte->pci, ",pci=%d"),
ril_cell_info_int_format(lte->tac, ",tac=%d"),
ril_cell_info_int_format(lte->signalStrength,
",strength=%d"),
ril_cell_info_int_format(lte->rsrp, ",rsrp=%d"),
ril_cell_info_int_format(lte->rsrq, ",rsrq=%d"),
ril_cell_info_int_format(lte->rssnr, ",rssnr=%d"),
ril_cell_info_int_format(lte->cqi, ",cqi=%d"),
ril_cell_info_int_format(lte->timingAdvance, ",t=%d"));
cell->type = SAILFISH_CELL_TYPE_LTE;
cell->registered = registered;
return cell;
}
ofono_error("failed to parse LTE cell info");
ril_cell_free(cell);
return NULL;
}
static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
struct sailfish_cell **cell_ptr)
{
int type, reg;
if (grilio_parser_get_int32(rilp, &type) &&
grilio_parser_get_int32(rilp, &reg) &&
/* Skip timestamp */
grilio_parser_get_int32_array(rilp, NULL, 3)) {
int skip = 0;
struct sailfish_cell *cell = NULL;
/* Normalize the boolean value */
reg = (reg != FALSE);
switch (type) {
case RIL_CELL_INFO_TYPE_GSM:
cell = ril_cell_info_parse_cell_gsm(rilp, v, reg);
break;
case RIL_CELL_INFO_TYPE_WCDMA:
cell = ril_cell_info_parse_cell_wcdma(rilp, v, reg);
break;
case RIL_CELL_INFO_TYPE_LTE:
cell = ril_cell_info_parse_cell_lte(rilp, v, 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 TRUE;
}
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
*cell_ptr = NULL;
return TRUE;
}
}
*cell_ptr = NULL;
return FALSE;
}
static GSList *ril_cell_info_parse_list(guint v, 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 sailfish_cell *c;
DBG("%d cell(s):", n);
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
if (c) {
l = g_slist_insert_sorted(l, c,
sailfish_cell_compare_func);
}
}
}
GASSERT(grilio_parser_at_end(&rilp));
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
(io->ril_version, data, len));
}
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
DBG_(self, "");
GASSERT(self->query_id);
self->query_id = 0;
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
}
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
DBG_(self, "");
GASSERT(self->set_rate_id);
self->set_rate_id = 0;
}
static gboolean ril_cell_info_retry(GRilIoRequest* request, int ril_status,
const void* response_data, guint response_len, void* user_data)
{
switch (ril_status) {
case RIL_E_SUCCESS:
case RIL_E_RADIO_NOT_AVAILABLE:
return FALSE;
default:
return TRUE;
}
}
static void ril_cell_info_query(struct ril_cell_info *self)
{
GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
grilio_request_set_retry_func(req, ril_cell_info_retry);
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
self->query_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
NULL, self);
grilio_request_unref(req);
}
static void ril_cell_info_set_rate(struct ril_cell_info *self)
{
GRilIoRequest *req = grilio_request_array_int32_new(1,
(self->update_rate_ms >= 0) ? self->update_rate_ms : INT_MAX);
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
grilio_request_set_retry_func(req, ril_cell_info_retry);
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
ril_cell_info_set_rate_cb, NULL, self);
grilio_request_unref(req);
}
static void ril_cell_info_refresh(struct ril_cell_info *self)
{
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
if (self->radio->state == RADIO_STATE_ON && self->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);
self->sim_card_ready = ril_sim_card_ready(sim);
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
ril_cell_info_refresh(self);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
}
/* sailfish_cell_info interface callbacks */
struct ril_cell_info_closure {
GCClosure cclosure;
sailfish_cell_info_cb_t cb;
void *arg;
};
static inline struct ril_cell_info *ril_cell_info_cast
(struct sailfish_cell_info *info)
{
return G_CAST(info, struct ril_cell_info, info);
}
static void ril_cell_info_ref_proc(struct sailfish_cell_info *info)
{
g_object_ref(ril_cell_info_cast(info));
}
static void ril_cell_info_unref_proc(struct sailfish_cell_info *info)
{
g_object_unref(ril_cell_info_cast(info));
}
static void ril_cell_info_cells_changed_cb(struct ril_cell_info *self,
struct ril_cell_info_closure *closure)
{
closure->cb(&self->info, closure->arg);
}
static gulong ril_cell_info_add_cells_changed_handler_proc
(struct sailfish_cell_info *info,
sailfish_cell_info_cb_t cb, void *arg)
{
if (cb) {
struct ril_cell_info_closure *closure =
(struct ril_cell_info_closure *) g_closure_new_simple
(sizeof(struct ril_cell_info_closure), NULL);
GCClosure* cc = &closure->cclosure;
cc->closure.data = closure;
cc->callback = G_CALLBACK(ril_cell_info_cells_changed_cb);
closure->cb = cb;
closure->arg = arg;
return g_signal_connect_closure_by_id(ril_cell_info_cast(info),
ril_cell_info_signals[SIGNAL_CELLS_CHANGED], 0,
&cc->closure, FALSE);
} else {
return 0;
}
}
static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
gulong id)
{
if (G_LIKELY(id)) {
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
}
}
static void ril_cell_info_set_update_interval_proc
(struct sailfish_cell_info *info, int ms)
{
struct ril_cell_info *self = ril_cell_info_cast(info);
if (self->update_rate_ms != ms) {
self->update_rate_ms = ms;
DBG_(self, "%d ms", ms);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
}
}
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card)
{
static const struct sailfish_cell_info_proc ril_cell_info_proc = {
ril_cell_info_ref_proc,
ril_cell_info_unref_proc,
ril_cell_info_add_cells_changed_handler_proc,
ril_cell_info_remove_handler_proc,
ril_cell_info_set_update_interval_proc
};
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
self->info.proc = &ril_cell_info_proc;
self->io = grilio_channel_ref(io);
self->radio = ril_radio_ref(radio);
self->sim_card = ril_sim_card_ref(sim_card);
self->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
DBG_(self, "");
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
self->radio_state_event_id =
ril_radio_add_state_changed_handler(radio,
ril_cell_info_radio_state_cb, self);
self->sim_status_event_id =
ril_sim_card_add_status_changed_handler(self->sim_card,
ril_cell_info_sim_status_cb, self);
self->sim_card_ready = ril_sim_card_ready(sim_card);
ril_cell_info_refresh(self);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
return &self->info;
}
static void ril_cell_info_init(struct ril_cell_info *self)
{
self->update_rate_ms = DEFAULT_UPDATE_RATE_MS;
}
static void ril_cell_info_dispose(GObject *object)
{
struct ril_cell_info *self = RIL_CELL_INFO(object);
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
if (self->query_id) {
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
self->query_id = 0;
}
if (self->set_rate_id) {
grilio_channel_cancel_request(self->io, self->set_rate_id,
FALSE);
self->set_rate_id = 0;
}
ril_radio_remove_handlers(self->radio, &self->radio_state_event_id, 1);
ril_sim_card_remove_handlers(self->sim_card,
&self->sim_status_event_id, 1);
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
}
static void ril_cell_info_finalize(GObject *object)
{
struct ril_cell_info *self = RIL_CELL_INFO(object);
DBG_(self, "");
g_free(self->log_prefix);
grilio_channel_unref(self->io);
ril_radio_unref(self->radio);
ril_sim_card_unref(self->sim_card);
g_slist_free_full(self->info.cells, ril_cell_free1);
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
}
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;
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

@@ -1,35 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_CELL_INFO_H
#define RIL_CELL_INFO_H
#include "ril_types.h"
#include <sailfish_cell_info.h>
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card);
#endif /* RIL_CELL_INFO_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,313 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
*
* 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"
#include "ril_util.h"
#include "ril_log.h"
#include <gutil_intarray.h>
#include <gutil_ints.h>
#include <gutil_misc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* Utilities for parsing ril_subscription.conf */
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
{
char *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;
}
char **ril_config_get_strings(GKeyFile *file, const char *group,
const char *key, char delimiter)
{
char *str = ril_config_get_string(file, group, key);
if (str) {
char **strv, **p;
char delimiter_str[2];
delimiter_str[0] = delimiter;
delimiter_str[1] = 0;
strv = g_strsplit(str, delimiter_str, -1);
/* Strip whitespaces */
for (p = strv; *p; p++) {
*p = g_strstrip(*p);
}
g_free(str);
return strv;
}
return NULL;
}
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
const char *key, int *out_value)
{
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;
}
}
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...)
{
char *str = ril_config_get_string(file, group, key);
if (str) {
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(str, '#');
if (comment) *comment = 0;
g_strstrip(str);
if (strcasecmp(str, name)) {
va_list args;
va_start(args, value);
while ((name = va_arg(args, char*)) != NULL) {
value = va_arg(args, int);
if (!strcasecmp(str, name)) {
break;
}
}
va_end(args);
}
if (!name) {
ofono_error("Invalid %s config value (%s)", key, str);
}
g_free(str);
if (name) {
if (result) {
*result = value;
}
return TRUE;
}
}
return FALSE;
}
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...)
{
char *str = ril_config_get_string(file, group, key);
gboolean ok = FALSE;
if (result) {
*result = 0;
}
if (str) {
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(str, '#');
char **values, **ptr;
if (comment) *comment = 0;
values = g_strsplit(str, "+", -1);
for (ok = TRUE, ptr = values; *ptr && ok; ptr++) {
const char* found_str = NULL;
const char* s = g_strstrip(*ptr);
if (!strcasecmp(s, name)) {
found_str = name;
if (result) {
*result |= value;
}
} else {
va_list args;
const char* known;
va_start(args, value);
while ((known = va_arg(args, char*)) != NULL) {
const int bit = va_arg(args, int);
if (!strcasecmp(s, known)) {
found_str = known;
if (result) {
*result |= bit;
}
break;
}
}
va_end(args);
}
if (!found_str) {
ofono_error("Unknown bit '%s' in %s", s, key);
ok = FALSE;
}
}
g_strfreev(values);
g_free(str);
}
if (!ok && result) {
*result = 0;
}
return ok;
}
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key)
{
char *value = ril_config_get_string(file, group, key);
if (value) {
GUtilIntArray *array = gutil_int_array_new();
char **values, **ptr;
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(value, '#');
if (comment) *comment = 0;
values = g_strsplit(value, ",", -1);
ptr = values;
while (*ptr) {
int val;
if (gutil_parse_int(*ptr++, 0, &val)) {
gutil_int_array_append(array, val);
}
}
g_free(value);
g_strfreev(values);
return gutil_int_array_free_to_ints(array);
}
return NULL;
}
char *ril_config_ints_to_string(GUtilInts *ints, char separator)
{
if (ints) {
guint i, n;
const int *data = gutil_ints_get_data(ints, &n);
GString *buf = g_string_new(NULL);
for (i=0; i<n; i++) {
if (buf->len > 0) {
g_string_append_c(buf, separator);
}
g_string_append_printf(buf, "%d", data[i]);
}
return g_string_free(buf, FALSE);
}
return NULL;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,56 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
*
* 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);
char **ril_config_get_strings(GKeyFile *file, const char *group,
const char *key, char delimiter);
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
const char *key, int *value);
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
const char *key, gboolean *value);
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
const char *key, int flag, int *flags);
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...)
G_GNUC_NULL_TERMINATED;
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...)
G_GNUC_NULL_TERMINATED;
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key);
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
#endif /* RIL_CONFIG_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,622 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_connman.h"
#include <ofono/log.h>
#include <gdbus.h>
#include <gutil_macros.h>
#include <gutil_misc.h>
#include <glib-object.h>
#define CONNMAN_BUS DBUS_BUS_SYSTEM
#define CONNMAN_SERVICE "net.connman"
#define CONNMAN_PATH "/"
#define CONNMAN_GET_PROPERTIES "GetProperties"
#define CONNMAN_GET_TECHNOLOGIES "GetTechnologies"
#define CONNMAN_PROPERTY_CHANGED "PropertyChanged"
#define CONNMAN_TECH_CONNECTED "Connected"
#define CONNMAN_TECH_TETHERING "Tethering"
#define CONNMAN_INTERFACE_(name) "net.connman." name
#define CONNMAN_MANAGER_INTERFACE CONNMAN_INTERFACE_("Manager")
#define CONNMAN_TECH_INTERFACE CONNMAN_INTERFACE_("Technology")
#define CONNMAN_TECH_PATH_(name) "/net/connman/technology/" name
#define CONNMAN_TECH_PATH_WIFI CONNMAN_TECH_PATH_("wifi")
#define CONNMAN_TECH_CONNECTED_BIT (0x01)
#define CONNMAN_TECH_TETHERING_BIT (0x02)
#define CONNMAN_TECH_ALL_PROPERTY_BITS (\
CONNMAN_TECH_CONNECTED_BIT | \
CONNMAN_TECH_TETHERING_BIT)
typedef GObjectClass ConnManObjectClass;
typedef struct connman_tech ConnManTech;
typedef struct connman_object {
GObject object;
struct ril_connman pub;
guint32 pending_signals;
DBusConnection *connection;
DBusPendingCall *call;
guint service_watch;
guint signal_watch;
GHashTable *techs;
ConnManTech *wifi;
} ConnManObject;
G_DEFINE_TYPE(ConnManObject, connman_object, G_TYPE_OBJECT)
#define CONNMAN_OBJECT_TYPE (connman_object_get_type())
#define CONNMAN_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
CONNMAN_OBJECT_TYPE, ConnManObject))
struct connman_tech {
ConnManObject *obj;
const char *path;
gboolean connected;
gboolean tethering;
};
typedef struct connman_closure {
GCClosure cclosure;
ril_connman_property_cb_t callback;
gpointer user_data;
} ConnManClosure;
#define connman_closure_new() ((ConnManClosure *) \
g_closure_new_simple(sizeof(ConnManClosure), NULL))
#define SIGNAL_PROPERTY_CHANGED_NAME "ril-connman-property-changed"
#define SIGNAL_PROPERTY_DETAIL "%x"
#define SIGNAL_PROPERTY_DETAIL_MAX_LEN (8)
#define SIGNAL_BIT(property) (1 << (property - 1))
#define SIGNAL_BIT_(name) SIGNAL_BIT(RIL_CONNMAN_PROPERTY_##name)
enum connman_object_signal {
SIGNAL_PROPERTY_CHANGED,
SIGNAL_COUNT
};
static guint connman_object_signals[SIGNAL_COUNT];
static GQuark connman_object_property_quarks[RIL_CONNMAN_PROPERTY_COUNT - 1];
static inline ConnManObject *connman_object_cast(struct ril_connman *connman)
{
return G_LIKELY(connman) ?
CONNMAN_OBJECT(G_CAST(connman, ConnManObject, pub)) :
NULL;
}
static inline const char *connman_iter_get_string(DBusMessageIter *it)
{
const char *str = NULL;
dbus_message_iter_get_basic(it, &str);
return str;
}
static GQuark connman_object_property_quark(enum ril_connman_property p)
{
/* For ANY property this function is expected to return zero */
if (p > RIL_CONNMAN_PROPERTY_ANY && p < RIL_CONNMAN_PROPERTY_COUNT) {
const int i = p - 1;
if (G_UNLIKELY(!connman_object_property_quarks[i])) {
char buf[SIGNAL_PROPERTY_DETAIL_MAX_LEN + 1];
snprintf(buf, sizeof(buf), SIGNAL_PROPERTY_DETAIL, p);
buf[sizeof(buf) - 1] = 0;
connman_object_property_quarks[i] =
g_quark_from_string(buf);
}
return connman_object_property_quarks[i];
}
return 0;
}
static void connman_object_property_changed(ConnManObject *self,
enum ril_connman_property property, ConnManClosure *closure)
{
closure->callback(&self->pub, property, closure->user_data);
}
static void connman_object_emit_property_change(ConnManObject *self,
enum ril_connman_property p)
{
self->pending_signals &= ~SIGNAL_BIT(p);
g_signal_emit(self, connman_object_signals[SIGNAL_PROPERTY_CHANGED],
connman_object_property_quark(p), p);
}
static void connman_object_emit_pending_signals(ConnManObject *self)
{
struct ril_connman *connman = &self->pub;
gboolean valid_changed, present_changed;
enum ril_connman_property p;
/* Handlers could drop their references to us */
g_object_ref(self);
/*
* PRESENT and VALID are the last signals to be emitted if the object
* BECOMES present and/or valid.
*/
if ((self->pending_signals & SIGNAL_BIT_(VALID)) &&
connman->valid) {
self->pending_signals &= ~SIGNAL_BIT_(VALID);
valid_changed = TRUE;
} else {
valid_changed = FALSE;
}
if ((self->pending_signals & SIGNAL_BIT_(PRESENT)) &&
connman->present) {
self->pending_signals &= ~SIGNAL_BIT_(PRESENT);
present_changed = TRUE;
} else {
present_changed = FALSE;
}
/*
* Emit the signals. Not that in case if valid has become FALSE,
* then VALID is emitted first, otherwise it's emitted last.
* Same thing with PRESENT.
*/
for (p = RIL_CONNMAN_PROPERTY_ANY + 1;
p < RIL_CONNMAN_PROPERTY_COUNT && self->pending_signals;
p++) {
if (self->pending_signals & SIGNAL_BIT(p)) {
connman_object_emit_property_change(self, p);
}
}
/* Then emit PRESENT and VALID if necessary */
if (present_changed) {
connman_object_emit_property_change(self,
RIL_CONNMAN_PROPERTY_PRESENT);
}
if (valid_changed) {
connman_object_emit_property_change(self,
RIL_CONNMAN_PROPERTY_VALID);
}
/* And release the temporary reference */
g_object_unref(self);
}
static void connman_cancel_call(ConnManObject *self)
{
if (self->call) {
dbus_pending_call_cancel(self->call);
dbus_pending_call_unref(self->call);
self->call = NULL;
}
}
static ConnManTech *connman_tech_new(ConnManObject *self, const char *path)
{
ConnManTech *tech = g_new0(ConnManTech, 1);
char *key = g_strdup(path);
tech->obj = self;
tech->path = key;
g_hash_table_replace(self->techs, key, tech);
return tech;
}
static void connman_invalidate(ConnManObject *self)
{
struct ril_connman *connman = &self->pub;
if (connman->valid) {
connman->valid = FALSE;
self->pending_signals |= SIGNAL_BIT_(VALID);
}
}
static void connman_update_valid(ConnManObject *self)
{
struct ril_connman *connman = &self->pub;
const gboolean valid = (connman->present && !self->call);
if (connman->valid != valid) {
connman->valid = valid;
self->pending_signals |= SIGNAL_BIT_(VALID);
}
}
static gboolean connman_update_tethering(ConnManObject *self)
{
struct ril_connman *connman = &self->pub;
gboolean tethering = FALSE;
GHashTableIter it;
gpointer value;
g_hash_table_iter_init(&it, self->techs);
while (g_hash_table_iter_next(&it, NULL, &value)) {
const ConnManTech *tech = value;
if (tech->tethering) {
tethering = TRUE;
break;
}
}
if (connman->tethering != tethering) {
connman->tethering = tethering;
self->pending_signals |= SIGNAL_BIT_(TETHERING);
return TRUE;
} else {
return FALSE;
}
}
static void connman_set_tech_tethering(ConnManTech *tech, gboolean tethering)
{
if (tech->tethering != tethering) {
ConnManObject *self = tech->obj;
tech->tethering = tethering;
DBG(CONNMAN_TECH_TETHERING " %s for %s",
tethering ? "on" : "off", tech->path);
if (tethering) {
struct ril_connman *connman = &self->pub;
if (G_LIKELY(!connman->tethering)) {
/* Definitely tethering now */
connman->tethering = TRUE;
self->pending_signals |= SIGNAL_BIT_(TETHERING);
DBG("Tethering on");
}
} else if (connman_update_tethering(self)) {
/* Not tethering anymore */
DBG("Tethering off");
}
}
}
static void connman_set_tech_connected(ConnManTech *tech, gboolean connected)
{
if (tech->connected != connected) {
ConnManObject *self = tech->obj;
tech->connected = connected;
DBG(CONNMAN_TECH_CONNECTED " %s for %s",
connected ? "on" : "off", tech->path);
if (tech == self->wifi) {
struct ril_connman *connman = &self->pub;
connman->wifi_connected = connected;
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
DBG("WiFi %sconnected", connected ? "" : "dis");
}
}
}
static int connman_tech_set_property(ConnManTech *tech, DBusMessageIter *it)
{
DBusMessageIter var;
DBusBasicValue value;
const char *key = connman_iter_get_string(it);
dbus_message_iter_next(it);
dbus_message_iter_recurse(it, &var);
dbus_message_iter_get_basic(&var, &value);
if (!g_ascii_strcasecmp(key, CONNMAN_TECH_CONNECTED)) {
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
connman_set_tech_connected(tech, value.bool_val);
return CONNMAN_TECH_CONNECTED_BIT;
}
} else if (!g_ascii_strcasecmp(key, CONNMAN_TECH_TETHERING)) {
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
connman_set_tech_tethering(tech, value.bool_val);
return CONNMAN_TECH_TETHERING_BIT;
}
}
return 0;
}
static void connman_tech_set_properties(ConnManTech *tech, DBusMessageIter *it)
{
DBusMessageIter dict;
int handled = 0;
dbus_message_iter_recurse(it, &dict);
while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
DBusMessageIter entry;
dbus_message_iter_recurse(&dict, &entry);
handled |= connman_tech_set_property(tech, &entry);
if (handled == CONNMAN_TECH_ALL_PROPERTY_BITS) {
/* Ignore the rest */
break;
}
dbus_message_iter_next(&dict);
}
}
static gboolean connman_tech_property_changed(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
const char *path = dbus_message_get_path(msg);
ConnManObject *self = CONNMAN_OBJECT(user_data);
ConnManTech *tech = g_hash_table_lookup(self->techs, path);
DBusMessageIter it;
if (tech && dbus_message_has_signature(msg, "sv") &&
dbus_message_iter_init(msg, &it)) {
const char* name = connman_iter_get_string(&it);
if (!connman_tech_set_property(tech, &it)) {
DBG("%s changed for %s", name, path);
}
connman_object_emit_pending_signals(self);
}
return TRUE;
}
static void connman_set_techs(ConnManObject *self, DBusMessageIter *it)
{
DBusMessageIter list;
dbus_message_iter_recurse(it, &list);
while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) {
DBusMessageIter entry;
const char *path;
ConnManTech *tech;
dbus_message_iter_recurse(&list, &entry);
path = connman_iter_get_string(&entry);
tech = connman_tech_new(self, path);
DBG("%s", path);
if (!g_strcmp0(path, CONNMAN_TECH_PATH_WIFI)) {
/* WiFi is a special case */
self->wifi = tech;
}
dbus_message_iter_next(&entry);
connman_tech_set_properties(tech, &entry);
dbus_message_iter_next(&list);
}
}
static void connman_techs_reply(DBusPendingCall *call, void *user_data)
{
ConnManObject *self = CONNMAN_OBJECT(user_data);
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusError error;
DBusMessageIter array;
dbus_error_init(&error);
if (dbus_set_error_from_message(&error, reply)) {
DBG("Failed to get technologies: %s", error.message);
dbus_error_free(&error);
} else if (dbus_message_has_signature(reply, "a(oa{sv})") &&
dbus_message_iter_init(reply, &array)) {
connman_set_techs(self, &array);
}
dbus_message_unref(reply);
dbus_pending_call_unref(self->call);
self->call = NULL;
connman_update_valid(self);
connman_object_emit_pending_signals(self);
}
static void connman_get_techs(ConnManObject *self)
{
DBusMessage *msg = dbus_message_new_method_call(CONNMAN_SERVICE,
CONNMAN_PATH, CONNMAN_MANAGER_INTERFACE,
CONNMAN_GET_TECHNOLOGIES);
connman_cancel_call(self);
if (g_dbus_send_message_with_reply(self->connection, msg,
&self->call, DBUS_TIMEOUT_INFINITE)) {
/* Not valid while any request is pending */
connman_invalidate(self);
dbus_pending_call_set_notify(self->call, connman_techs_reply,
self, NULL);
}
dbus_message_unref(msg);
}
static void connman_appeared(DBusConnection *conn, void *user_data)
{
ConnManObject *self = CONNMAN_OBJECT(user_data);
struct ril_connman *connman = &self->pub;
if (!connman->present) {
DBG("connman is there");
connman->present = TRUE;
self->pending_signals |= SIGNAL_BIT_(PRESENT);
connman_get_techs(self);
connman_object_emit_pending_signals(self);
}
}
static void connman_vanished(DBusConnection *conn, void *user_data)
{
ConnManObject *self = CONNMAN_OBJECT(user_data);
struct ril_connman *connman = &self->pub;
if (connman->present) {
DBG("connman has disappeared");
g_hash_table_remove_all(self->techs);
self->wifi = NULL;
connman->present = FALSE;
self->pending_signals |= SIGNAL_BIT_(PRESENT);
if (connman->wifi_connected) {
connman->wifi_connected = FALSE;
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
}
if (connman->tethering) {
connman->tethering = FALSE;
self->pending_signals |= SIGNAL_BIT_(TETHERING);
}
connman_object_emit_pending_signals(self);
}
}
static void connman_init(ConnManObject *self, DBusConnection *connection)
{
self->connection = dbus_connection_ref(connection);
self->service_watch = g_dbus_add_service_watch(self->connection,
CONNMAN_SERVICE, connman_appeared, connman_vanished,
self, NULL);
self->signal_watch = g_dbus_add_signal_watch(self->connection,
CONNMAN_SERVICE, NULL, CONNMAN_TECH_INTERFACE,
CONNMAN_PROPERTY_CHANGED, connman_tech_property_changed,
self, NULL);
}
struct ril_connman *ril_connman_new()
{
static ConnManObject *instance = NULL;
if (instance) {
g_object_ref(instance);
return &instance->pub;
} else {
DBusError error;
DBusConnection *connection;
dbus_error_init(&error);
connection = dbus_bus_get(CONNMAN_BUS, NULL);
if (connection) {
instance = g_object_new(CONNMAN_OBJECT_TYPE, NULL);
connman_init(instance, connection);
dbus_connection_unref(connection);
g_object_add_weak_pointer(G_OBJECT(instance),
(gpointer*)(&instance));
return &instance->pub;
} else {
ofono_error("Unable to attach to connman bus: %s",
error.message);
dbus_error_free(&error);
return NULL;
}
}
}
struct ril_connman *ril_connman_ref(struct ril_connman *connman)
{
ConnManObject *self = connman_object_cast(connman);
if (G_LIKELY(self)) {
g_object_ref(self);
return connman;
} else {
return NULL;
}
}
void ril_connman_unref(struct ril_connman *connman)
{
ConnManObject *self = connman_object_cast(connman);
if (G_LIKELY(self)) {
g_object_unref(self);
}
}
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg)
{
ConnManObject *self = connman_object_cast(connman);
if (G_LIKELY(self) && G_LIKELY(cb)) {
/*
* We can't directly connect the provided callback because
* it expects the first parameter to point to public part
* of the object but glib will call it with ConnManObject
* as the first parameter. connman_object_property_changed()
* will do the conversion.
*/
ConnManClosure *closure = connman_closure_new();
GCClosure *cc = &closure->cclosure;
cc->closure.data = closure;
cc->callback = G_CALLBACK(connman_object_property_changed);
closure->callback = cb;
closure->user_data = arg;
return g_signal_connect_closure_by_id(self,
connman_object_signals[SIGNAL_PROPERTY_CHANGED],
connman_object_property_quark(p), &cc->closure, FALSE);
}
return 0;
}
void ril_connman_remove_handler(struct ril_connman *connman, gulong id)
{
if (G_LIKELY(id)) {
ConnManObject *self = connman_object_cast(connman);
if (G_LIKELY(self)) {
g_signal_handler_disconnect(self, id);
}
}
}
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
int n)
{
gutil_disconnect_handlers(connman_object_cast(connman), ids, n);
}
static void connman_object_init(ConnManObject *self)
{
self->techs = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
}
static void connman_object_finalize(GObject *object)
{
ConnManObject *self = CONNMAN_OBJECT(object);
connman_cancel_call(self);
g_hash_table_destroy(self->techs);
g_dbus_remove_watch(self->connection, self->service_watch);
g_dbus_remove_watch(self->connection, self->signal_watch);
dbus_connection_unref(self->connection);
G_OBJECT_CLASS(connman_object_parent_class)->finalize(object);
}
static void connman_object_class_init(ConnManObjectClass *klass)
{
G_OBJECT_CLASS(klass)->finalize = connman_object_finalize;
connman_object_signals[SIGNAL_PROPERTY_CHANGED] =
g_signal_new(SIGNAL_PROPERTY_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,61 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_CONNMAN_H
#define RIL_CONNMAN_H
#include <gutil_misc.h>
struct ril_connman {
gboolean valid; /* TRUE if other fields are valid */
gboolean present; /* ConnMan is present on D-Bus */
gboolean tethering; /* At least one technology is tethering */
gboolean wifi_connected; /* WiFi network is connected */
};
enum ril_connman_property {
RIL_CONNMAN_PROPERTY_ANY,
RIL_CONNMAN_PROPERTY_VALID,
RIL_CONNMAN_PROPERTY_PRESENT,
RIL_CONNMAN_PROPERTY_TETHERING,
RIL_CONNMAN_PROPERTY_WIFI_CONNECTED,
RIL_CONNMAN_PROPERTY_COUNT
};
typedef void (*ril_connman_property_cb_t)(struct ril_connman *connman,
enum ril_connman_property property, void *arg);
struct ril_connman *ril_connman_new(void);
struct ril_connman *ril_connman_ref(struct ril_connman *connman);
void ril_connman_unref(struct ril_connman *connman);
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg);
void ril_connman_remove_handler(struct ril_connman *connman, gulong id);
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
int n);
#define ril_connman_remove_all_handlers(connman, ids) \
ril_connman_remove_handlers(connman, ids, G_N_ELEMENTS(ids))
#endif /* RIL_CONNMAN_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,399 +0,0 @@
/*
* Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2013-2020 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
#include <ofono/ril-constants.h>
#define RIL_MAX_UUID_LENGTH 64
/* 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,
RADIO_TECH_LTE_CA = 19
};
/* Radio capabilities */
enum ril_radio_access_family {
RAF_GPRS = (1 << RADIO_TECH_GPRS),
RAF_EDGE = (1 << RADIO_TECH_EDGE),
RAF_UMTS = (1 << RADIO_TECH_UMTS),
RAF_IS95A = (1 << RADIO_TECH_IS95A),
RAF_IS95B = (1 << RADIO_TECH_IS95B),
RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
RAF_HSPA = (1 << RADIO_TECH_HSPA),
RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
RAF_LTE = (1 << RADIO_TECH_LTE),
RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
RAF_GSM = (1 << RADIO_TECH_GSM),
RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
};
enum ril_radio_capability_phase {
RC_PHASE_CONFIGURED = 0,
RC_PHASE_START = 1,
RC_PHASE_APPLY = 2,
RC_PHASE_UNSOL_RSP = 3,
RC_PHASE_FINISH = 4
};
enum ril_radio_capability_status {
RC_STATUS_NONE = 0,
RC_STATUS_SUCCESS = 1,
RC_STATUS_FAIL = 2
};
#define RIL_RADIO_CAPABILITY_VERSION 1
struct ril_radio_capability {
int version;
int session;
enum ril_radio_capability_phase phase;
enum ril_radio_access_family rat;
char logicalModemUuid[RIL_MAX_UUID_LENGTH];
int status;
};
enum ril_uicc_subscription_action {
RIL_UICC_SUBSCRIPTION_DEACTIVATE = 0,
RIL_UICC_SUBSCRIPTION_ACTIVATE = 1
};
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
enum ril_call_fail_cause {
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
CALL_FAIL_NORMAL = 16,
CALL_FAIL_BUSY = 17,
CALL_FAIL_NO_USER_RESPONDING = 18,
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
CALL_FAIL_CALL_REJECTED = 21,
CALL_FAIL_NUMBER_CHANGED = 22,
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
CALL_FAIL_FACILITY_REJECTED = 29,
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
CALL_FAIL_CONGESTION = 34,
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
CALL_FAIL_TEMPORARY_FAILURE = 41,
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
CALL_FAIL_QOS_UNAVAILABLE = 49,
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
CALL_FAIL_CALL_BARRED = 240,
CALL_FAIL_FDN_BLOCKED = 241,
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
/* Not defined in ril.h but valid 3GPP specific cause values
* for call control. See 3GPP TS 24.008 Annex H. */
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
CALL_FAIL_PRE_EMPTION = 25
};
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_QOS_NOT_ACCEPTED = 0x25,
PDP_FAIL_NETWORK_FAILURE = 0x26,
PDP_FAIL_UMTS_REACTIVATION_REQ = 0x27,
PDP_FAIL_FEATURE_NOT_SUPP = 0x28,
PDP_FAIL_TFT_SEMANTIC_ERROR = 0x29,
PDP_FAIL_TFT_SYTAX_ERROR = 0x2A,
PDP_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
PDP_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
PDP_FAIL_FILTER_SYTAX_ERROR = 0x2D,
PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
PDP_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
PDP_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
PDP_FAIL_INVALID_TRANSACTION_ID = 0x51,
PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
PDP_FAIL_INVALID_MANDATORY_INFO = 0x60,
PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
PDP_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
PDP_FAIL_CONDITIONAL_IE_ERROR = 0x64,
PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
PDP_FAIL_APN_TYPE_CONFLICT = 0x70,
PDP_FAIL_INVALID_PCSCF_ADDR = 0x71,
PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
PDP_FAIL_EMM_ACCESS_BARRED = 0x73,
PDP_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
PDP_FAIL_IFACE_MISMATCH = 0x75,
PDP_FAIL_COMPANION_IFACE_IN_USE = 0x76,
PDP_FAIL_IP_ADDRESS_MISMATCH = 0x77,
PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
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_profile_type {
RIL_PROFILE_COMMON = 0,
RIL_PROFILE_3GPP = 1,
RIL_PROFILE_3GPP2 = 2
};
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
};
enum ril_restricted_state {
RIL_RESTRICTED_STATE_NONE = 0x00,
RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01,
RIL_RESTRICTED_STATE_CS_NORMAL = 0x02,
RIL_RESTRICTED_STATE_CS_ALL = 0x04,
RIL_RESTRICTED_STATE_PS_ALL = 0x10
};
/* Suplementary services Service class*/
#define SERVICE_CLASS_NONE 0
/* RIL_FACILITY_LOCK parameters */
#define RIL_FACILITY_UNLOCK "0"
#define RIL_FACILITY_LOCK "1"
/* See RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER (RIL_VERSION >= 15) */
enum ril_unsolicited_response_filter {
RIL_UR_SIGNAL_STRENGTH = 0x01,
RIL_UR_FULL_NETWORK_STATE = 0x02,
RIL_UR_DATA_CALL_DORMANCY_CHANGED = 0x04
};
/* RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE result */
enum ril_network_selection_mode {
RIL_NETWORK_SELECTION_MODE_AUTO = 0,
RIL_NETWORK_SELECTION_MODE_MANUAL = 1
};
#endif /*__RIL_CONSTANTS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,145 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2021 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* 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>
#include <glib-object.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;
char **pcscf;
};
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,
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS = 0x02
};
enum ril_data_allow_data_opt {
RIL_ALLOW_DATA_AUTO,
RIL_ALLOW_DATA_ENABLED,
RIL_ALLOW_DATA_DISABLED
};
enum ril_data_call_format {
RIL_DATA_CALL_FORMAT_AUTO,
RIL_DATA_CALL_FORMAT_6 = 6,
RIL_DATA_CALL_FORMAT_9 = 9,
RIL_DATA_CALL_FORMAT_11 = 11
};
struct ril_data_options {
enum ril_data_allow_data_opt allow_data;
enum ril_data_call_format data_call_format;
unsigned int data_call_retry_limit;
unsigned int data_call_retry_delay_ms;
};
struct ril_data_manager;
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
void ril_data_manager_unref(struct ril_data_manager *dm);
void ril_data_manager_check_data(struct ril_data_manager *dm);
void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
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, const struct ril_data_options *options,
const struct ril_slot_config *config,
struct ril_vendor *vendor);
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
gboolean ril_data_allowed(struct ril_data *data);
void ril_data_poll_call_state(struct ril_data *data);
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
ril_data_cb_t cb, void *arg);
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,
enum ofono_gprs_context_type context_type,
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);
gboolean ril_data_call_grab(struct ril_data *data, int cid, void *cookie);
void ril_data_call_release(struct ril_data *data, int cid, void *cookie);
void ril_data_call_free(struct ril_data_call *call);
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
int cid);
/* Constructors of various kinds of RIL requests */
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
#endif /* RIL_DATA_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,225 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
#include <gutil_idlequeue.h>
/*
* TODO: No public RIL api to query manufacturer or model.
* Check where to get, could /system/build.prop be updated to have good values?
*/
enum ril_devinfo_cb_tag {
DEVINFO_QUERY_SERIAL = 1,
DEVINFO_QUERY_SVN
};
struct ril_devinfo {
struct ofono_devinfo *info;
GRilIoQueue *q;
GUtilIdleQueue *iq;
char *log_prefix;
char *imeisv;
char *imei;
};
struct ril_devinfo_cbd {
struct ril_devinfo *di;
ofono_devinfo_query_cb_t cb;
gpointer data;
};
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
#define ril_devinfo_cbd_free g_free
static inline struct ril_devinfo *ril_devinfo_get_data(
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_revision_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_(cbd->di, "%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_(di, "");
grilio_queue_send_request_full(di->q, NULL,
RIL_REQUEST_BASEBAND_VERSION,
ril_devinfo_query_revision_cb,
ril_devinfo_cbd_free,
ril_devinfo_cbd_new(di, cb, data));
}
static void ril_devinfo_query_serial_cb(gpointer user_data)
{
struct ril_devinfo_cbd *cbd = user_data;
struct ril_devinfo *di = cbd->di;
struct ofono_error error;
DBG_(di, "%s", di->imei);
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
}
static void ril_devinfo_query_svn_cb(gpointer user_data)
{
struct ril_devinfo_cbd *cbd = user_data;
struct ril_devinfo *di = cbd->di;
struct ofono_error error;
DBG_(di, "%s", di->imeisv);
if (di->imeisv && di->imeisv[0]) {
cbd->cb(ril_error_ok(&error), di->imeisv, cbd->data);
} else {
cbd->cb(ril_error_failure(&error), "", cbd->data);
}
}
static void ril_devinfo_query(struct ril_devinfo *di,
enum ril_devinfo_cb_tag tag, GUtilIdleFunc fn,
ofono_devinfo_query_cb_t cb, void *data)
{
GVERIFY_FALSE(gutil_idle_queue_cancel_tag(di->iq, tag));
gutil_idle_queue_add_tag_full(di->iq, tag, fn,
ril_devinfo_cbd_new(di, cb, data),
ril_devinfo_cbd_free);
}
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb,
void *data)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG_(di, "");
ril_devinfo_query(di, DEVINFO_QUERY_SERIAL,
ril_devinfo_query_serial_cb, cb, data);
}
static void ril_devinfo_query_svn(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb,
void *data)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG_(di, "");
ril_devinfo_query(di, DEVINFO_QUERY_SVN,
ril_devinfo_query_svn_cb, cb, data);
}
static void ril_devinfo_register(gpointer user_data)
{
struct ril_devinfo *di = user_data;
DBG_(di, "");
ofono_devinfo_register(di->info);
}
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);
di->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
DBG_(di, "%s", modem->imei);
GASSERT(modem->imei);
di->q = grilio_queue_new(ril_modem_io(modem));
di->info = info;
di->imeisv = g_strdup(modem->imeisv);
di->imei = g_strdup(modem->imei);
di->iq = gutil_idle_queue_new();
gutil_idle_queue_add(di->iq, 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_(di, "");
ofono_devinfo_set_data(info, NULL);
gutil_idle_queue_cancel_all(di->iq);
gutil_idle_queue_unref(di->iq);
grilio_queue_cancel_all(di->q, FALSE);
grilio_queue_unref(di->q);
g_free(di->log_prefix);
g_free(di->imeisv);
g_free(di->imei);
g_free(di);
}
const struct ofono_devinfo_driver ril_devinfo_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_devinfo_probe,
.remove = ril_devinfo_remove,
/* query_revision won't be called if query_model is missing */
.query_model = ril_devinfo_query_unsupported,
.query_revision = ril_devinfo_query_revision,
.query_serial = ril_devinfo_query_serial,
.query_svn = ril_devinfo_query_svn
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,44 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_devmon.h"
struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon,
GRilIoChannel *channel, struct sailfish_cell_info *cell_info)
{
return devmon ? devmon->start_io(devmon, channel, cell_info) : NULL;
}
void ril_devmon_io_free(struct ril_devmon_io *devmon_io)
{
if (devmon_io) {
devmon_io->free(devmon_io);
}
}
void ril_devmon_free(struct ril_devmon *devmon)
{
if (devmon) {
devmon->free(devmon);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,80 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* 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_DEVMON_H
#define RIL_DEVMON_H
#include "ril_cell_info.h"
/*
* Separate instance of ril_devmon is created for each modem.
* Device monitor is started after RIL has been connected.
*/
struct ril_devmon_io {
void (*free)(struct ril_devmon_io *devmon_io);
};
struct ril_devmon {
void (*free)(struct ril_devmon *devmon);
struct ril_devmon_io *(*start_io)(struct ril_devmon *devmon,
GRilIoChannel *channel, struct sailfish_cell_info *cell_info);
};
/*
* Legacy Device Monitor uses RIL_REQUEST_SCREEN_STATE to tell
* the modem when screen turns on and off.
*/
struct ril_devmon *ril_devmon_ss_new(const struct ril_slot_config *config);
/*
* This Device Monitor uses RIL_REQUEST_SEND_DEVICE_STATE to let
* the modem choose the right power saving strategy. It basically
* mirrors the logic of Android's DeviceStateMonitor class.
*/
struct ril_devmon *ril_devmon_ds_new(const struct ril_slot_config *config);
/*
* This Device Monitor implementation controls network state updates
* by sending SET_UNSOLICITED_RESPONSE_FILTER.
*/
struct ril_devmon *ril_devmon_ur_new(const struct ril_slot_config *config);
/*
* This one selects the type based on the RIL version.
*/
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config);
/*
* This one combines several methods. Takes ownership of ril_devmon objects.
*/
struct ril_devmon *ril_devmon_combine(struct ril_devmon *devmon[], guint n);
/* Utilities (NULL tolerant) */
struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon,
GRilIoChannel *channel, struct sailfish_cell_info *cell_info);
void ril_devmon_io_free(struct ril_devmon_io *devmon_io);
void ril_devmon_free(struct ril_devmon *devmon);
#endif /* RIL_CONNMAN_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,92 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_devmon.h"
#include <ofono/log.h>
#include <grilio_channel.h>
typedef struct ril_devmon_ds {
struct ril_devmon pub;
struct ril_devmon *ss;
struct ril_devmon *ds;
} DevMon;
static inline DevMon *ril_devmon_auto_cast(struct ril_devmon *pub)
{
return G_CAST(pub, DevMon, pub);
}
static struct ril_devmon_io *ril_devmon_auto_start_io(struct ril_devmon *devmon,
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
{
DevMon *self = ril_devmon_auto_cast(devmon);
if (!self->ss) {
/* We have already chosen SEND_DEVICE_STATE method */
return ril_devmon_start_io(self->ds, io, cell_info);
} else if (!self->ds) {
/* We have already chosen SCREEN_STATE method */
return ril_devmon_start_io(self->ss, io, cell_info);
} else if (io->ril_version > 14 /* Covers binder implementation */) {
/* Choose SEND_DEVICE_STATE method */
DBG("%s: Will use SEND_DEVICE_STATE method", io->name);
ril_devmon_free(self->ss);
self->ss = NULL;
return ril_devmon_start_io(self->ds, io, cell_info);
} else {
/* Choose legacy SCREEN_STATE method */
DBG("%s: Will use SCREEN_STATE method", io->name);
ril_devmon_free(self->ds);
self->ds = NULL;
return ril_devmon_start_io(self->ss, io, cell_info);
}
}
static void ril_devmon_auto_free(struct ril_devmon *devmon)
{
DevMon *self = ril_devmon_auto_cast(devmon);
ril_devmon_free(self->ss);
ril_devmon_free(self->ds);
g_free(self);
}
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
/*
* Allocate both implementations at startup. We need to do that
* early so that connections to D-Bus daemon and services are
* established before we drop privileges. This isn't much of
* an overhead because those implementation don't do much until
* we actually start the I/O (at which point we drop one of those).
*/
self->pub.free = ril_devmon_auto_free;
self->pub.start_io = ril_devmon_auto_start_io;
self->ss = ril_devmon_ss_new(config);
self->ds = ril_devmon_ds_new(config);
return &self->pub;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,104 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* 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_devmon.h"
#include <ofono/log.h>
typedef struct ril_devmon_combine {
struct ril_devmon pub;
struct ril_devmon **impl;
guint count;
} DevMon;
typedef struct ril_devmon_combine_io {
struct ril_devmon_io pub;
struct ril_devmon_io **impl;
guint count;
} DevMonIo;
static inline DevMon *ril_devmon_combine_cast(struct ril_devmon *dm)
{
return G_CAST(dm, DevMon, pub);
}
static inline DevMonIo *ril_devmon_ds_io_cast(struct ril_devmon_io *io)
{
return G_CAST(io, DevMonIo, pub);
}
static void ril_devmon_combine_io_free(struct ril_devmon_io *io)
{
guint i;
DevMonIo *self = ril_devmon_ds_io_cast(io);
for (i = 0; i < self->count; i++) {
ril_devmon_io_free(self->impl[i]);
}
g_free(self);
}
static struct ril_devmon_io *ril_devmon_combine_start_io(struct ril_devmon *dm,
GRilIoChannel *chan, struct sailfish_cell_info *ci)
{
guint i;
DevMon *self = ril_devmon_combine_cast(dm);
DevMonIo *io = g_malloc0(sizeof(DevMonIo) +
sizeof(struct ril_devmon_io *) * self->count);
io->pub.free = ril_devmon_combine_io_free;
io->impl = (struct ril_devmon_io**)(io + 1);
io->count = self->count;
for (i = 0; i < io->count; i++) {
io->impl[i] = ril_devmon_start_io(self->impl[i], chan, ci);
}
return &io->pub;
}
static void ril_devmon_combine_free(struct ril_devmon *dm)
{
DevMon *self = ril_devmon_combine_cast(dm);
guint i;
for (i = 0; i < self->count; i++) {
ril_devmon_free(self->impl[i]);
}
g_free(self);
}
struct ril_devmon *ril_devmon_combine(struct ril_devmon *dm[], guint n)
{
guint i;
DevMon *self = g_malloc0(sizeof(DevMon) +
sizeof(struct ril_devmon *) * n);
self->pub.free = ril_devmon_combine_free;
self->pub.start_io = ril_devmon_combine_start_io;
self->impl = (struct ril_devmon **)(self + 1);
self->count = n;
for (i = 0; i < n; i++) {
self->impl[i] = dm[i];
}
return &self->pub;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,355 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_devmon.h"
#include "ril_connman.h"
#include <ofono/log.h>
#include <ofono/ril-constants.h>
#include <mce_battery.h>
#include <mce_charger.h>
#include <mce_display.h>
#include <grilio_channel.h>
#include <grilio_request.h>
#include <gutil_macros.h>
enum device_state_type {
/* Mirrors RIL_DeviceStateType from ril.h */
POWER_SAVE_MODE,
CHARGING_STATE,
LOW_DATA_EXPECTED
};
enum ril_devmon_ds_battery_event {
BATTERY_EVENT_VALID,
BATTERY_EVENT_STATUS,
BATTERY_EVENT_COUNT
};
enum ril_devmon_ds_charger_event {
CHARGER_EVENT_VALID,
CHARGER_EVENT_STATE,
CHARGER_EVENT_COUNT
};
enum ril_devmon_ds_display_event {
DISPLAY_EVENT_VALID,
DISPLAY_EVENT_STATE,
DISPLAY_EVENT_COUNT
};
enum ril_devmon_ds_connman_event {
CONNMAN_EVENT_VALID,
CONNMAN_EVENT_TETHERING,
CONNMAN_EVENT_COUNT
};
typedef struct ril_devmon_ds {
struct ril_devmon pub;
struct ril_connman *connman;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMon;
typedef struct ril_devmon_ds_io {
struct ril_devmon_io pub;
struct ril_connman *connman;
struct sailfish_cell_info *cell_info;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
GRilIoChannel *io;
guint low_data_req_id;
guint charging_req_id;
gboolean low_data;
gboolean charging;
gboolean low_data_supported;
gboolean charging_supported;
gulong connman_event_id[CONNMAN_EVENT_COUNT];
gulong battery_event_id[BATTERY_EVENT_COUNT];
gulong charger_event_id[CHARGER_EVENT_COUNT];
gulong display_event_id[DISPLAY_EVENT_COUNT];
guint req_id;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMonIo;
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
static inline DevMon *ril_devmon_ds_cast(struct ril_devmon *pub)
{
return G_CAST(pub, DevMon, pub);
}
static inline DevMonIo *ril_devmon_ds_io_cast(struct ril_devmon_io *pub)
{
return G_CAST(pub, DevMonIo, pub);
}
static inline gboolean ril_devmon_ds_tethering_on(struct ril_connman *connman)
{
return connman->valid && connman->tethering;
}
static inline gboolean ril_devmon_ds_battery_ok(MceBattery *battery)
{
return battery->valid && battery->status >= MCE_BATTERY_OK;
}
static inline gboolean ril_devmon_ds_charging(MceCharger *charger)
{
return charger->valid && charger->state == MCE_CHARGER_ON;
}
static inline gboolean ril_devmon_ds_display_on(MceDisplay *display)
{
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
}
static guint ril_devmon_ds_io_send_device_state(DevMonIo *self,
enum device_state_type type, gboolean state,
GRilIoChannelResponseFunc callback)
{
GRilIoRequest *req = grilio_request_array_int32_new(2, type, state);
const guint id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SEND_DEVICE_STATE, callback, NULL, self);
grilio_request_unref(req);
return id;
}
static void ril_devmon_ds_io_low_data_state_sent(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
DevMonIo *self = user_data;
self->low_data_req_id = 0;
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
DBG_(self, "LOW_DATA_EXPECTED state is not supported");
self->low_data_supported = FALSE;
}
}
static void ril_devmon_ds_io_charging_state_sent(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
DevMonIo *self = user_data;
self->charging_req_id = 0;
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
DBG_(self, "CHARGING state is not supported");
self->charging_supported = FALSE;
}
}
static void ril_devmon_ds_io_update_charging(DevMonIo *self)
{
const gboolean charging = ril_devmon_ds_charging(self->charger);
if (self->charging != charging) {
self->charging = charging;
DBG_(self, "Charging %s", charging ? "on" : "off");
if (self->charging_supported) {
grilio_channel_cancel_request(self->io,
self->charging_req_id, FALSE);
self->charging_req_id =
ril_devmon_ds_io_send_device_state(self,
CHARGING_STATE, charging,
ril_devmon_ds_io_charging_state_sent);
}
}
}
static void ril_devmon_ds_io_update_low_data(DevMonIo *self)
{
const gboolean low_data =
!ril_devmon_ds_tethering_on(self->connman) &&
!ril_devmon_ds_charging(self->charger) &&
!ril_devmon_ds_display_on(self->display);
if (self->low_data != low_data) {
self->low_data = low_data;
DBG_(self, "Low data is%s expected", low_data ? "" : " not");
if (self->low_data_supported) {
grilio_channel_cancel_request(self->io,
self->low_data_req_id, FALSE);
self->low_data_req_id =
ril_devmon_ds_io_send_device_state(self,
LOW_DATA_EXPECTED, low_data,
ril_devmon_ds_io_low_data_state_sent);
}
}
}
static void ril_devmon_ds_io_set_cell_info_update_interval(DevMonIo *self)
{
sailfish_cell_info_set_update_interval(self->cell_info,
(ril_devmon_ds_display_on(self->display) &&
(ril_devmon_ds_charging(self->charger) ||
ril_devmon_ds_battery_ok(self->battery))) ?
self->cell_info_interval_short_ms :
self->cell_info_interval_long_ms);
}
static void ril_devmon_ds_io_connman_cb(struct ril_connman *connman,
enum ril_connman_property property, void *user_data)
{
ril_devmon_ds_io_update_low_data((DevMonIo *)user_data);
}
static void ril_devmon_ds_io_battery_cb(MceBattery *battery, void *user_data)
{
ril_devmon_ds_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ds_io_display_cb(MceDisplay *display, void *user_data)
{
DevMonIo *self = user_data;
ril_devmon_ds_io_update_low_data(self);
ril_devmon_ds_io_set_cell_info_update_interval(self);
}
static void ril_devmon_ds_io_charger_cb(MceCharger *charger, void *user_data)
{
DevMonIo *self = user_data;
ril_devmon_ds_io_update_low_data(self);
ril_devmon_ds_io_update_charging(self);
ril_devmon_ds_io_set_cell_info_update_interval(self);
}
static void ril_devmon_ds_io_free(struct ril_devmon_io *devmon_io)
{
DevMonIo *self = ril_devmon_ds_io_cast(devmon_io);
ril_connman_remove_all_handlers(self->connman, self->connman_event_id);
ril_connman_unref(self->connman);
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
mce_battery_unref(self->battery);
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
mce_charger_unref(self->charger);
mce_display_remove_all_handlers(self->display, self->display_event_id);
mce_display_unref(self->display);
grilio_channel_cancel_request(self->io, self->low_data_req_id, FALSE);
grilio_channel_cancel_request(self->io, self->charging_req_id, FALSE);
grilio_channel_unref(self->io);
sailfish_cell_info_unref(self->cell_info);
g_free(self);
}
static struct ril_devmon_io *ril_devmon_ds_start_io(struct ril_devmon *devmon,
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
{
DevMon *ds = ril_devmon_ds_cast(devmon);
DevMonIo *self = g_new0(DevMonIo, 1);
self->pub.free = ril_devmon_ds_io_free;
self->low_data_supported = TRUE;
self->charging_supported = TRUE;
self->io = grilio_channel_ref(io);
self->cell_info = sailfish_cell_info_ref(cell_info);
self->connman = ril_connman_ref(ds->connman);
self->connman_event_id[CONNMAN_EVENT_VALID] =
ril_connman_add_property_changed_handler(self->connman,
RIL_CONNMAN_PROPERTY_VALID,
ril_devmon_ds_io_connman_cb, self);
self->connman_event_id[CONNMAN_EVENT_TETHERING] =
ril_connman_add_property_changed_handler(self->connman,
RIL_CONNMAN_PROPERTY_TETHERING,
ril_devmon_ds_io_connman_cb, self);
self->battery = mce_battery_ref(ds->battery);
self->battery_event_id[BATTERY_EVENT_VALID] =
mce_battery_add_valid_changed_handler(self->battery,
ril_devmon_ds_io_battery_cb, self);
self->battery_event_id[BATTERY_EVENT_STATUS] =
mce_battery_add_status_changed_handler(self->battery,
ril_devmon_ds_io_battery_cb, self);
self->charger = mce_charger_ref(ds->charger);
self->charger_event_id[CHARGER_EVENT_VALID] =
mce_charger_add_valid_changed_handler(self->charger,
ril_devmon_ds_io_charger_cb, self);
self->charger_event_id[CHARGER_EVENT_STATE] =
mce_charger_add_state_changed_handler(self->charger,
ril_devmon_ds_io_charger_cb, self);
self->display = mce_display_ref(ds->display);
self->display_event_id[DISPLAY_EVENT_VALID] =
mce_display_add_valid_changed_handler(self->display,
ril_devmon_ds_io_display_cb, self);
self->display_event_id[DISPLAY_EVENT_STATE] =
mce_display_add_state_changed_handler(self->display,
ril_devmon_ds_io_display_cb, self);
self->cell_info_interval_short_ms =
ds->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
ds->cell_info_interval_long_ms;
ril_devmon_ds_io_update_low_data(self);
ril_devmon_ds_io_update_charging(self);
ril_devmon_ds_io_set_cell_info_update_interval(self);
return &self->pub;
}
static void ril_devmon_ds_free(struct ril_devmon *devmon)
{
DevMon *self = ril_devmon_ds_cast(devmon);
ril_connman_unref(self->connman);
mce_battery_unref(self->battery);
mce_charger_unref(self->charger);
mce_display_unref(self->display);
g_free(self);
}
struct ril_devmon *ril_devmon_ds_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
self->pub.free = ril_devmon_ds_free;
self->pub.start_io = ril_devmon_ds_start_io;
self->connman = ril_connman_new();
self->battery = mce_battery_new();
self->charger = mce_charger_new();
self->display = mce_display_new();
self->cell_info_interval_short_ms =
config->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
config->cell_info_interval_long_ms;
return &self->pub;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,261 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_devmon.h"
#include <ofono/log.h>
#include <ofono/ril-constants.h>
#include <mce_battery.h>
#include <mce_charger.h>
#include <mce_display.h>
#include <grilio_channel.h>
#include <grilio_request.h>
#include <gutil_macros.h>
enum ril_devmon_ss_battery_event {
BATTERY_EVENT_VALID,
BATTERY_EVENT_STATUS,
BATTERY_EVENT_COUNT
};
enum ril_devmon_ss_charger_event {
CHARGER_EVENT_VALID,
CHARGER_EVENT_STATE,
CHARGER_EVENT_COUNT
};
enum ril_devmon_ss_display_event {
DISPLAY_EVENT_VALID,
DISPLAY_EVENT_STATE,
DISPLAY_EVENT_COUNT
};
typedef struct ril_devmon_ss {
struct ril_devmon pub;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMon;
typedef struct ril_devmon_ss_io {
struct ril_devmon_io pub;
struct sailfish_cell_info *cell_info;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
GRilIoChannel *io;
gboolean display_on;
gboolean screen_state_supported;
gulong battery_event_id[BATTERY_EVENT_COUNT];
gulong charger_event_id[CHARGER_EVENT_COUNT];
gulong display_event_id[DISPLAY_EVENT_COUNT];
guint req_id;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMonIo;
inline static DevMon *ril_devmon_ss_cast(struct ril_devmon *pub)
{
return G_CAST(pub, DevMon, pub);
}
inline static DevMonIo *ril_devmon_ss_io_cast(struct ril_devmon_io *pub)
{
return G_CAST(pub, DevMonIo, pub);
}
static inline gboolean ril_devmon_ss_battery_ok(MceBattery *battery)
{
return battery->valid && battery->status >= MCE_BATTERY_OK;
}
static inline gboolean ril_devmon_ss_charging(MceCharger *charger)
{
return charger->valid && charger->state == MCE_CHARGER_ON;
}
static gboolean ril_devmon_ss_display_on(MceDisplay *display)
{
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
}
static void ril_devmon_ss_io_state_sent(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
DevMonIo *self = user_data;
self->req_id = 0;
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
/* This is a permanent failure */
DBG("RIL_REQUEST_SCREEN_STATE is not supported");
self->screen_state_supported = FALSE;
}
}
static void ril_devmon_ss_io_send_screen_state(DevMonIo *self)
{
/*
* RIL_REQUEST_SCREEN_STATE (deprecated on 2017-01-10)
*
* ((int *)data)[0] is == 1 for "Screen On"
* ((int *)data)[0] is == 0 for "Screen Off"
*/
if (self->screen_state_supported) {
GRilIoRequest *req = grilio_request_array_int32_new(1,
self->display_on);
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
self->req_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SCREEN_STATE, ril_devmon_ss_io_state_sent,
NULL, self);
grilio_request_unref(req);
}
}
static void ril_devmon_ss_io_set_cell_info_update_interval(DevMonIo *self)
{
sailfish_cell_info_set_update_interval(self->cell_info,
(self->display_on && (ril_devmon_ss_charging(self->charger) ||
ril_devmon_ss_battery_ok(self->battery))) ?
self->cell_info_interval_short_ms :
self->cell_info_interval_long_ms);
}
static void ril_devmon_ss_io_battery_cb(MceBattery *battery, void *user_data)
{
ril_devmon_ss_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ss_io_charger_cb(MceCharger *charger, void *user_data)
{
ril_devmon_ss_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ss_io_display_cb(MceDisplay *display, void *user_data)
{
DevMonIo *self = user_data;
const gboolean display_on = ril_devmon_ss_display_on(display);
if (self->display_on != display_on) {
self->display_on = display_on;
ril_devmon_ss_io_send_screen_state(self);
ril_devmon_ss_io_set_cell_info_update_interval(self);
}
}
static void ril_devmon_ss_io_free(struct ril_devmon_io *devmon_io)
{
DevMonIo *self = ril_devmon_ss_io_cast(devmon_io);
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
mce_battery_unref(self->battery);
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
mce_charger_unref(self->charger);
mce_display_remove_all_handlers(self->display, self->display_event_id);
mce_display_unref(self->display);
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
grilio_channel_unref(self->io);
sailfish_cell_info_unref(self->cell_info);
g_free(self);
}
static struct ril_devmon_io *ril_devmon_ss_start_io(struct ril_devmon *devmon,
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
{
DevMon *ss = ril_devmon_ss_cast(devmon);
DevMonIo *self = g_new0(DevMonIo, 1);
self->pub.free = ril_devmon_ss_io_free;
self->screen_state_supported = TRUE;
self->io = grilio_channel_ref(io);
self->cell_info = sailfish_cell_info_ref(cell_info);
self->battery = mce_battery_ref(ss->battery);
self->battery_event_id[BATTERY_EVENT_VALID] =
mce_battery_add_valid_changed_handler(self->battery,
ril_devmon_ss_io_battery_cb, self);
self->battery_event_id[BATTERY_EVENT_STATUS] =
mce_battery_add_status_changed_handler(self->battery,
ril_devmon_ss_io_battery_cb, self);
self->charger = mce_charger_ref(ss->charger);
self->charger_event_id[CHARGER_EVENT_VALID] =
mce_charger_add_valid_changed_handler(self->charger,
ril_devmon_ss_io_charger_cb, self);
self->charger_event_id[CHARGER_EVENT_STATE] =
mce_charger_add_state_changed_handler(self->charger,
ril_devmon_ss_io_charger_cb, self);
self->display = mce_display_ref(ss->display);
self->display_on = ril_devmon_ss_display_on(self->display);
self->display_event_id[DISPLAY_EVENT_VALID] =
mce_display_add_valid_changed_handler(self->display,
ril_devmon_ss_io_display_cb, self);
self->display_event_id[DISPLAY_EVENT_STATE] =
mce_display_add_state_changed_handler(self->display,
ril_devmon_ss_io_display_cb, self);
self->cell_info_interval_short_ms =
ss->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
ss->cell_info_interval_long_ms;
ril_devmon_ss_io_send_screen_state(self);
ril_devmon_ss_io_set_cell_info_update_interval(self);
return &self->pub;
}
static void ril_devmon_ss_free(struct ril_devmon *devmon)
{
DevMon *self = ril_devmon_ss_cast(devmon);
mce_battery_unref(self->battery);
mce_charger_unref(self->charger);
mce_display_unref(self->display);
g_free(self);
}
struct ril_devmon *ril_devmon_ss_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
self->pub.free = ril_devmon_ss_free;
self->pub.start_io = ril_devmon_ss_start_io;
self->battery = mce_battery_new();
self->charger = mce_charger_new();
self->display = mce_display_new();
self->cell_info_interval_short_ms =
config->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
config->cell_info_interval_long_ms;
return &self->pub;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,267 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC
*
* 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_devmon.h"
#include <ofono/log.h>
#include <ofono/ril-constants.h>
#include <mce_battery.h>
#include <mce_charger.h>
#include <mce_display.h>
#include <grilio_channel.h>
#include <grilio_request.h>
#include <gutil_macros.h>
#define RIL_UR_ENABLE_ALL (RIL_UR_SIGNAL_STRENGTH | \
RIL_UR_FULL_NETWORK_STATE | \
RIL_UR_DATA_CALL_DORMANCY_CHANGED)
enum ril_devmon_ur_battery_event {
BATTERY_EVENT_VALID,
BATTERY_EVENT_STATUS,
BATTERY_EVENT_COUNT
};
enum ril_devmon_ur_charger_event {
CHARGER_EVENT_VALID,
CHARGER_EVENT_STATE,
CHARGER_EVENT_COUNT
};
enum ril_devmon_ur_display_event {
DISPLAY_EVENT_VALID,
DISPLAY_EVENT_STATE,
DISPLAY_EVENT_COUNT
};
typedef struct ril_devmon_ur {
struct ril_devmon pub;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMon;
typedef struct ril_devmon_ur_io {
struct ril_devmon_io pub;
struct sailfish_cell_info *cell_info;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
GRilIoChannel *io;
gboolean display_on;
gboolean unsol_filter_supported;
gulong battery_event_id[BATTERY_EVENT_COUNT];
gulong charger_event_id[CHARGER_EVENT_COUNT];
gulong display_event_id[DISPLAY_EVENT_COUNT];
guint req_id;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
} DevMonIo;
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
inline static DevMon *ril_devmon_ur_cast(struct ril_devmon *pub)
{
return G_CAST(pub, DevMon, pub);
}
inline static DevMonIo *ril_devmon_ur_io_cast(struct ril_devmon_io *pub)
{
return G_CAST(pub, DevMonIo, pub);
}
static inline gboolean ril_devmon_ur_battery_ok(MceBattery *battery)
{
return battery->valid && battery->status >= MCE_BATTERY_OK;
}
static inline gboolean ril_devmon_ur_charging(MceCharger *charger)
{
return charger->valid && charger->state == MCE_CHARGER_ON;
}
static gboolean ril_devmon_ur_display_on(MceDisplay *display)
{
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
}
static void ril_devmon_ur_io_unsol_response_filter_sent(GRilIoChannel *io,
int status, const void *data, guint len,
void *user_data)
{
DevMonIo *self = user_data;
self->req_id = 0;
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
/* This is a permanent failure */
DBG_(self, "Unsolicited response filter is not supported");
self->unsol_filter_supported = FALSE;
}
}
static void ril_devmon_ur_io_set_unsol_response_filter(DevMonIo *self)
{
if (self->unsol_filter_supported) {
const gint32 value = self->display_on ? RIL_UR_ENABLE_ALL : 0;
GRilIoRequest *req = grilio_request_array_int32_new(1, value);
DBG_(self, "Setting unsolicited response filter: %u", value);
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
self->req_id =
grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER,
ril_devmon_ur_io_unsol_response_filter_sent,
NULL, self);
grilio_request_unref(req);
}
}
static void ril_devmon_ur_io_set_cell_info_update_interval(DevMonIo *self)
{
sailfish_cell_info_set_update_interval(self->cell_info,
(self->display_on && (ril_devmon_ur_charging(self->charger) ||
ril_devmon_ur_battery_ok(self->battery))) ?
self->cell_info_interval_short_ms :
self->cell_info_interval_long_ms);
}
static void ril_devmon_ur_io_battery_cb(MceBattery *battery, void *user_data)
{
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ur_io_charger_cb(MceCharger *charger, void *user_data)
{
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ur_io_display_cb(MceDisplay *display, void *user_data)
{
DevMonIo *self = user_data;
const gboolean display_on = ril_devmon_ur_display_on(display);
if (self->display_on != display_on) {
self->display_on = display_on;
ril_devmon_ur_io_set_unsol_response_filter(self);
ril_devmon_ur_io_set_cell_info_update_interval(self);
}
}
static void ril_devmon_ur_io_free(struct ril_devmon_io *devmon_io)
{
DevMonIo *self = ril_devmon_ur_io_cast(devmon_io);
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
mce_battery_unref(self->battery);
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
mce_charger_unref(self->charger);
mce_display_remove_all_handlers(self->display, self->display_event_id);
mce_display_unref(self->display);
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
grilio_channel_unref(self->io);
sailfish_cell_info_unref(self->cell_info);
g_free(self);
}
static struct ril_devmon_io *ril_devmon_ur_start_io(struct ril_devmon *devmon,
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
{
DevMon *ur = ril_devmon_ur_cast(devmon);
DevMonIo *self = g_new0(DevMonIo, 1);
self->pub.free = ril_devmon_ur_io_free;
self->unsol_filter_supported = TRUE;
self->io = grilio_channel_ref(io);
self->cell_info = sailfish_cell_info_ref(cell_info);
self->battery = mce_battery_ref(ur->battery);
self->battery_event_id[BATTERY_EVENT_VALID] =
mce_battery_add_valid_changed_handler(self->battery,
ril_devmon_ur_io_battery_cb, self);
self->battery_event_id[BATTERY_EVENT_STATUS] =
mce_battery_add_status_changed_handler(self->battery,
ril_devmon_ur_io_battery_cb, self);
self->charger = mce_charger_ref(ur->charger);
self->charger_event_id[CHARGER_EVENT_VALID] =
mce_charger_add_valid_changed_handler(self->charger,
ril_devmon_ur_io_charger_cb, self);
self->charger_event_id[CHARGER_EVENT_STATE] =
mce_charger_add_state_changed_handler(self->charger,
ril_devmon_ur_io_charger_cb, self);
self->display = mce_display_ref(ur->display);
self->display_on = ril_devmon_ur_display_on(self->display);
self->display_event_id[DISPLAY_EVENT_VALID] =
mce_display_add_valid_changed_handler(self->display,
ril_devmon_ur_io_display_cb, self);
self->display_event_id[DISPLAY_EVENT_STATE] =
mce_display_add_state_changed_handler(self->display,
ril_devmon_ur_io_display_cb, self);
self->cell_info_interval_short_ms =
ur->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
ur->cell_info_interval_long_ms;
ril_devmon_ur_io_set_unsol_response_filter(self);
ril_devmon_ur_io_set_cell_info_update_interval(self);
return &self->pub;
}
static void ril_devmon_ur_free(struct ril_devmon *devmon)
{
DevMon *self = ril_devmon_ur_cast(devmon);
mce_battery_unref(self->battery);
mce_charger_unref(self->charger);
mce_display_unref(self->display);
g_free(self);
}
struct ril_devmon *ril_devmon_ur_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
self->pub.free = ril_devmon_ur_free;
self->pub.start_io = ril_devmon_ur_start_io;
self->battery = mce_battery_new();
self->charger = mce_charger_new();
self->display = mce_display_new();
self->cell_info_interval_short_ms =
config->cell_info_interval_short_ms;
self->cell_info_interval_long_ms =
config->cell_info_interval_long_ms;
return &self->pub;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,301 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#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_parse(const char *content)
{
char **ptr;
char **list = NULL;
guint i;
/*
* Some MediaTek devices use ECC,CAT;ECC,CAT kind of syntax
*/
if (strchr(content, ';')) {
list = g_strsplit(content, ";", 0);
for (ptr = list; *ptr; ptr++) {
char* comma;
*ptr = g_strstrip(*ptr);
/* Strip service category */
comma = strchr(*ptr, ',');
if (comma) {
*comma = 0;
}
}
} else {
/* The right ECC,ECC syntax is handled here */
list = g_strsplit(content, ",", 0);
for (ptr = list; *ptr; ptr++) {
*ptr = g_strstrip(*ptr);
}
}
/* Sort the list */
gutil_strv_sort(list, TRUE);
/* Remove empty strings (those are at the beginning after sorting) */
while (list[0] && !list[0][0]) {
list = gutil_strv_remove_at(list, 0, TRUE);
}
/* Remove duplicates */
for (i = 0; list[i] && list[i+1]; i++) {
while (list[i+1] && !strcmp(list[i], list[i+1])) {
list = gutil_strv_remove_at(list, i+1, TRUE);
}
}
return list;
}
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)) {
DBG("%s = %s", priv->name, content);
list = ril_ecclist_parse(content);
} else {
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);
DBG("%swatching %s", priv->file_watch ? "" : "not ",
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

@@ -1,48 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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"
#include <glib-object.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

@@ -1,283 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_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

@@ -1,602 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 <gutil_strv.h>
#include <arpa/inet.h>
#include "ofono.h"
#include "common.h"
#include "mtu-watch.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_id;
struct 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 *bits)
{
if (bits) {
int nbits = atoi(bits);
if (nbits > 0 && nbits < 33) {
const char* str;
struct in_addr in;
in.s_addr = htonl((nbits == 32) ? 0xffffffff :
((1u << nbits)-1) << (32-nbits));
str = inet_ntoa(in);
if (str) {
return g_strdup(str);
}
}
}
return NULL;
}
static int ril_gprs_context_address_family(const char *addr)
{
if (strchr(addr, ':')) {
return AF_INET6;
} else if (strchr(addr, '.')) {
return AF_INET;
} else {
return AF_UNSPEC;
}
}
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
{
if (gcd->active_call) {
ril_data_call_release(gcd->data, gcd->active_call->cid, gcd);
ril_data_call_free(gcd->active_call);
gcd->active_call = NULL;
}
if (gcd->calls_changed_id) {
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
gcd->calls_changed_id = 0;
}
if (gcd->mtu_watch) {
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 = mtu_watch_new(MAX_MTU);
}
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
ril_data_call_grab(gcd->data, call->cid, gcd);
} else {
ril_gprs_context_free_active_call(gcd);
}
}
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_context_set_address(struct ofono_gprs_context *gc,
const struct ril_data_call *call)
{
const char *ip_addr = NULL;
char *ip_mask = NULL;
const char *ipv6_addr = NULL;
unsigned char ipv6_prefix_length = 0;
char *tmp_ip_addr = NULL;
char *tmp_ipv6_addr = NULL;
char * const *list = call->addresses;
const int n = gutil_strv_length(list);
int i;
for (i = 0; i < n && (!ipv6_addr || !ip_addr); i++) {
const char *addr = list[i];
switch (ril_gprs_context_address_family(addr)) {
case AF_INET:
if (!ip_addr) {
const char* s = strstr(addr, "/");
if (s) {
const gsize len = s - addr;
tmp_ip_addr = g_strndup(addr, len);
ip_addr = tmp_ip_addr;
ip_mask = ril_gprs_context_netmask(s+1);
} else {
ip_addr = addr;
}
if (!ip_mask) {
ip_mask = g_strdup("255.255.255.0");
}
}
break;
case AF_INET6:
if (!ipv6_addr) {
const char* s = strstr(addr, "/");
if (s) {
const gsize len = s - addr;
const int prefix = atoi(s + 1);
tmp_ipv6_addr = g_strndup(addr, len);
ipv6_addr = tmp_ipv6_addr;
if (prefix >= 0 && prefix <= 128) {
ipv6_prefix_length = prefix;
}
} else {
ipv6_addr = addr;
}
}
}
}
ofono_gprs_context_set_ipv4_address(gc, ip_addr, TRUE);
ofono_gprs_context_set_ipv4_netmask(gc, ip_mask);
ofono_gprs_context_set_ipv6_address(gc, ipv6_addr);
ofono_gprs_context_set_ipv6_prefix_length(gc, ipv6_prefix_length);
if (!ip_addr && !ipv6_addr) {
ofono_error("GPRS context: No IP address");
}
/* Allocate temporary strings */
g_free(ip_mask);
g_free(tmp_ip_addr);
g_free(tmp_ipv6_addr);
}
static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
const struct ril_data_call *call)
{
const char *ip_gw = NULL;
const char *ipv6_gw = NULL;
char * const *list = call->gateways;
const int n = gutil_strv_length(list);
int i;
/* Pick 1 gw for each protocol*/
for (i = 0; i < n && (!ipv6_gw || !ip_gw); i++) {
const char *addr = list[i];
switch (ril_gprs_context_address_family(addr)) {
case AF_INET:
if (!ip_gw) ip_gw = addr;
break;
case AF_INET6:
if (!ipv6_gw) ipv6_gw = addr;
break;
}
}
ofono_gprs_context_set_ipv4_gateway(gc, ip_gw);
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
}
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
const struct ril_data_call *call)
{
int i;
char * const *list = call->dnses;
const int n = gutil_strv_length(list);
const char **ip_dns = g_new0(const char *, n+1);
const char **ipv6_dns = g_new0(const char *, n+1);
const char **ip_ptr = ip_dns;
const char **ipv6_ptr = ipv6_dns;
for (i = 0; i < n; i++) {
const char *addr = list[i];
switch (ril_gprs_context_address_family(addr)) {
case AF_INET:
*ip_ptr++ = addr;
break;
case AF_INET6:
*ipv6_ptr++ = addr;
break;
}
}
ofono_gprs_context_set_ipv4_dns_servers(gc, ip_dns);
ofono_gprs_context_set_ipv6_dns_servers(gc, ipv6_dns);
g_free(ip_dns);
g_free(ipv6_dns);
}
/* Only compares the stuff that's important to us */
#define DATA_CALL_IFNAME_CHANGED (0x01)
#define DATA_CALL_ADDRESS_CHANGED (0x02)
#define DATA_CALL_GATEWAY_CHANGED (0x04)
#define DATA_CALL_DNS_CHANGED (0x08)
#define DATA_CALL_ALL_CHANGED (0x0f)
static int ril_gprs_context_data_call_change(
const struct ril_data_call *c1,
const struct ril_data_call *c2)
{
if (!c1 && !c2) {
return 0;
} else if (c1 && c2) {
int changes = 0;
if (g_strcmp0(c1->ifname, c2->ifname)) {
changes |= DATA_CALL_IFNAME_CHANGED;
}
if (!gutil_strv_equal(c1->addresses, c2->addresses)) {
changes |= DATA_CALL_ADDRESS_CHANGED;
}
if (!gutil_strv_equal(c1->gateways, c2->gateways)) {
changes |= DATA_CALL_GATEWAY_CHANGED;
}
if (!gutil_strv_equal(c1->dnses, c2->dnses)) {
changes |= DATA_CALL_DNS_CHANGED;
}
return changes;
} else {
return DATA_CALL_ALL_CHANGED;
}
}
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);
int change = 0;
if (call && call->active != RIL_DATA_CALL_INACTIVE) {
/* Compare it against the last known state */
change = ril_gprs_context_data_call_change(call, prev_call);
} else {
ofono_error("Clearing active context");
ril_gprs_context_set_disconnected(gcd);
call = NULL;
}
if (!call) {
/* We are not interested */
return;
} else if (!change) {
DBG("call %u didn't change", call->cid);
return;
} else {
DBG("call %u changed", call->cid);
}
/*
* 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 (change & DATA_CALL_IFNAME_CHANGED) {
DBG("interface changed");
ofono_gprs_context_set_interface(gc, call->ifname);
}
if (change & DATA_CALL_ADDRESS_CHANGED) {
DBG("address changed");
ril_gprs_context_set_address(gc, call);
}
if (change & DATA_CALL_GATEWAY_CHANGED) {
DBG("gateway changed");
ril_gprs_context_set_gateway(gc, call);
}
if (change & DATA_CALL_DNS_CHANGED) {
DBG("name server(s) changed");
ril_gprs_context_set_dns_servers(gc, call);
}
ofono_gprs_context_signal_change(gc, gcd->active_ctx_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;
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));
} else if (!call) {
ofono_error("Unexpected data call failure");
} else if (call->status != PDP_FAIL_NONE) {
ofono_error("Unexpected data call status %d", call->status);
error.type = OFONO_ERROR_TYPE_CMS;
error.error = call->status;
} else if (!call->ifname) {
/* Must have interface */
ofono_error("GPRS context: No interface");
} else {
ofono_info("setting up data call");
GASSERT(!gcd->calls_changed_id);
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
gcd->calls_changed_id =
ril_data_add_calls_changed_handler(gcd->data,
ril_gprs_context_call_list_changed, gcd);
ril_gprs_context_set_active_call(gcd, call);
ofono_gprs_context_set_interface(gc, call->ifname);
ril_gprs_context_set_address(gc, call);
ril_gprs_context_set_gateway(gc, call);
ril_gprs_context_set_dns_servers(gc, call);
ril_error_init_ok(&error);
}
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
gcd->active_ctx_cid = CTX_ID_NONE;
}
cb = gcd->activate.cb;
cb_data = gcd->activate.data;
GASSERT(gcd->activate.req);
memset(&gcd->activate, 0, sizeof(gcd->activate));
if (cb) {
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 %u (roaming)",
ctx->cid);
cb(ril_error_failure(&error), data);
return;
}
}
ofono_info("Activating context: %u", 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,
__ofono_gprs_context_get_assigned_type(gc),
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) {
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);
ofono_info("Deactivated data call");
} else {
ofono_error("Deactivate failure: %s",
ril_error_to_string(ril_status));
}
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
if (cb) {
struct ofono_error error;
ril_gprs_context_free_active_call(gcd);
cb(ril_error_ok(&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_ctx_cid == id);
ofono_info("Deactivating context: %u", id);
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("%u", 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_id);
ril_data_unref(gcd->data);
ril_network_unref(gcd->network);
ril_data_call_free(gcd->active_call);
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

@@ -1,584 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* 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_cell_info.h"
#include "ril_vendor.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
#include "ofono.h"
#include <ofono/watch.h>
#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
};
enum ril_modem_watch_event {
WATCH_IMSI,
WATCH_ICCID,
WATCH_SIM_STATE,
WATCH_EVENT_COUNT
};
struct ril_modem_online_request {
const char *name;
ofono_modem_online_cb_t cb;
struct ril_modem_data *md;
void *data;
guint timeout_id;
};
struct ril_modem_data {
struct ril_modem modem;
struct ofono_watch *watch;
GRilIoQueue *q;
char *log_prefix;
char *imeisv;
char *imei;
char *ecclist_file;
gulong watch_event_id[WATCH_EVENT_COUNT];
char* last_known_iccid;
char* reset_iccid;
guint online_check_id;
enum ril_modem_power_state power_state;
gulong radio_state_event_id;
struct ril_modem_online_request set_online;
struct ril_modem_online_request set_offline;
};
#define RADIO_POWER_TAG(md) (md)
#define DBG_(md,fmt,args...) DBG("%s" fmt, (md)->log_prefix, ##args)
static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
{
struct ril_modem_data *md = ofono_modem_get_data(o);
GASSERT(md->modem.ofono == o);
return md;
}
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);
}
static inline struct ofono_radio_settings *ril_modem_radio_settings(
struct ril_modem *modem)
{
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
}
void ril_modem_delete(struct ril_modem *md)
{
if (md && md->ofono) {
ofono_modem_remove(md->ofono);
}
}
static void ril_modem_online_request_done(struct ril_modem_online_request *req)
{
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;
DBG_(req->md, "%s", req->name);
cb(ril_error_ok(&error), 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;
}
ril_modem_online_request_done(req);
}
static void ril_modem_update_online_state(struct ril_modem_data *md)
{
switch (md->modem.radio->state) {
case RADIO_STATE_ON:
DBG_(md, "online");
ril_modem_online_request_ok(&md->set_online);
break;
case RADIO_STATE_OFF:
case RADIO_STATE_UNAVAILABLE:
DBG_(md, "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;
GASSERT(req->timeout_id);
req->timeout_id = 0;
DBG_(req->md, "%s", req->name);
ril_modem_online_request_done(req);
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)
{
struct ril_modem *m = &md->modem;
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
if (md->watch->imsi) {
/* radio-settings.c assumes that IMSI is available */
if (!rs) {
DBG_(md, "initializing radio settings interface");
ofono_radio_settings_create(m->ofono, 0,
RILMODEM_DRIVER, md);
}
} else if (rs) {
DBG_(md, "removing radio settings interface");
ofono_radio_settings_remove(rs);
} else {
/* ofono core may remove radio settings atom internally */
DBG_(md, "radio settings interface is already gone");
}
}
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_online_state(md);
}
static void ril_modem_imsi_cb(struct ofono_watch *watch, void *data)
{
struct ril_modem_data *md = data;
GASSERT(md->watch == watch);
ril_modem_update_radio_settings(md);
}
static void ril_modem_iccid_cb(struct ofono_watch *watch, void *data)
{
struct ril_modem_data *md = data;
GASSERT(md->watch == watch);
if (watch->iccid) {
g_free(md->last_known_iccid);
md->last_known_iccid = g_strdup(watch->iccid);
DBG_(md, "%s", md->last_known_iccid);
}
}
static void ril_modem_sim_state_cb(struct ofono_watch *watch, void *data)
{
struct ril_modem_data *md = data;
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
GASSERT(md->watch == watch);
if (state == OFONO_SIM_STATE_RESETTING) {
g_free(md->reset_iccid);
md->reset_iccid = md->last_known_iccid;
md->last_known_iccid = NULL;
DBG_(md, "%s is resetting", md->reset_iccid);
}
}
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));
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
if (md->modem.config.enable_voicecall) {
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
}
if (!md->radio_state_event_id) {
md->radio_state_event_id =
ril_radio_add_state_changed_handler(md->modem.radio,
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) {
guint i;
static const enum ofono_gprs_context_type ap_types[] = {
OFONO_GPRS_CONTEXT_TYPE_INTERNET,
OFONO_GPRS_CONTEXT_TYPE_MMS,
OFONO_GPRS_CONTEXT_TYPE_IMS
};
/* Create a context for each type */
for (i = 0; i < G_N_ELEMENTS(ap_types); i++) {
struct ofono_gprs_context *gc =
ofono_gprs_context_create(modem, 0,
RILMODEM_DRIVER, md);
if (gc == NULL)
break;
ofono_gprs_context_set_type(gc, ap_types[i]);
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_message_waiting_register(ofono_message_waiting_create(modem));
if (md->modem.config.enable_stk) {
if (!md->reset_iccid ||
g_strcmp0(md->reset_iccid, md->watch->iccid)) {
/* This SIM was never reset */
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
} else {
ofono_warn("Disabling STK after SIM reset");
}
}
if (md->modem.config.enable_cbs) {
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
}
}
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);
ofono_netmon_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_radio *radio = md->modem.radio;
struct ril_modem_online_request *req;
DBG("%s going %sline", ofono_modem_get_path(modem),
online ? "on" : "off");
ril_radio_set_online(radio, online);
if (online) {
ril_radio_power_on(radio, RADIO_POWER_TAG(md));
req = &md->set_online;
} else {
ril_radio_power_off(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));
ofono_modem_set_data(ofono, NULL);
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
ril_radio_set_online(modem->radio, FALSE);
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
ril_radio_set_online(modem->radio, FALSE);
ril_radio_unref(modem->radio);
ril_sim_settings_unref(modem->sim_settings);
ofono_watch_remove_all_handlers(md->watch, md->watch_event_id);
ofono_watch_unref(md->watch);
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_vendor_unref(modem->vendor);
ril_network_unref(modem->network);
ril_sim_card_unref(modem->sim_card);
ril_data_unref(modem->data);
sailfish_cell_info_unref(modem->cell_info);
grilio_channel_unref(modem->io);
grilio_queue_cancel_all(md->q, FALSE);
grilio_queue_unref(md->q);
g_free(md->last_known_iccid);
g_free(md->reset_iccid);
g_free(md->ecclist_file);
g_free(md->log_prefix);
g_free(md->imeisv);
g_free(md->imei);
g_free(md);
}
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const char *path, const char *imei, const char *imeisv,
const char *ecclist_file, const struct ril_slot_config *config,
struct ril_radio *radio, struct ril_network *network,
struct ril_sim_card *card, struct ril_data *data,
struct ril_sim_settings *settings, struct ril_vendor *vendor,
struct sailfish_cell_info *cell_info)
{
/* Skip the slash from the path, it looks like "/ril_0" */
struct ofono_modem *ofono = ofono_modem_create(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(imei);
/* Copy config */
modem->config = *config;
modem->imei = md->imei = g_strdup(imei);
modem->imeisv = md->imeisv = g_strdup(imeisv);
modem->log_prefix = log_prefix; /* No need to strdup */
modem->ecclist_file = ecclist_file; /* No need to strdup */
md->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
modem->ofono = ofono;
modem->vendor = ril_vendor_ref(vendor);
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->cell_info = sailfish_cell_info_ref(cell_info);
modem->data = ril_data_ref(data);
modem->io = grilio_channel_ref(io);
md->q = grilio_queue_new(io);
md->watch = ofono_watch_new(path);
md->last_known_iccid = g_strdup(md->watch->iccid);
md->watch_event_id[WATCH_IMSI] =
ofono_watch_add_imsi_changed_handler(md->watch,
ril_modem_imsi_cb, md);
md->watch_event_id[WATCH_ICCID] =
ofono_watch_add_iccid_changed_handler(md->watch,
ril_modem_iccid_cb, md);
md->watch_event_id[WATCH_SIM_STATE] =
ofono_watch_add_sim_state_changed_handler(md->watch,
ril_modem_sim_state_cb, md);
md->set_online.name = "online";
md->set_online.md = md;
md->set_offline.name = "offline";
md->set_offline.md = md;
ofono_modem_set_data(ofono, md);
err = ofono_modem_register(ofono);
if (!err) {
GASSERT(io->connected);
if (config->radio_power_cycle) {
ril_radio_power_cycle(modem->radio);
}
/*
* 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.
*/
if (config->query_available_band_mode) {
grilio_queue_send_request(md->q, NULL,
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE);
}
ril_modem_update_radio_settings(md);
return modem;
} 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:
*/

View File

@@ -1,324 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 <sailfish_cell_info.h>
#include "ofono.h"
struct ril_netmon {
struct ofono_netmon *netmon;
struct sailfish_cell_info *cell_info;
guint register_id;
};
/* This number must be in sync with ril_netmon_notify_ofono: */
#define RIL_NETMON_MAX_OFONO_PARAMS (8)
struct ril_netmon_ofono_param {
enum ofono_netmon_info type;
int value;
};
static inline struct ril_netmon *ril_netmon_get_data(struct ofono_netmon *ofono)
{
return ofono ? ofono_netmon_get_data(ofono) : NULL;
}
static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
{
s_mcc[0] = 0;
s_mnc[0] = 0;
if (mcc >= 0 && mcc <= 999) {
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
if (mnc >= 0 && mnc <= 999) {
const unsigned int mnclen = mnclength(mcc, mnc);
const char *format[] = { "%d", "%02d", "%03d" };
const char *fmt = (mnclen > 0 &&
mnclen <= G_N_ELEMENTS(format)) ?
format[mnclen - 1] : format[0];
snprintf(s_mnc, OFONO_MAX_MNC_LENGTH + 1, fmt, mnc);
}
}
}
static void ril_netmon_notify_ofono(struct ofono_netmon *netmon,
enum ofono_netmon_cell_type type, int mcc, int mnc,
struct ril_netmon_ofono_param *params, int nparams)
{
char s_mcc[OFONO_MAX_MCC_LENGTH + 1];
char s_mnc[OFONO_MAX_MNC_LENGTH + 1];
int i;
/* Better not to push uninitialized data to the stack ... */
for (i = nparams; i < RIL_NETMON_MAX_OFONO_PARAMS; i++) {
params[i].type = OFONO_NETMON_INFO_INVALID;
params[i].value = SAILFISH_CELL_INVALID_VALUE;
}
ril_netmon_format_mccmnc(s_mcc, s_mnc, mcc, mnc);
ofono_netmon_serving_cell_notify(netmon, type,
OFONO_NETMON_INFO_MCC, s_mcc,
OFONO_NETMON_INFO_MNC, s_mnc,
params[0].type, params[0].value,
params[1].type, params[1].value,
params[2].type, params[2].value,
params[3].type, params[3].value,
params[4].type, params[4].value,
params[5].type, params[5].value,
params[6].type, params[6].value,
params[7].type, params[7].value,
OFONO_NETMON_INFO_INVALID);
}
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
const struct sailfish_cell_info_gsm *gsm)
{
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
int n = 0;
if (gsm->lac != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_LAC;
params[n].value = gsm->lac;
n++;
}
if (gsm->cid != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CI;
params[n].value = gsm->cid;
n++;
}
if (gsm->arfcn != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_ARFCN;
params[n].value = gsm->arfcn;
n++;
}
if (gsm->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSSI;
params[n].value = gsm->signalStrength;
n++;
}
if (gsm->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_BER;
params[n].value = gsm->bitErrorRate;
n++;
}
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_GSM,
gsm->mcc, gsm->mnc, params, n);
}
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
const struct sailfish_cell_info_wcdma *wcdma)
{
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
int n = 0;
if (wcdma->lac != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_LAC;
params[n].value = wcdma->lac;
n++;
}
if (wcdma->cid != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CI;
params[n].value = wcdma->cid;
n++;
}
if (wcdma->psc != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_PSC;
params[n].value = wcdma->psc;
n++;
}
if (wcdma->uarfcn != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_ARFCN;
params[n].value = wcdma->uarfcn;
n++;
}
if (wcdma->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSSI;
params[n].value = wcdma->signalStrength;
n++;
}
if (wcdma->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_BER;
params[n].value = wcdma->bitErrorRate;
n++;
}
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_UMTS,
wcdma->mcc, wcdma->mnc, params, n);
}
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
const struct sailfish_cell_info_lte *lte)
{
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
int n = 0;
if (lte->ci != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CI;
params[n].value = lte->ci;
n++;
}
if (lte->earfcn != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_EARFCN;
params[n].value = lte->earfcn;
n++;
}
if (lte->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSSI;
params[n].value = lte->signalStrength;
n++;
}
if (lte->rsrp != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSRQ;
params[n].value = lte->rsrp;
n++;
}
if (lte->rsrq != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSRP;
params[n].value = lte->rsrq;
n++;
}
if (lte->cqi != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CQI;
params[n].value = lte->cqi;
n++;
}
if (lte->timingAdvance != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_TIMING_ADVANCE;
params[n].value = lte->timingAdvance;
n++;
}
ril_netmon_notify_ofono(netmon, OFONO_NETMON_CELL_TYPE_LTE,
lte->mcc, lte->mnc, params, n);
}
static void ril_netmon_request_update(struct ofono_netmon *netmon,
ofono_netmon_cb_t cb, void *data)
{
struct ril_netmon *nm = ril_netmon_get_data(netmon);
struct ofono_error error;
GSList *l;
for (l = nm->cell_info->cells; l; l = l->next) {
const struct sailfish_cell *cell = l->data;
if (cell->registered) {
switch (cell->type) {
case SAILFISH_CELL_TYPE_GSM:
ril_netmon_notify_gsm(netmon,
&cell->info.gsm);
break;
case SAILFISH_CELL_TYPE_WCDMA:
ril_netmon_notify_wcdma(netmon,
&cell->info.wcdma);
break;
case SAILFISH_CELL_TYPE_LTE:
ril_netmon_notify_lte(netmon,
&cell->info.lte);
break;
default:
break;
}
}
}
cb(ril_error_ok(&error), data);
}
static gboolean ril_netmon_register(gpointer user_data)
{
struct ril_netmon *nm = user_data;
GASSERT(nm->register_id);
nm->register_id = 0;
ofono_netmon_register(nm->netmon);
return G_SOURCE_REMOVE;
}
static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
int ret;
if (modem->cell_info) {
struct ril_netmon *nm = g_slice_new0(struct ril_netmon);
nm->cell_info = sailfish_cell_info_ref(modem->cell_info);
nm->netmon = netmon;
ofono_netmon_set_data(netmon, nm);
nm->register_id = g_idle_add(ril_netmon_register, nm);
ret = 0;
} else {
DBG("%s no", modem->log_prefix ? modem->log_prefix : "");
ret = -1;
}
DBG("%s %d", modem->log_prefix ? modem->log_prefix : "", ret);
return ret;
}
static void ril_netmon_remove(struct ofono_netmon *netmon)
{
struct ril_netmon *nm = ril_netmon_get_data(netmon);
DBG("");
ofono_netmon_set_data(netmon, NULL);
if (nm->register_id > 0) {
g_source_remove(nm->register_id);
}
sailfish_cell_info_unref(nm->cell_info);
g_slice_free(struct ril_netmon, nm);
}
const struct ofono_netmon_driver ril_netmon_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_netmon_probe,
.remove = ril_netmon_remove,
.request_update = ril_netmon_request_update,
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,732 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
*
* 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_vendor.h"
#include "ril_log.h"
#include "ofono.h"
#include "common.h"
#include "simutil.h"
#include <ofono/watch.h>
#define REGISTRATION_MAX_RETRIES (2)
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;
gboolean replace_strange_oper;
gboolean network_selection_manual_0;
int signal_strength_dbm_weak;
int signal_strength_dbm_strong;
struct ofono_watch *watch;
struct ofono_netreg *netreg;
struct ril_network *network;
struct ril_vendor *vendor;
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];
int network_selection_timeout;
};
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
#define DBG_(nd,fmt,args...) DBG("%s" fmt, (nd)->log_prefix, ##args)
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
{
return ofono ? ofono_netreg_get_data(ofono) : NULL;
}
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_(nd, "");
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_(nd, "notification aready queued");
} else {
DBG_(nd, "queuing notification");
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_(nd, "");
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_(nd, "");
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 gboolean ril_netreg_strange(const struct ofono_network_operator *op,
struct ofono_sim *sim)
{
gsize mcclen;
if (sim && op->status != OPERATOR_STATUS_CURRENT) {
const char *spn = ofono_sim_get_spn(sim);
const char *mcc = ofono_sim_get_mcc(sim);
const char *mnc = ofono_sim_get_mnc(sim);
if (spn && mcc && mnc && !strcmp(op->name, spn) &&
(strcmp(op->mcc, mcc) || strcmp(op->mnc, mnc))) {
/*
* Status is not "current", SPN matches the SIM, but
* MCC and/or MNC don't (e.g. Sony Xperia X where all
* operators could be reported with the same name
* which equals SPN).
*/
DBG("%s %s%s (sim spn?)", op->name, op->mcc, op->mnc);
return TRUE;
}
}
mcclen = strlen(op->mcc);
if (!strncmp(op->name, op->mcc, mcclen) &&
!strcmp(op->name + mcclen, op->mnc)) {
/* Some MediaTek RILs only report numeric operator name */
DBG("%s %s%s (numeric?)", op->name, op->mcc, op->mnc);
return TRUE;
}
return FALSE;
}
static void ril_netreg_process_operators(struct ril_netreg *nd,
struct ofono_network_operator *ops, int nops)
{
if (nd->replace_strange_oper) {
int i;
for (i = 0; i < nops; i++) {
struct ofono_network_operator *op = ops + i;
struct ofono_gprs_provision_data *prov = NULL;
int np = 0;
if (ril_netreg_strange(op, nd->watch->sim) &&
__ofono_gprs_provision_get_settings(op->mcc,
op->mnc, NULL, &prov, &np)) {
/* Use the first entry */
if (np > 0 && prov->provider_name &&
prov->provider_name[0]) {
DBG("%s %s%s -> %s", op->name, op->mcc,
op->mnc, prov->provider_name);
strncpy(op->name, prov->provider_name,
OFONO_MAX_OPERATOR_NAME_LENGTH);
}
__ofono_gprs_provision_free_settings(prov, np);
}
}
}
}
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 ril_netreg *nd = cbd->nd;
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 (!status) {
op->status = OPERATOR_STATUS_UNKNOWN;
} else if (!strcmp(status, "available")) {
op->status = OPERATOR_STATUS_AVAILABLE;
} else if (!strcmp(status, "current")) {
op->status = OPERATOR_STATUS_CURRENT;
} else if (!strcmp(status, "forbidden")) {
op->status = OPERATOR_STATUS_FORBIDDEN;
} else {
op->status = OPERATOR_STATUS_UNKNOWN;
}
op->tech = -1;
ok = ril_parse_mcc_mnc(numeric, op);
if (ok) {
if (op->tech < 0) {
op->tech = 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) {
ril_netreg_process_operators(nd, list, noperators);
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_set_register_auto(struct ril_netreg *nd,
ofono_netreg_register_cb_t cb, void *data)
{
GRilIoRequest *req = grilio_request_new();
ofono_info("nw select automatic");
grilio_request_set_timeout(req, nd->network_selection_timeout);
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
ril_netreg_register_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, cb, data));
grilio_request_unref(req);
}
static void ril_netreg_query_register_auto_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;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
gint32 net_mode;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, NULL) /* Array length */ &&
grilio_parser_get_int32(&rilp, &net_mode) &&
net_mode == RIL_NETWORK_SELECTION_MODE_AUTO) {
struct ofono_error error;
ofono_info("nw selection is already auto");
cb(ril_error_ok(&error), cbd->data);
return;
}
}
ril_netreg_set_register_auto(cbd->nd, cb, 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);
GRilIoRequest *req = grilio_request_new();
grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE,
ril_netreg_query_register_auto_cb, ril_netreg_cbd_free,
ril_netreg_cbd_new(nd, cb, data));
grilio_request_unref(req);
}
static void ril_netreg_register_manual(struct ofono_netreg *netreg,
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();
const char *suffix = nd->network_selection_manual_0 ? "+0" : "";
ofono_info("nw select manual: %s%s%s", mcc, mnc, suffix);
grilio_request_append_format(req, "%s%s%s", mcc, mnc, suffix);
grilio_request_set_timeout(req, nd->network_selection_timeout);
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_qdbm_to_percentage(struct ril_netreg *nd, int qdbm)
{
const int min_qdbm = 4 * nd->signal_strength_dbm_weak; /* 4*dBm */
const int max_qdbm = 4 * nd->signal_strength_dbm_strong; /* 4*dBm */
return (qdbm <= min_qdbm) ? 1 :
(qdbm >= max_qdbm) ? 100 :
(100 * (qdbm - min_qdbm) / (max_qdbm - min_qdbm));
}
static int ril_netreg_get_signal_strength(struct ril_netreg *nd,
const void *data, guint len)
{
GRilIoParser rilp;
struct ril_vendor_signal_strength signal;
grilio_parser_init(&rilp, data, len);
signal.gsm = INT_MAX;
signal.lte = INT_MAX;
signal.qdbm = 0;
if (!ril_vendor_signal_strength_parse(nd->vendor, &signal, &rilp)) {
gint32 rsrp = 0, tdscdma_dbm = 0;
/* Apply default parsing algorithm */
grilio_parser_init(&rilp, data, len);
signal.gsm = INT_MAX;
signal.lte = INT_MAX;
signal.qdbm = 0;
/* GW_SignalStrength */
grilio_parser_get_int32(&rilp, &signal.gsm);
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
/* CDMA_SignalStrength */
grilio_parser_get_int32(&rilp, NULL); /* dbm */
grilio_parser_get_int32(&rilp, NULL); /* ecio */
/* EVDO_SignalStrength */
grilio_parser_get_int32(&rilp, NULL); /* dbm */
grilio_parser_get_int32(&rilp, NULL); /* ecio */
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
/* LTE_SignalStrength */
grilio_parser_get_int32(&rilp, &signal.lte);
grilio_parser_get_int32(&rilp, &rsrp);
/* The rest is considered optional */
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
grilio_parser_get_int32(&rilp, NULL) && /* cqi */
grilio_parser_get_int32(&rilp, NULL) && /* timingAdv */
/* TD_SCDMA_SignalStrength */
grilio_parser_get_int32(&rilp, &tdscdma_dbm) &&
/* RSCP range: 25 to 120 dBm per 3GPP TS 25.123 */
tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
signal.qdbm = -4 * tdscdma_dbm;
} else if (signal.lte == 99 && rsrp >= 44 && rsrp <= 140) {
/* RSRP range: 44 to 140 dBm per 3GPP TS 36.133 */
signal.qdbm = -4 * rsrp;
}
}
DBG("gw: %d, lte: %d, qdbm: %d", signal.gsm, signal.lte, signal.qdbm);
/* Return the first valid one */
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
* RSRP value. If we've got zero, don't report it just yet. */
if (signal.gsm >= 1 && signal.gsm <= 31) {
/* Valid values are (0-31, 99) as defined in TS 27.007 */
return (signal.gsm * 100) / 31;
}
/* Valid values are (0-31, 99) as defined in TS 27.007 */
if (signal.lte >= 0 && signal.lte <= 31) {
return (signal.lte * 100) / 31;
}
if (signal.qdbm < 0) {
return ril_netreg_qdbm_to_percentage(nd, signal.qdbm);
} else if (signal.gsm == 0) {
return 0;
} else {
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(nd, data, len);
DBG_(nd, "%d", strength);
if (strength >= 0) {
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) {
cb(ril_error_ok(&error), ril_netreg_get_signal_strength
(cbd->nd, data, len), 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;
int year, mon, mday, hour, min, sec, tzi, dst = 0;
char tzs;
gchar *nitz;
GASSERT(ril_event == RIL_UNSOL_NITZ_TIME_RECEIVED);
grilio_parser_init(&rilp, data, len);
nitz = grilio_parser_get_utf8(&rilp);
DBG_(nd, "%s", nitz);
/*
* Format: yy/mm/dd,hh:mm:ss(+/-)tz[,ds]
* The ds part is considered optional, initialized to zero.
*/
if (nitz && sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u",
&year, &mon, &mday, &hour, &min, &sec, &tzs, &tzi,
&dst) >= 8 && (tzs == '+' || tzs == '-')) {
struct ofono_network_time time;
char tz[4];
snprintf(tz, sizeof(tz), "%c%d", tzs, tzi);
time.utcoff = atoi(tz) * 15 * 60;
time.dst = dst;
time.sec = sec;
time.min = min;
time.hour = hour;
time.mday = mday;
time.mon = mon;
time.year = 2000 + year;
ofono_netreg_time_notify(nd->netreg, &time);
} else {
ofono_warn("Failed to parse NITZ string \"%s\"", nitz);
}
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);
const struct ril_slot_config *config = &modem->config;
nd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
DBG_(nd, "%p", netreg);
nd->io = grilio_channel_ref(ril_modem_io(modem));
nd->q = grilio_queue_new(nd->io);
nd->watch = ofono_watch_new(ril_modem_get_path(modem));
nd->vendor = ril_vendor_ref(modem->vendor);
nd->network = ril_network_ref(modem->network);
nd->netreg = netreg;
nd->replace_strange_oper = config->replace_strange_oper;
nd->network_selection_manual_0 = config->network_selection_manual_0;
nd->signal_strength_dbm_weak = config->signal_strength_dbm_weak;
nd->signal_strength_dbm_strong = config->signal_strength_dbm_strong;
nd->network_selection_timeout = config->network_selection_timeout;
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);
DBG_(nd, "%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);
}
ofono_watch_unref(nd->watch);
ril_network_remove_all_handlers(nd->network, nd->network_event_id);
ril_network_unref(nd->network);
ril_vendor_unref(nd->vendor);
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
grilio_channel_unref(nd->io);
grilio_queue_unref(nd->q);
g_free(nd->log_prefix);
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:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,88 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* 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 <glib-object.h>
struct ofono_network_operator;
struct ril_radio_caps;
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;
enum ofono_radio_access_mode max_pref_mode;
struct ril_sim_settings *settings;
};
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card,
struct ril_sim_settings *settings,
const struct ril_slot_config *ril_slot_config,
struct ril_vendor *vendor);
struct ril_network *ril_network_ref(struct ril_network *net);
void ril_network_unref(struct ril_network *net);
void ril_network_set_radio_caps(struct ril_network *net,
struct ril_radio_caps *caps);
void ril_network_set_max_pref_mode(struct ril_network *net,
enum ofono_radio_access_mode max_pref_mode,
gboolean force_check);
enum ofono_radio_access_mode ril_network_max_supported_mode
(struct ril_network *self);
void ril_network_query_registration_state(struct ril_network *net);
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
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);
#define ril_network_remove_all_handlers(net, ids) \
ril_network_remove_handlers(net, ids, G_N_ELEMENTS(ids))
#endif /* RIL_NETWORK_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,167 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* 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 {
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_done(void *msg)
{
dbus_message_unref(msg);
}
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;
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);
dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
&data, len);
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);
}
g_dbus_send_message(ofono_dbus_get_connection(), reply);
}
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
void *user_data)
{
DBusMessageIter it;
struct ril_oem_raw *oem = user_data;
if (!__ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
OFONO_DBUS_ACCESS_INTF_OEMRAW,
OFONO_DBUS_ACCESS_OEMRAW_SEND, NULL)) {
return __ofono_error_access_denied(msg);
}
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,
ril_oem_raw_send_done, 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->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);
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

@@ -1,117 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* 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 "sailfish_manager.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 <ofono/netmon.h>
#include <grilio_queue.h>
#include <grilio_request.h>
#include <grilio_parser.h>
#define RILMODEM_DRIVER "ril"
struct ril_modem {
GRilIoChannel *io;
const char *imei;
const char *imeisv;
const char *log_prefix;
const char *ecclist_file;
struct ofono_modem *ofono;
struct sailfish_cell_info *cell_info;
struct ril_vendor *vendor;
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;
};
struct ril_oem_raw;
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
const char *log_prefix);
void ril_oem_raw_free(struct ril_oem_raw *raw);
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const char *path, const char *imei, const char *imeisv,
const char *ecclist_file, const struct ril_slot_config *config,
struct ril_radio *radio, struct ril_network *network,
struct ril_sim_card *card, struct ril_data *data,
struct ril_sim_settings *settings, struct ril_vendor *vendor,
struct sailfish_cell_info *cell_info);
void ril_modem_delete(struct ril_modem *modem);
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
#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 *reg, gint status);
extern const struct ofono_call_barring_driver ril_call_barring_driver;
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;
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;
extern const struct ofono_netmon_driver ril_netmon_driver;
#endif /* RIL_PLUGIN_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,511 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 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.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#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))
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
return (self->online || g_hash_table_size(priv->req_table) > 0) &&
!priv->power_cycle;
}
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 = RIL_RADIO(user_data);
struct ril_radio_priv *priv = self->priv;
DBG_(self, "");
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_(self, "retry cancelled");
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) {
gboolean should_be_on = ril_radio_power_should_be_on(self);
if (ril_radio_state_on(priv->last_known_state) ==
should_be_on) {
/* All is good, cancel pending retry if there is one */
ril_radio_cancel_retry(self);
} else if (priv->state_changed_while_request_pending) {
/* 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_(self, "retry scheduled");
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_(self, "%s -> %s", ril_radio_state_to_string(self->state),
ril_radio_state_to_string(priv->last_known_state));
self->state = priv->last_known_state;
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
}
}
static void ril_radio_power_request_done(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
GASSERT(priv->pending_id);
priv->pending_id = 0;
if (priv->next_state_valid) {
ril_radio_submit_power_request(self, priv->next_state);
} else {
ril_radio_check_state(self);
}
}
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_radio *self = RIL_RADIO(user_data);
if (ril_status != RIL_E_SUCCESS) {
ofono_error("Power request failed: %s",
ril_error_to_string(ril_status));
}
ril_radio_power_request_done(self);
}
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
{
/*
* RIL_REQUEST_RADIO_POWER
*
* "data" is int *
* ((int *)data)[0] is > 0 for "Radio On"
* ((int *)data)[0] is == 0 for "Radio Off"
*
* "response" is NULL
**/
GRilIoRequest *req = grilio_request_array_int32_new(1, on);
struct ril_radio_priv *priv = self->priv;
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);
grilio_request_set_blocking(req, TRUE);
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb,
NULL, self);
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_(self, "%s (queued)", on_off);
} else {
DBG_(self, "%s (ignored)", on_off);
}
} else {
if (ril_radio_state_on(priv->last_known_state) == on) {
DBG_(self, "%s (already)", on_off);
ril_radio_check_state(self);
} else {
DBG_(self, "%s", on_off);
ril_radio_submit_power_request(self, on);
}
}
}
void ril_radio_confirm_power_on(struct ril_radio *self)
{
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
struct ril_radio_priv *priv = self->priv;
if (priv->pending_id) {
if (!priv->next_state) {
/* Wait for the pending request to complete */
priv->next_state_valid = TRUE;
priv->next_state = TRUE;
DBG_(self, "on (queued)");
}
} else {
DBG_(self, "on");
ril_radio_submit_power_request(self, 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_(self, "power is already off");
GASSERT(!priv->power_cycle);
} else if (priv->power_cycle) {
DBG_(self, "already in progress");
} else {
DBG_(self, "initiated");
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_(self, "%p", tag);
g_hash_table_insert(priv->req_table, tag, tag);
if (!was_on && ril_radio_power_should_be_on(self)) {
ril_radio_power_request(self, TRUE, FALSE);
}
}
}
}
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_(self, "%p", tag);
if (!ril_radio_power_should_be_on(self)) {
/* The last one turns the lights off */
ril_radio_power_request(self, FALSE, FALSE);
}
}
}
}
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 = RIL_RADIO(user_data);
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
if (radio_state != RADIO_STATE_UNAVAILABLE) {
struct ril_radio_priv *priv = self->priv;
DBG_(self, "%s", ril_radio_state_to_string(radio_state));
GASSERT(!priv->pending_id || !priv->retry_id);
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
DBG_(self, "switched off for power cycle");
priv->power_cycle = FALSE;
}
priv->last_known_state = radio_state;
if (priv->pending_id) {
if (ril_radio_state_on(radio_state) ==
ril_radio_power_should_be_on(self)) {
DBG_(self, "dropping pending request");
/*
* All right, the modem has switched to the
* desired state, drop the request.
*/
grilio_queue_cancel_request(priv->q,
priv->pending_id, FALSE);
/*
* This will zero pending_id and call
* ril_radio_check_state() if necesary:
*/
ril_radio_power_request_done(self);
/* We are done */
return;
} else {
/* Something weird is going on */
priv->state_changed_while_request_pending++;
}
}
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_(self, "");
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_radio_state_changed,
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
/*
* Some RILs like to receive power off request at startup even if
* radio is already off. Make those happy.
*/
ril_radio_submit_power_request(self, FALSE);
return self;
}
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_(self, "");
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

@@ -1,60 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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"
#include <glib-object.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);
#define ril_radio_remove_all_handlers(r,ids) \
ril_radio_remove_handlers(r, ids, G_N_ELEMENTS(ids))
#endif /* RIL_RADIO_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,96 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2017-2020 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_RADIO_CAPS_H
#define RIL_RADIO_CAPS_H
#include "ril_types.h"
struct ril_data_manager;
struct ril_sim_settings;
struct ril_radio_caps;
struct ril_radio_caps_manager;
struct ril_radio_capability;
struct ril_radio_caps_request;
typedef void (*ril_radio_caps_cb_t)(struct ril_radio_caps *caps, void *arg);
typedef void (*ril_radio_caps_manager_cb_t)(struct ril_radio_caps_manager *mgr,
void *user_data);
/* ril_radio_capability pointer is NULL if functionality is unsupported */
typedef void (*ril_radio_caps_check_cb_t)
(const struct ril_radio_capability *cap, void *user_data);
/* The check can be cancelled with grilio_channel_cancel_request */
guint ril_radio_caps_check(GRilIoChannel *io, ril_radio_caps_check_cb_t cb,
void *user_data);
/* There should be a single ril_radio_caps_manager shared by all all modems */
struct ril_radio_caps_manager *ril_radio_caps_manager_new
(struct ril_data_manager *dm);
struct ril_radio_caps_manager *ril_radio_caps_manager_ref
(struct ril_radio_caps_manager *mgr);
void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr);
gulong ril_radio_caps_manager_add_tx_aborted_handler
(struct ril_radio_caps_manager *mgr,
ril_radio_caps_manager_cb_t cb, void *arg);
gulong ril_radio_caps_manager_add_tx_done_handler
(struct ril_radio_caps_manager *mgr,
ril_radio_caps_manager_cb_t cb, void *arg);
void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *mgr,
gulong id);
void ril_radio_caps_manager_remove_handlers(struct ril_radio_caps_manager *mgr,
gulong *ids, int count);
#define ril_radio_caps_manager_remove_all_handlers(mgr, ids) \
ril_radio_caps_manager_remove_handlers(mgr, ids, G_N_ELEMENTS(ids))
/* And one ril_radio_caps object per modem */
struct ril_radio_caps {
struct ril_radio_caps_manager *mgr;
enum ofono_radio_access_mode supported_modes;
};
struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
const char *log_prefix, GRilIoChannel *io,
struct ofono_watch *watch,
struct ril_data *data, struct ril_radio *radio,
struct ril_sim_card *sim, struct ril_sim_settings *settings,
const struct ril_slot_config *config,
const struct ril_radio_capability *cap);
struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps);
void ril_radio_caps_unref(struct ril_radio_caps *caps);
void ril_radio_caps_drop(struct ril_radio_caps *caps);
gulong ril_radio_caps_add_supported_modes_handler
(struct ril_radio_caps *caps,
ril_radio_caps_cb_t cb, void *arg);
void ril_radio_caps_remove_handler(struct ril_radio_caps *caps, gulong id);
/* Data requests */
struct ril_radio_caps_request *ril_radio_caps_request_new
(struct ril_radio_caps *caps, enum ofono_radio_access_mode mode,
enum ril_data_role role);
void ril_radio_caps_request_free(struct ril_radio_caps_request *req);
#endif /* RIL_RADIO_CAPS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,194 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_sim_settings.h"
#include "ril_util.h"
#include "ril_log.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;
GASSERT(rsd->source_id);
rsd->source_id = 0;
cbd->cb.available_rats(ril_error_ok(&error), rsd->settings->techs,
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:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,805 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 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.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#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>
/*
* First we wait for USIM app to get activated by itself. If that
* doesn't happen within UICC_SUBSCRIPTION_START_MS we poke the SIM
* with SET_UICC_SUBSCRIPTION request, resubmitting it if it times out.
* If nothing happens within UICC_SUBSCRIPTION_TIMEOUT_MS we give up.
*
* Submitting SET_UICC_SUBSCRIPTION request when rild doesn't expect
* it sometimes breaks pretty much everything. Unfortunately, there no
* reliable way to find out when rild expects it and when it doesn't :/
*/
#define UICC_SUBSCRIPTION_START_MS (5000)
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
/* SIM I/O idle timeout is measured in the number of idle loops.
* When active SIM I/O is going on, the idle loop count very rarely
* exceeds 1 between the requests, so 10 is more than enough. Idle
* loop is actually more accurate criteria than a timeout because
* it doesn't depend that much on the system load. */
#define SIM_IO_IDLE_LOOPS (10)
typedef GObjectClass RilSimCardClass;
typedef struct ril_sim_card RilSimCard;
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;
guint sub_req_id;
guint sub_start_timer;
gulong event_id[EVENT_COUNT];
guint sim_io_idle_id;
guint sim_io_idle_count;
GHashTable* sim_io_pending;
};
enum ril_sim_card_signal {
SIGNAL_STATUS_RECEIVED,
SIGNAL_STATUS_CHANGED,
SIGNAL_STATE_CHANGED,
SIGNAL_APP_CHANGED,
SIGNAL_SIM_IO_ACTIVE_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
#define SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME "ril-simcard-sim-io-active-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 NEW_SIGNAL(klass,name) NEW_SIGNAL_(klass,name##_CHANGED)
#define NEW_SIGNAL_(klass,name) \
ril_sim_card_signals[SIGNAL_##name] = \
g_signal_new(SIGNAL_##name##_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
#define RIL_SIMCARD_STATE_CHANGED (0x01)
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
static 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_tx_start(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
GRILIO_TRANSACTION_STATE tx_state =
grilio_queue_transaction_state(priv->q);
if (tx_state == GRILIO_TRANSACTION_NONE) {
tx_state = grilio_queue_transaction_start(priv->q);
DBG("status tx for slot %u %s", self->slot,
(tx_state == GRILIO_TRANSACTION_STARTED) ?
"started" : "starting");
}
}
static void ril_sim_card_tx_check(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
if (grilio_queue_transaction_state(priv->q) !=
GRILIO_TRANSACTION_NONE) {
const struct ril_sim_card_status *status = self->status;
if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
/* Transaction (if there is any) is finished when
* both GET_SIM_STATUS and SET_UICC_SUBSCRIPTION
* complete or get dropped */
if (!priv->status_req_id && !priv->sub_req_id &&
status->gsm_umts_index >= 0 &&
status->gsm_umts_index < status->num_apps) {
DBG("status tx for slot %u finished",
self->slot);
grilio_queue_transaction_finish(priv->q);
}
} else {
DBG("status tx for slot %u cancelled", self->slot);
grilio_queue_transaction_finish(priv->q);
}
}
}
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;
if (priv->sub_start_timer) {
/* Don't need this timer anymore */
g_source_remove(priv->sub_start_timer);
priv->sub_start_timer = 0;
}
if (priv->sub_req_id) {
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
* so we better drop rather than cancel it (so that it gets
* removed from the list of pending requests) */
grilio_channel_drop_request(priv->io, priv->sub_req_id);
priv->sub_req_id = 0;
}
ril_sim_card_tx_check(self);
}
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
const void* data, guint len, void* user_data)
{
struct ril_sim_card *self = RIL_SIMCARD(user_data);
struct ril_sim_card_priv *priv = self->priv;
GASSERT(status == GRILIO_STATUS_OK);
GASSERT(priv->sub_req_id);
priv->sub_req_id = 0;
DBG("UICC subscription OK for slot %u", self->slot);
ril_sim_card_subscription_done(self);
}
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index)
{
struct ril_sim_card_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(16);
const guint sub_id = self->slot;
guint code;
DBG("%u,%d,%u", self->slot, app_index, sub_id);
grilio_request_append_int32(req, self->slot);
grilio_request_append_int32(req, app_index);
grilio_request_append_int32(req, sub_id);
grilio_request_append_int32(req, RIL_UICC_SUBSCRIPTION_ACTIVATE);
grilio_request_set_retry(req, 0, -1);
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
code = (priv->io->ril_version <= 9 &&
(priv->flags & RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND)) ?
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
RIL_REQUEST_SET_UICC_SUBSCRIPTION;
if (priv->sub_req_id) {
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
* so we better drop rather than cancel it (so that it gets
* removed from the list of pending requests) */
grilio_channel_drop_request(priv->io, priv->sub_req_id);
}
/* Don't allow any requests other that GET_SIM_STATUS until
* we are done with the subscription */
ril_sim_card_tx_start(self);
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
req, code, ril_sim_card_subscribe_cb, NULL, self);
grilio_request_unref(req);
}
static int ril_sim_card_select_app(const struct ril_sim_card_status *status)
{
int i, selected_app = -1;
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;
ril_sim_card_subscription_done(self);
} else {
app_index = ril_sim_card_select_app(status);
if (app_index >= 0 && !self->priv->sub_start_timer) {
ril_sim_card_subscribe(self, app_index);
}
}
} else {
app_index = -1;
ril_sim_card_subscription_done(self);
}
if (app_index >= 0 &&
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 gboolean ril_sim_card_sub_start_timeout(gpointer user_data)
{
struct ril_sim_card *self = RIL_SIMCARD(user_data);
struct ril_sim_card_priv *priv = self->priv;
DBG("%u", self->slot);
GASSERT(priv->sub_start_timer);
priv->sub_start_timer = 0;
ril_sim_card_update_app(self);
return G_SOURCE_REMOVE;
}
static void ril_sim_card_update_status(struct ril_sim_card *self,
struct ril_sim_card_status *status)
{
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;
if (diff & RIL_SIMCARD_STATE_CHANGED &&
status->card_state == RIL_CARDSTATE_PRESENT) {
struct ril_sim_card_priv *priv = self->priv;
/*
* SIM card has just appeared, give it some time to
* activate the USIM app
*/
if (priv->sub_start_timer) {
g_source_remove(priv->sub_start_timer);
}
DBG("started subscription timeout for slot %u",
self->slot);
priv->sub_start_timer =
g_timeout_add(UICC_SUBSCRIPTION_START_MS,
ril_sim_card_sub_start_timeout, self);
}
ril_sim_card_update_app(self);
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_STATUS_RECEIVED], 0);
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_update_app(self);
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) {
GASSERT(grilio_parser_at_end(&rilp));
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 = RIL_SIMCARD(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);
}
}
ril_sim_card_tx_check(self);
}
void ril_sim_card_reset(struct ril_sim_card *self)
{
if (G_LIKELY(self)) {
struct ril_sim_card_status *status =
g_new0(struct ril_sim_card_status, 1);
/* Simulate removal and re-submit the SIM status query */
status->card_state = RIL_CARDSTATE_ABSENT;
status->gsm_umts_index = -1;
status->cdma_index = -1;
status->ims_index = -1;
ril_sim_card_update_status(self, status);
ril_sim_card_request_status(self);
}
}
void ril_sim_card_request_status(struct ril_sim_card *self)
{
if (G_LIKELY(self)) {
struct ril_sim_card_priv *priv = self->priv;
if (priv->status_req_id) {
/* Retry right away, don't wait for retry
* timeout to expire */
grilio_channel_retry_request(priv->io,
priv->status_req_id);
} else {
GRilIoRequest* req = grilio_request_new();
/* Start the transaction to not allow any other
* requests to interfere with SIM status query */
ril_sim_card_tx_start(self);
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
priv->status_req_id =
grilio_queue_send_request_full(priv->q,
req, RIL_REQUEST_GET_SIM_STATUS,
ril_sim_card_status_cb, NULL, self);
grilio_request_unref(req);
}
}
}
static void ril_sim_card_update_sim_io_active(struct ril_sim_card *self)
{
/* SIM I/O is considered active for certain period of time after
* the last request has completed. That's because SIM_IO requests
* are usually submitted in large quantities and quick succession.
* Some RILs don't like being bothered while they are doing SIM I/O
* and some time after that too. That sucks but what else can we
* do about it? */
struct ril_sim_card_priv *priv = self->priv;
const gboolean active = priv->sim_io_idle_id ||
g_hash_table_size(priv->sim_io_pending);
if (self->sim_io_active != active) {
self->sim_io_active = active;
DBG("SIM I/O for slot %u is %sactive", self->slot,
active ? "" : "in");
g_signal_emit(self, ril_sim_card_signals
[SIGNAL_SIM_IO_ACTIVE_CHANGED], 0);
}
}
void ril_sim_card_sim_io_started(struct ril_sim_card *self, guint id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
struct ril_sim_card_priv *priv = self->priv;
gpointer key = GINT_TO_POINTER(id);
g_hash_table_insert(priv->sim_io_pending, key, key);
if (priv->sim_io_idle_id) {
g_source_remove(priv->sim_io_idle_id);
priv->sim_io_idle_id = 0;
priv->sim_io_idle_count = 0;
}
ril_sim_card_update_sim_io_active(self);
}
}
static gboolean ril_sim_card_sim_io_idle_cb(gpointer user_data)
{
struct ril_sim_card *self = RIL_SIMCARD(user_data);
struct ril_sim_card_priv *priv = self->priv;
if (++(priv->sim_io_idle_count) >= SIM_IO_IDLE_LOOPS) {
priv->sim_io_idle_id = 0;
priv->sim_io_idle_count = 0;
ril_sim_card_update_sim_io_active(self);
return G_SOURCE_REMOVE;
} else {
return G_SOURCE_CONTINUE;
}
}
void ril_sim_card_sim_io_finished(struct ril_sim_card *self, guint id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
struct ril_sim_card_priv *priv = self->priv;
gpointer key = GINT_TO_POINTER(id);
if (g_hash_table_remove(priv->sim_io_pending, key) &&
!g_hash_table_size(priv->sim_io_pending)) {
/* Reset the idle loop count */
if (priv->sim_io_idle_id) {
g_source_remove(priv->sim_io_idle_id);
priv->sim_io_idle_count = 0;
}
priv->sim_io_idle_id =
g_idle_add(ril_sim_card_sim_io_idle_cb, self);
}
ril_sim_card_update_sim_io_active(self);
}
}
static void ril_sim_card_status_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_sim_card *self = RIL_SIMCARD(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;
}
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *self,
ril_sim_card_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
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)
{
struct ril_sim_card_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_SIMCARD_TYPE, struct ril_sim_card_priv);
self->priv = priv;
priv->sim_io_pending = g_hash_table_new(g_direct_hash, g_direct_equal);
}
static void ril_sim_card_dispose(GObject *object)
{
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;
if (priv->sim_io_idle_id) {
g_source_remove(priv->sim_io_idle_id);
}
if (priv->sub_start_timer) {
g_source_remove(priv->sub_start_timer);
}
g_hash_table_destroy(priv->sim_io_pending);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
ril_sim_card_status_free(self->status);
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));
NEW_SIGNAL_(klass,STATUS_RECEIVED);
NEW_SIGNAL(klass,STATUS);
NEW_SIGNAL(klass,STATE);
NEW_SIGNAL(klass,APP);
NEW_SIGNAL(klass,SIM_IO_ACTIVE);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,96 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2018 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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"
#include <glib-object.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;
gboolean sim_io_active;
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);
void ril_sim_card_reset(struct ril_sim_card *sc);
void ril_sim_card_request_status(struct ril_sim_card *sc);
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
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);
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
/* Inline wrappers */
static inline enum ril_app_type ril_sim_card_app_type(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
static inline const char *ril_sim_card_app_aid(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->aid : NULL; }
#define ril_sim_card_remove_all_handlers(net, ids) \
ril_sim_card_remove_handlers(net, ids, G_N_ELEMENTS(ids))
#endif /* RIL_SIM_CARD_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,198 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 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.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_sim_settings.h"
#include "ril_log.h"
#include <ofono/watch.h>
#include <gutil_misc.h>
#define RIL_PREF_MODE_DEFAULT(self) (\
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
OFONO_RADIO_ACCESS_MODE_LTE : \
((self)->techs & OFONO_RADIO_ACCESS_MODE_UMTS) ? \
OFONO_RADIO_ACCESS_MODE_UMTS : \
OFONO_RADIO_ACCESS_MODE_GSM)
typedef GObjectClass RilSimSettingsClass;
typedef struct ril_sim_settings RilSimSettings;
enum ofono_watch_events {
WATCH_EVENT_IMSI,
WATCH_EVENT_COUNT
};
struct ril_sim_settings_priv {
gulong watch_event_id[WATCH_EVENT_COUNT];
struct ofono_watch *watch;
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)
/* Skip the leading slash from the modem path: */
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
static void ril_sim_settings_signal_emit(struct ril_sim_settings *self,
enum ril_sim_settings_signal id)
{
g_signal_emit(self, ril_sim_settings_signals[id], 0);
}
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) {
self->pref_mode = mode;
ril_sim_settings_signal_emit(self, SIGNAL_PREF_MODE_CHANGED);
}
}
static void ril_sim_settings_imsi_changed(struct ofono_watch *watch,
void *user_data)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
struct ril_sim_settings_priv *priv = self->priv;
if (g_strcmp0(priv->imsi, watch->imsi)) {
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(watch->imsi);
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
}
}
struct ril_sim_settings *ril_sim_settings_new(const char *path,
enum ofono_radio_access_mode techs)
{
struct ril_sim_settings *self = NULL;
if (G_LIKELY(path)) {
struct ril_sim_settings_priv *priv;
self = g_object_new(RIL_SIM_SETTINGS_TYPE, NULL);
priv = self->priv;
self->techs = techs;
self->pref_mode = RIL_PREF_MODE_DEFAULT(self);
priv->watch = ofono_watch_new(path);
priv->watch_event_id[WATCH_EVENT_IMSI] =
ofono_watch_add_imsi_changed_handler(priv->watch,
ril_sim_settings_imsi_changed, self);
self->imsi = priv->imsi = g_strdup(priv->watch->imsi);
}
return self;
}
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_SIM_SETTINGS(self));
return self;
} else {
return NULL;
}
}
void ril_sim_settings_unref(struct ril_sim_settings *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_SIM_SETTINGS(self));
}
}
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *self,
ril_sim_settings_cb_t cb, void *arg)
{
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);
}
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_finalize(GObject *object)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
struct ril_sim_settings_priv *priv = self->priv;
ofono_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
ofono_watch_unref(priv->watch);
g_free(priv->imsi);
G_OBJECT_CLASS(ril_sim_settings_parent_class)->finalize(object);
}
static void ril_sim_settings_class_init(RilSimSettingsClass *klass)
{
G_OBJECT_CLASS(klass)->finalize = ril_sim_settings_finalize;
g_type_class_add_private(klass, sizeof(struct ril_sim_settings_priv));
NEW_SIGNAL(klass, IMSI);
NEW_SIGNAL(klass, PREF_MODE);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,59 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 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 <glib-object.h>
struct ril_sim_settings_priv;
struct ril_sim_settings {
GObject object;
struct ril_sim_settings_priv *priv;
const char *imsi;
enum ofono_radio_access_mode techs;
enum ofono_radio_access_mode pref_mode;
};
typedef void (*ril_sim_settings_cb_t)(struct ril_sim_settings *s, void *arg);
struct ril_sim_settings *ril_sim_settings_new(const char *path,
enum ofono_radio_access_mode techs);
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *s);
void ril_sim_settings_unref(struct ril_sim_settings *s);
void ril_sim_settings_set_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);
#define ril_sim_settings_remove_all_handlers(s,ids) \
ril_sim_settings_remove_handlers(s, ids, G_N_ELEMENTS(ids))
#endif /* RIL_SIM_SETTINGS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,516 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "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,
mms ? RIL_REQUEST_SEND_SMS_EXPECT_MORE : RIL_REQUEST_SEND_SMS,
ril_sms_submit_cb, ril_sms_cbd_free,
ril_sms_cbd_new(sd, cb, data));
grilio_request_unref(req);
g_free(tpdu);
}
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)
{
unsigned 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:
*/

View File

@@ -1,302 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.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);
unsigned 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

@@ -1,373 +0,0 @@
# 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]
# This option stops RIL plugin from creating any RIL modems.
# If it's set to true, all [ril_x] sections are ignored even
# if they are present, and no default configurtation is created.
#
# Default false
#
#EmptyConfig=false
# User and group for the ofono process. RIL clients are typically
# expected to run under radio:radio.
#
# Default radio:radio
#
#Identity=radio:radio
# If the phone has more than one SIM slot, the 3G/LTE module may be
# shared by all modems, meaning that only one of the slots can use
# 3G/LTE. In order to "hand 4G over" to the other slot, the modem
# 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.
#
# Defaults to true (switch the current data modem to 2G when changing
# the data modems)
#
#3GLTEHandover=true
# If this option is on, preferred technology is set to GSM for non-data
# slots.
#
# Default true (for historical reasons)
#
#ForceGsmForNonDataSlots=true
# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
# This option allows you to forcibly enable or disable use of this request.
# It's involved in 3G/LTE handover between the modems, meaning that it only
# makes sense if you have more than one slot.
#
# Possible values are auto, on and off
#
# Default auto (enable for RIL version >= 11)
#
#SetRadioCapability=auto
[ril_0]
# Required entry, defines the RIL socket path
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.
#
# Default zero (no timeout)
#
#timeout=0
# Comma-separated list of radio technologies supported by the modem.
# Valid technologies are "gsm", "umts" and "lte". The special value
# "all" means that all technologies are supported.
#
# Default all
#
#technologies=all
# This one is deprecated, use the technologies entry instead (above).
#
#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 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 auto (enable for RIL version >= 11)
#
#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 true
#
#emptyPinQuery=true
# Different RILs use different data call structures which don't necessarily
# match the format specified in the data list header. The header may have
# version 9 but the list may contain RIL_Data_Call_Response_v6 structures,
# list version 10 may contain RIL_Data_Call_Response_v11 and so on. By default
# ofono assumes that the version from the list header matches the contents
# but sometimes you have to explicitly tell ofono which one to use.
# Possible values are 6, 9, 11 and auto.
#
# Default auto
#
#dataCallFormat=auto
# Data call may fail with status 65535 which according to ril.h means that
# we need to retry silently. The maximum number of retries is limited by
# this parameter. Usually, one retry is enough. The first retry occurs
# immediately, the subsequent ones after dataCallRetryDelay (see below)
#
# Default 4
#
#dataCallRetryLimit=4
# Delay between data call retries, in milliseconds. Note that the first
# retry occurs immediately after the first failure, the delays are only
# applied if the first retry fails too.
#
# Default 200 ms
#
#dataCallRetryDelay=200
# Additional local and remote hangup reasons. Remote reasons are checked
# first. Normally, RIL plugin figures it out automatically. You would only
# need to define these if your RIL does something unusual.
#
# No default
#
#remoteHangupReasons=20
#localHangupReasons=23
# Voice call support. Some devices like USB modems and tablets don't support
# voice calls. By default, voice calls are enabled and this option allows you
# to disable voice call handling.
#
# Default true
#
#enableVoicecall=true
# Support for Cell Broadcast System (CBS). By default, its enabled but if
# your rild and/or modem is not happy about it, you can turn it off.
#
# Default true
#
#enableCellBroadcast=true
# Support for Sim Toolkit (STK). By default, its enabled but if your rild
# and/or modem is not happy about it, you can turn it off.
#
# Default true
#
#enableSimToolkit=true
# Timeout for the modem to show up, in milliseconds. Those that don't
# show up before this timeout expires, will be dropped (ignored).
#
# In some fairly rare cases it makes sense to shorten this timeout for
# optional modems (which may or may not be available), to speed up the
# boot up process.
#
# Default 20000 (20 seconds)
#
#startTimeout=20000
# This allows to use deprecated RIL_REQUEST_GET_IMEI instead of
# RIL_REQUEST_DEVICE_IDENTITY to query IMEI from the modem. Some
# RILs (e.g. MTK) still don't understand RIL_REQUEST_DEVICE_IDENTITY.
#
# Default false (use RIL_REQUEST_DEVICE_IDENTITY)
#
#legacyImeiQuery=false
# Some devices don't support LTE RAT mode PREF_NET_TYPE_LTE_GSM_WCDMA.
# This option allows to set a custom LTE mode.
#
# Default 9 (PREF_NET_TYPE_LTE_GSM_WCDMA)
#
#lteNetworkMode=9
# UMTS network mode.
#
# Default 3 (PREF_NET_TYPE_GSM_WCDMA_AUTO)
#
#umtsNetworkMode=3
# Timeout for RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, in milliseconds.
#
# Default 20000 (20 seconds)
#
#networkModeTimeout=20000
# Timeout for RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC and
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, in milliseconds.
#
# Default 100000 (100 seconds)
#
#networkSelectionTimeout=100000
# Comma-separated signal strength range, in dBm.
#
# These values are used for translating dBm values returned by the modem in
# LTE mode into signal strength percentage. If you are getting significantly
# different signal strength readings in GSM and LTE modes, you may need to
# tweak those.
#
# Default -100,-60
#
#signalStrengthRange=-100,-60
# Cycle radio power at startup.
#
# Default true (cycle the power)
#
#radioPowerCycle=true
# With some RILs it seems to be necessary to kick (RIL_REQUEST_RADIO_POWER)
# the modems with power on after one of the modems has been powered off.
# Otherwise bad things may happen (like the modem never registering
# on the network).
#
# On the other hand, with some RILs it's causing some trouble (like this
# extra RIL_REQUEST_RADIO_POWER getting stuck indefinitely).
#
# Default true (for historical reasons)
#
#confirmRadioPowerOn=true
# Normally we should be able to have two simultaneously active data
# contexts - one for mobile data and one for MMS. Some devices however
# require that mobile data is disconnected before we can send or receive
# MMS. In other words, activation of the second data context fails.
#
# Default false (more than one context is supported)
#
#singleDataContext=false
# With some RILs, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS returns strange
# operator names, i.e. numeric MCC+MNC values or the same name for all
# operators (which is actually SPN fetched from the SIM). Such strange
# names can be replaced with operator names from MBPI database, based
# on the operator's MCC and MNC. That may not be 100% accurate, though.
#
# Default false (i.e. trust RIL to report the actual names)
#
#replaceStrangeOperatorNames=false
# Configures whether +0 is added to MCCMNC string passed to
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL. Some Qualcomm RILs
# require it, some MediaTek RILs don't like it.
#
# Default true
#
#networkSelectionManual0=true
# Enables use of SET_DATA_PROFILE requests. Everything used to work without
# profiles, that's why it's disabled by default.
#
# Default false
#
#useDataProfiles=false
# Configures MMS data profile ID. Must be non-zero.
# This option is ignored if useDataProfiles is false.
#
# Default 2 (RIL_DATA_PROFILE_IMS)
#
#mmsDataProfileId=2
# Configures device state tracking (basically, power saving strategy).
# Possible values are:
#
# ss = Use legacy device state management (RIL_REQUEST_SCREEN_STATE)
# ds = Use newer device state management (RIL_REQUEST_SEND_DEVICE_STATE)
# ur = Use URC filter (RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER)
# This may be useful on devices with RIL version >= 15 if auto
# method fails
# auto = Choose ss or ds based on the RIL version
# none = Disable device state management
#
# In addition to specifying ss, ds or ur method, one can specify a
# combination of methods, e.g. ds+ur
#
# Default auto
#
#deviceStateTracking=auto
# On some phones (such as Jolla C), even if the slot which has been
# using LTE gets powered off, we still need to explicitely set its
# preferred mode to GSM, to make LTE machinery available to the other slot.
#
# Default true (false for MTK RILs)
#
#forceGsmWhenRadioOff=true
# Configures a period between RIL_UNSOL_CELL_INFO_LIST events when the device
# is awake. Possible values are:
#
# 0 = invoke RIL_UNSOL_CELL_INFO_LIST when any of the reported information
# changes
# 1..INT_MAX-1 (2147483646) = sets update period in milliseconds
# negative value or INT_MAX = never issue a RIL_UNSOL_CELL_INFO_LIST
#
# On MediaTek devices the period of RIL_UNSOL_CELL_INFO_LIST events can't be
# configured. The parameter RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE has
# non-standard meaning:
#
# 0 = enable RIL_UNSOL_CELL_INFO_LIST
# any other value = disable RIL_UNSOL_CELL_INFO_LIST
#
# Default 2000
#
#cellInfoIntervalShortMs=2000
# Configures period between RIL_UNSOL_CELL_INFO_LIST events when the device is
# in a power saving mode. For possible values, look cellInfoIntervalShortMs.
#
# Default 30000
#
#cellInfoIntervalLongMs=30000

View File

@@ -1,94 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
*
* 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>
struct ofono_watch;
struct ofono_modem;
struct ofono_sim;
#include <ofono/types.h>
#include <ofono/radio-settings.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ril_constants.h"
#define RIL_RETRY_SECS (2)
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
struct ril_data;
struct ril_data_call;
struct ril_modem;
struct ril_radio;
struct ril_network;
struct ril_sim_card;
struct ril_vendor;
enum ril_data_role {
RIL_DATA_ROLE_NONE, /* Mobile data not required */
RIL_DATA_ROLE_MMS, /* Data is needed at any speed */
RIL_DATA_ROLE_INTERNET /* Data is needed at full speed */
};
struct ril_slot_config {
guint slot;
enum ofono_radio_access_mode techs;
enum ril_pref_net_type lte_network_mode;
enum ril_pref_net_type umts_network_mode;
int network_mode_timeout;
int network_selection_timeout;
int signal_strength_dbm_weak;
int signal_strength_dbm_strong;
gboolean query_available_band_mode;
gboolean empty_pin_query;
gboolean radio_power_cycle;
gboolean confirm_radio_power_on;
gboolean enable_voicecall;
gboolean enable_cbs;
gboolean enable_stk;
gboolean replace_strange_oper;
gboolean network_selection_manual_0;
gboolean force_gsm_when_radio_off;
gboolean use_data_profiles;
guint mms_data_profile_id;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
int cell_info_interval_short_ms;
int cell_info_interval_long_ms;
};
#endif /* RIL_TYPES_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,269 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* 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 "smsutil.h"
#include "util.h"
#define USSD_REQUEST_TIMEOUT_SEC (30)
#define USSD_CANCEL_TIMEOUT_SEC (20)
struct ril_ussd {
struct ofono_ussd *ussd;
GRilIoChannel *io;
GRilIoQueue *q;
guint request_id;
guint cancel_id;
guint timer_id;
gulong event_id;
};
struct ril_ussd_cbd {
struct ril_ussd *ud;
ofono_ussd_cb_t cb;
gpointer data;
};
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(struct ril_ussd *ud,
ofono_ussd_cb_t cb, void *data)
{
struct ril_ussd_cbd *cbd = g_slice_new(struct ril_ussd_cbd);
cbd->ud = ud;
cbd->cb = cb;
cbd->data = data;
return cbd;
}
static void ril_ussd_cbd_free(void *cbd)
{
g_slice_free(struct ril_ussd_cbd, cbd);
}
static void ril_ussd_cancel_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_ussd_cbd *cbd = user_data;
struct ril_ussd *ud = cbd->ud;
/* Always report sucessful completion, otherwise ofono may get
* stuck in the USSD_STATE_ACTIVE state */
GASSERT(ud->cancel_id);
ud->cancel_id = 0;
cbd->cb(ril_error_ok(&error), cbd->data);
}
static void ril_ussd_response(GRilIoChannel* channel, int status,
const void* data, guint len, void* user_data)
{
struct ofono_error error;
struct ril_ussd_cbd *cbd = user_data;
struct ril_ussd *ud = cbd->ud;
GASSERT(ud->request_id);
ud->request_id = 0;
if (status == RIL_E_SUCCESS) {
ril_error_init_ok(&error);
} else {
ril_error_init_failure(&error);
}
cbd->cb(&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);
GASSERT(!ud->request_id);
if (ud->request_id) {
grilio_queue_cancel_request(ud->q, ud->request_id, FALSE);
ud->request_id = 0;
}
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_request_set_timeout(req,
USSD_REQUEST_TIMEOUT_SEC * 1000);
ud->request_id =
grilio_queue_send_request_full(ud->q,
req, RIL_REQUEST_SEND_USSD,
ril_ussd_response,
ril_ussd_cbd_free,
ril_ussd_cbd_new(ud, cb, data));
grilio_request_unref(req);
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);
GRilIoRequest *req = grilio_request_new();
ofono_info("send ussd cancel");
GASSERT(!ud->cancel_id);
grilio_queue_cancel_request(ud->q, ud->cancel_id, FALSE);
grilio_request_set_timeout(req, USSD_CANCEL_TIMEOUT_SEC * 1000);
ud->cancel_id = grilio_queue_send_request_full(ud->q, req,
RIL_REQUEST_CANCEL_USSD, ril_ussd_cancel_cb,
ril_ussd_cbd_free, ril_ussd_cbd_new(ud, cb, data));
grilio_request_unref(req);
}
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 *type;
guint32 n = 0;
ofono_info("ussd received");
GASSERT(code == RIL_UNSOL_ON_USSD);
grilio_parser_init(&rilp, data, len);
grilio_parser_get_uint32(&rilp, &n);
type = grilio_parser_get_utf8(&rilp);
if (type) {
int ussdtype = g_ascii_xdigit_value(*type);
char *msg = (n > 1) ? grilio_parser_get_utf8(&rilp) : NULL;
if (msg) {
const int msglen = strlen(msg);
DBG("ussd length %d", msglen);
ofono_ussd_notify(ud->ussd, ussdtype, 0xFF,
(const unsigned char *)msg, msglen);
/* msg is freed by core if dcs is 0xFF */
} else {
ofono_ussd_notify(ud->ussd, ussdtype, 0, NULL, 0);
}
g_free(type);
}
}
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 G_SOURCE_REMOVE;
}
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

@@ -1,481 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 <gutil_misc.h>
#include <sys/socket.h>
#include <ctype.h>
#include "common.h"
#include "netreg.h"
#define RIL_PROTO_IP_STR "IP"
#define RIL_PROTO_IPV6_STR "IPV6"
#define RIL_PROTO_IPV4V6_STR "IPV4V6"
const char *ril_error_to_string(int error)
{
#define RIL_E_(name) case RIL_E_##name: return #name
#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_(MISSING_RESOURCE);
RIL_E_(NO_SUCH_ELEMENT);
RIL_E_(DIAL_MODIFIED_TO_USSD);
RIL_E_(DIAL_MODIFIED_TO_SS);
RIL_E_(DIAL_MODIFIED_TO_DIAL);
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_(SUBSCRIPTION_NOT_SUPPORTED);
RIL_E_(SS_MODIFIED_TO_SS);
RIL_E_(LCE_NOT_SUPPORTED);
RIL_E_(NO_MEMORY);
RIL_E_(INTERNAL_ERR);
RIL_E_(SYSTEM_ERR);
RIL_E_(MODEM_ERR);
RIL_E_(INVALID_STATE);
RIL_E_(NO_RESOURCES);
RIL_E_(SIM_ERR);
RIL_E_(INVALID_ARGUMENTS);
RIL_E_(INVALID_SIM_STATE);
RIL_E_(INVALID_MODEM_STATE);
RIL_E_(INVALID_CALL_ID);
RIL_E_(NO_SMS_TO_ACK);
RIL_E_(NETWORK_ERR);
RIL_E_(REQUEST_RATE_LIMITED);
RIL_E_(SIM_BUSY);
RIL_E_(SIM_FULL);
RIL_E_(NETWORK_REJECT);
RIL_E_(OPERATION_NOT_ALLOWED);
RIL_E_(EMPTY_RECORD);
RIL_E_(INVALID_SMS_FORMAT);
RIL_E_(ENCODING_ERR);
RIL_E_(INVALID_SMSC_ADDRESS);
RIL_E_(NO_SUCH_ENTRY);
RIL_E_(NETWORK_NOT_READY);
RIL_E_(NOT_PROVISIONED);
RIL_E_(NO_SUBSCRIPTION);
RIL_E_(NO_NETWORK_FOUND);
RIL_E_(DEVICE_IN_USE);
RIL_E_(ABORTED);
RIL_E_(INVALID_RESPONSE);
default:
snprintf(unknown, sizeof(unknown), "%d", error);
return unknown;
}
}
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);
RIL_REQUEST_(START_LCE);
RIL_REQUEST_(STOP_LCE);
RIL_REQUEST_(GET_ACTIVITY_INFO);
RIL_REQUEST_(GET_CARRIER_RESTRICTIONS);
RIL_REQUEST_(SEND_DEVICE_STATE);
RIL_REQUEST_(SET_UNSOLICITED_RESPONSE_FILTER);
RIL_REQUEST_(SET_SIM_CARD_POWER);
RIL_REQUEST_(SET_CARRIER_INFO_IMSI_ENCRYPTION);
RIL_REQUEST_(START_NETWORK_SCAN);
RIL_REQUEST_(STOP_NETWORK_SCAN);
RIL_REQUEST_(START_KEEPALIVE);
RIL_REQUEST_(STOP_KEEPALIVE);
case RIL_RESPONSE_ACKNOWLEDGEMENT:
return "RESPONSE_ACK";
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;
}
}
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto)
{
switch (proto) {
case OFONO_GPRS_PROTO_IPV6:
return RIL_PROTO_IPV6_STR;
case OFONO_GPRS_PROTO_IPV4V6:
return RIL_PROTO_IPV4V6_STR;
case OFONO_GPRS_PROTO_IP:
return RIL_PROTO_IP_STR;
}
return NULL;
}
int ril_protocol_to_ofono(const gchar *str)
{
if (str) {
if (!strcmp(str, RIL_PROTO_IPV6_STR)) {
return OFONO_GPRS_PROTO_IPV6;
} else if (!strcmp(str, RIL_PROTO_IPV4V6_STR)) {
return OFONO_GPRS_PROTO_IPV4V6;
} else if (!strcmp(str, RIL_PROTO_IP_STR)) {
return OFONO_GPRS_PROTO_IP;
}
}
return -1;
}
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth)
{
switch (auth) {
case OFONO_GPRS_AUTH_METHOD_NONE:
return RIL_AUTH_NONE;
case OFONO_GPRS_AUTH_METHOD_CHAP:
return RIL_AUTH_CHAP;
case OFONO_GPRS_AUTH_METHOD_PAP:
return RIL_AUTH_PAP;
case OFONO_GPRS_AUTH_METHOD_ANY:
/* Use default */
break;
}
/* Default */
return RIL_AUTH_BOTH;
}
/* Returns enum access_technology or -1 on failure. */
int ril_parse_tech(const char *stech, int *ril_tech)
{
int access_tech = -1;
int tech = -1;
if (gutil_parse_int(stech, 0, &tech)) {
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:
case RADIO_TECH_LTE_CA:
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

@@ -1,54 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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"
#include <ofono/gprs-context.h>
struct ofono_network_operator;
const char *ril_error_to_string(int error);
const char *ril_request_to_string(guint request);
const char *ril_unsol_event_to_string(guint event);
const char *ril_radio_state_to_string(int radio_state);
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto);
int ril_protocol_to_ofono(const char *str);
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth);
int ril_parse_tech(const char *stech, int *ril_tech);
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
#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

@@ -1,218 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ril_vendor.h"
#include "ril_vendor_impl.h"
#include "ril_log.h"
#include <grilio_channel.h>
G_DEFINE_ABSTRACT_TYPE(RilVendor, ril_vendor, G_TYPE_OBJECT)
/* Vendor driver descriptors are in the "__vendor" section */
extern const struct ril_vendor_driver __start___vendor[];
extern const struct ril_vendor_driver __stop___vendor[];
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name)
{
if (name) {
const struct ril_vendor_driver *d;
for (d = __start___vendor; d < __stop___vendor; d++) {
if (!strcasecmp(d->name, name)) {
return d;
}
}
}
return NULL;
}
RilVendor *ril_vendor_create(const struct ril_vendor_driver *driver,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *config)
{
return (driver && driver->create_vendor) ?
driver->create_vendor(driver->driver_data, io, path, config) :
NULL;
}
RilVendor *ril_vendor_ref(RilVendor *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_VENDOR(self));
}
return self;
}
void ril_vendor_unref(RilVendor *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_VENDOR(self));
}
}
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
struct ril_vendor_defaults *defaults)
{
if (vendor && vendor->get_defaults) {
vendor->get_defaults(defaults);
}
}
const char *ril_vendor_request_to_string(RilVendor *self, guint request)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
request_to_string(self, request) : NULL;
}
const char *ril_vendor_event_to_string(RilVendor *self, guint event)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
event_to_string(self, event) : NULL;
}
void ril_vendor_set_network(RilVendor *self, struct ril_network *nw)
{
if (G_LIKELY(self)) {
RIL_VENDOR_GET_CLASS(self)->set_network(self, nw);
}
}
GRilIoRequest *ril_vendor_set_attach_apn_req(RilVendor *self, const char *apn,
const char *user, const char *password,
enum ril_auth auth, const char *proto)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
set_attach_apn_req(self, apn, user, password, auth, proto) :
NULL;
}
GRilIoRequest *ril_vendor_data_call_req(RilVendor *self, int tech,
enum ril_data_profile profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
data_call_req(self, tech, profile, apn, username, password,
auth, proto) : NULL;
}
gboolean ril_vendor_data_call_parse(RilVendor *self,
struct ril_data_call *call, int ver, GRilIoParser *rilp)
{
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
data_call_parse(self, call, ver, rilp);
}
gboolean ril_vendor_signal_strength_parse(RilVendor *self,
struct ril_vendor_signal_strength *signal_strength,
GRilIoParser *rilp)
{
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
signal_strength_parse(self, signal_strength, rilp);
}
static void ril_vendor_default_set_network(RilVendor *self,
struct ril_network *network)
{
if (self->network != network) {
if (self->network) {
g_object_remove_weak_pointer(G_OBJECT(self->network),
(gpointer*) &self->network);
}
self->network = network;
if (self->network) {
g_object_add_weak_pointer(G_OBJECT(network),
(gpointer*) &self->network);
}
}
}
static const char *ril_vendor_default_id_to_string(RilVendor *self, guint id)
{
return NULL;
}
static GRilIoRequest *ril_vendor_default_set_attach_apn_req(RilVendor *self,
const char *apn, const char *username,
const char *password, enum ril_auth auth,
const char *proto)
{
return NULL;
}
static GRilIoRequest *ril_vendor_default_data_call_req(RilVendor *self,
int tech, enum ril_data_profile profile,
const char *apn, const char *user, const char *passwd,
enum ril_auth auth, const char *proto)
{
return NULL;
}
static gboolean ril_vendor_default_data_call_parse(RilVendor *self,
struct ril_data_call *call, int version,
GRilIoParser *rilp)
{
return FALSE;
}
static gboolean ril_vendor_default_signal_strength_parse(RilVendor *self,
struct ril_vendor_signal_strength *signal_strength,
GRilIoParser *rilp)
{
return FALSE;
}
void ril_vendor_init_base(RilVendor *self, GRilIoChannel *io)
{
self->io = grilio_channel_ref(io);
}
static void ril_vendor_init(RilVendor *self)
{
}
static void ril_vendor_finalize(GObject* object)
{
RilVendor *self = RIL_VENDOR(object);
if (self->network) {
g_object_remove_weak_pointer(G_OBJECT(self->network),
(gpointer*) &self->network);
}
grilio_channel_unref(self->io);
G_OBJECT_CLASS(ril_vendor_parent_class)->finalize(object);
}
static void ril_vendor_class_init(RilVendorClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = ril_vendor_finalize;
klass->set_network = ril_vendor_default_set_network;
klass->request_to_string = ril_vendor_default_id_to_string;
klass->event_to_string = ril_vendor_default_id_to_string;
klass->set_attach_apn_req = ril_vendor_default_set_attach_apn_req;
klass->data_call_req = ril_vendor_default_data_call_req;
klass->data_call_parse = ril_vendor_default_data_call_parse;
klass->signal_strength_parse = ril_vendor_default_signal_strength_parse;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,91 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_VENDOR_H
#define RIL_VENDOR_H
#include "ril_types.h"
struct ril_vendor_defaults {
gboolean empty_pin_query;
gboolean legacy_imei_query;
gboolean enable_cbs;
gboolean enable_stk;
gboolean replace_strange_oper;
gboolean query_available_band_mode;
gboolean use_data_profiles;
gboolean force_gsm_when_radio_off;
guint mms_data_profile_id;
};
struct ril_vendor_driver {
const char *name;
const void *driver_data;
void (*get_defaults)(struct ril_vendor_defaults *defaults);
struct ril_vendor *(*create_vendor)(const void *driver_data,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *cfg);
};
struct ril_vendor_signal_strength {
gint32 gsm; /* (0-31, 99) per TS 27.007 8.5 */
gint32 lte; /* (0-31, 99) per TS 27.007 8.5 */
gint32 qdbm; /* 4*dBm, 0 if none */
};
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name);
struct ril_vendor *ril_vendor_create
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
const char *path, const struct ril_slot_config *cfg);
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
struct ril_vendor_defaults *defaults);
struct ril_vendor *ril_vendor_ref(struct ril_vendor *vendor);
void ril_vendor_unref(struct ril_vendor *vendor);
const char *ril_vendor_request_to_string(struct ril_vendor *vendor,
guint request);
const char *ril_vendor_event_to_string(struct ril_vendor *vendor,
guint event);
void ril_vendor_set_network(struct ril_vendor *vendor, struct ril_network *nw);
GRilIoRequest *ril_vendor_set_attach_apn_req(struct ril_vendor *vendor,
const char *apn, const char *username,
const char *password, enum ril_auth auth,
const char *proto);
GRilIoRequest *ril_vendor_data_call_req(struct ril_vendor *vendor, int tech,
enum ril_data_profile profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
gboolean ril_vendor_data_call_parse(struct ril_vendor *vendor,
struct ril_data_call *call, int version,
GRilIoParser *rilp);
gboolean ril_vendor_signal_strength_parse(struct ril_vendor *vendor,
struct ril_vendor_signal_strength *signal_strength,
GRilIoParser *rilp);
/* Put vendor driver descriptors to the "__vendor" section */
#define RIL_VENDOR_DRIVER_DEFINE(name) const struct ril_vendor_driver name \
__attribute__((used, section("__vendor"))) =
#endif /* RIL_VENDOR_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,70 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_VENDOR_IMPL_H
#define RIL_VENDOR_IMPL_H
#include "ril_vendor.h"
#include <glib-object.h>
typedef struct ril_vendor {
GObject parent;
GRilIoChannel *io;
struct ril_network *network;
} RilVendor;
typedef struct ril_vendor_class {
GObjectClass parent;
void (*set_network)(RilVendor *vendor, struct ril_network *network);
const char *(*request_to_string)(RilVendor *vendor, guint request);
const char *(*event_to_string)(RilVendor *vendor, guint event);
GRilIoRequest *(*set_attach_apn_req)(RilVendor *vendor,
const char *apn, const char *username,
const char *password, enum ril_auth auth,
const char *proto);
GRilIoRequest *(*data_call_req)(RilVendor *vendor, int tech,
enum ril_data_profile profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
gboolean (*data_call_parse)(RilVendor *vendor,
struct ril_data_call *call, int version,
GRilIoParser *rilp);
gboolean (*signal_strength_parse)(RilVendor *vendor,
struct ril_vendor_signal_strength *signal_strength,
GRilIoParser *rilp);
} RilVendorClass;
GType ril_vendor_get_type(void);
#define RIL_VENDOR_TYPE (ril_vendor_get_type())
#define RIL_VENDOR(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_VENDOR_TYPE, RilVendor)
#define RIL_VENDOR_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
RIL_VENDOR_TYPE, RilVendorClass)
#define RIL_VENDOR_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
RIL_VENDOR_TYPE, RilVendorClass)
void ril_vendor_init_base(RilVendor *vendor, GRilIoChannel *io);
#endif /* RIL_VENDOR_IMPL_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,8 @@
#include <ofono/call-forwarding.h>
#include "common.h"
#pragma GCC diagnostic ignored "-Wrestrict"
#include "gril.h"
#include "rilmodem.h"

View File

@@ -108,7 +108,8 @@ static gboolean lte_delayed_register(gpointer user_data)
return FALSE;
}
static int ril_lte_probe(struct ofono_lte *lte, void *user_data)
static int ril_lte_probe(struct ofono_lte *lte,
unsigned int vendor, void *user_data)
{
GRil *ril = user_data;
struct ril_lte_data *ld;

View File

@@ -37,6 +37,8 @@
#include <ofono/modem.h>
#include <ofono/netreg.h>
#pragma GCC diagnostic ignored "-Wrestrict"
#include <gril/gril.h>
#include "common.h"

View File

@@ -91,7 +91,8 @@ static gboolean lte_delayed_register(gpointer user_data)
return FALSE;
}
static int ublox_lte_probe(struct ofono_lte *lte, void *data)
static int ublox_lte_probe(struct ofono_lte *lte,
unsigned int vendor, void *data)
{
GAtChat *chat = data;
struct lte_driver_data *ldd;

View File

@@ -30,6 +30,9 @@
#include <string.h>
#include <alloca.h>
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wcast-function-type"
#include <glib.h>
#include "ringbuffer.h"

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017-2019 Jolla Ltd.
* Copyright (C) 2017-2021 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
@@ -13,20 +13,26 @@
* GNU General Public License for more details.
*/
#ifndef SAILFISH_CELL_INFO_H
#define SAILFISH_CELL_INFO_H
#ifndef OFONO_CELL_INFO_H
#define OFONO_CELL_INFO_H
#include <glib.h>
/* This API exists since mer/1.24+git2 */
enum sailfish_cell_type {
SAILFISH_CELL_TYPE_GSM,
SAILFISH_CELL_TYPE_WCDMA,
SAILFISH_CELL_TYPE_LTE
#ifdef __cplusplus
extern "C" {
#endif
#include <ofono/types.h>
enum ofono_cell_type {
OFONO_CELL_TYPE_GSM,
OFONO_CELL_TYPE_WCDMA,
OFONO_CELL_TYPE_LTE
};
#define SAILFISH_CELL_INVALID_VALUE (INT_MAX)
#define OFONO_CELL_INVALID_VALUE (INT_MAX)
struct sailfish_cell_info_gsm {
struct ofono_cell_info_gsm {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int lac; /* Location Area Code (0..65535) */
@@ -38,7 +44,7 @@ struct sailfish_cell_info_gsm {
int timingAdvance; /* Timing Advance. 1 period = 48/13 us */
};
struct sailfish_cell_info_wcdma {
struct ofono_cell_info_wcdma {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int lac; /* Location Area Code (0..65535) */
@@ -49,7 +55,7 @@ struct sailfish_cell_info_wcdma {
int bitErrorRate; /* (0-7, 99) TS 27.007 */
};
struct sailfish_cell_info_lte {
struct ofono_cell_info_lte {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int ci; /* Cell Identity */
@@ -64,51 +70,50 @@ struct sailfish_cell_info_lte {
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
};
struct sailfish_cell {
enum sailfish_cell_type type;
gboolean registered;
typedef struct ofono_cell {
enum ofono_cell_type type;
ofono_bool_t registered;
union {
struct sailfish_cell_info_gsm gsm;
struct sailfish_cell_info_wcdma wcdma;
struct sailfish_cell_info_lte lte;
struct ofono_cell_info_gsm gsm;
struct ofono_cell_info_wcdma wcdma;
struct ofono_cell_info_lte lte;
} info;
} *ofono_cell_ptr;
struct ofono_cell_info {
const struct ofono_cell_info_proc *proc;
const ofono_cell_ptr *cells; /* NULL-terminated */
};
struct sailfish_cell_info {
const struct sailfish_cell_info_proc *proc;
GSList *cells;
typedef void (*ofono_cell_info_cb_t)(struct ofono_cell_info *ci, void *data);
struct ofono_cell_info_proc {
void (*ref)(struct ofono_cell_info *ci);
void (*unref)(struct ofono_cell_info *ci);
unsigned long (*add_change_handler)(struct ofono_cell_info *ci,
ofono_cell_info_cb_t cb, void *data);
void (*remove_handler)(struct ofono_cell_info *ci, unsigned long id);
void (*set_update_interval)(struct ofono_cell_info *ci, int ms);
void (*set_enabled)(struct ofono_cell_info *ci, ofono_bool_t enabled);
};
typedef void (*sailfish_cell_info_cb_t)(struct sailfish_cell_info *info,
void *arg);
/* Wrappers for ofono_cell_info objects */
struct ofono_cell_info *ofono_cell_info_ref(struct ofono_cell_info *ci);
void ofono_cell_info_unref(struct ofono_cell_info *ci);
unsigned long ofono_cell_info_add_change_handler(struct ofono_cell_info *ci,
ofono_cell_info_cb_t cb, void *data);
void ofono_cell_info_remove_handler(struct ofono_cell_info *ci,
unsigned long id);
void ofono_cell_info_set_update_interval(struct ofono_cell_info *ci, int ms);
void ofono_cell_info_set_enabled(struct ofono_cell_info *ci, ofono_bool_t on);
int ofono_cell_compare_location(const struct ofono_cell *c1,
const struct ofono_cell *c2);
struct sailfish_cell_info_proc {
void (*ref)(struct sailfish_cell_info *info);
void (*unref)(struct sailfish_cell_info *info);
gulong (*add_cells_changed_handler)(struct sailfish_cell_info *info,
sailfish_cell_info_cb_t cb, void *arg);
void (*remove_handler)(struct sailfish_cell_info *info, gulong id);
void (*set_update_interval)(struct sailfish_cell_info *info, int ms);
};
#ifdef __cplusplus
}
#endif
/* Utilities */
gint sailfish_cell_compare_func(gconstpointer v1, gconstpointer v2);
gint sailfish_cell_compare_location(const struct sailfish_cell *c1,
const struct sailfish_cell *c2);
/* Cell info object API */
struct sailfish_cell_info *sailfish_cell_info_ref
(struct sailfish_cell_info *info);
void sailfish_cell_info_unref(struct sailfish_cell_info *info);
gulong sailfish_cell_info_add_cells_changed_handler
(struct sailfish_cell_info *info,
sailfish_cell_info_cb_t cb, void *arg);
void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
gulong id);
void sailfish_cell_info_set_update_interval(struct sailfish_cell_info *info,
int ms);
#endif /* SAILFISH_CELINFO_H */
#endif /* OFONO_CELL_INFO_H */
/*
* Local Variables:

61
ofono/include/conf.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2021 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 OFONO_CONF_H
#define OFONO_CONF_H
/* This API exists since mer/1.24+git2 */
#ifdef __cplusplus
extern "C" {
#endif
#include <glib.h>
/* If a value isn't found in the specified group, it's looked up in this one */
#define OFONO_COMMON_SETTINGS_GROUP "Settings"
/* Utilities for parsing config files */
void ofono_conf_merge_files(GKeyFile *conf, const char *file);
char *ofono_conf_get_string(GKeyFile *conf, const char *group,
const char *key) G_GNUC_WARN_UNUSED_RESULT;
char **ofono_conf_get_strings(GKeyFile *conf, const char *group,
const char *key, char delimiter) G_GNUC_WARN_UNUSED_RESULT;
gboolean ofono_conf_get_integer(GKeyFile *conf, const char *group,
const char *key, int *value);
gboolean ofono_conf_get_boolean(GKeyFile *conf, const char *group,
const char *key, gboolean *value);
gboolean ofono_conf_get_flag(GKeyFile *conf, const char *group,
const char *key, int flag, int *flags);
gboolean ofono_conf_get_enum(GKeyFile *conf, const char *group,
const char *key, int *result, const char *name, int value, ...)
G_GNUC_NULL_TERMINATED;
gboolean ofono_conf_get_mask(GKeyFile *conf, const char *group,
const char *key, int *result, const char *name, int value, ...)
G_GNUC_NULL_TERMINATED;
#ifdef __cplusplus
}
#endif
#endif /* OFONO_CONF_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2019-2020 Jolla Ltd.
* Copyright (C) 2019-2021 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
@@ -158,6 +158,10 @@ const char *ofono_dbus_access_intf_name(enum ofono_dbus_access_intf intf);
const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
int method);
/* Since mer/1.24+git2 */
ofono_bool_t ofono_dbus_access_method_allowed(const char *sender,
enum ofono_dbus_access_intf iface, int method, const char *arg);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,55 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Open Mobile Platform LLC.
*
* 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 OFONO_DBUS_CLIENTS_H
#define OFONO_DBUS_CLIENTS_H
#include <ofono/types.h>
#include <ofono/dbus.h>
/* Since mer/1.23+git31 */
struct ofono_dbus_clients;
typedef void (*ofono_dbus_clients_notify_func)(const char *name,
void *user_data);
struct ofono_dbus_clients *ofono_dbus_clients_new(DBusConnection *conn,
ofono_dbus_clients_notify_func notify, void *user_data);
void ofono_dbus_clients_free(struct ofono_dbus_clients *clients);
unsigned int ofono_dbus_clients_count(struct ofono_dbus_clients *clients);
ofono_bool_t ofono_dbus_clients_add(struct ofono_dbus_clients *clients,
const char *name);
ofono_bool_t ofono_dbus_clients_remove(struct ofono_dbus_clients *clients,
const char *name);
void ofono_dbus_clients_signal(struct ofono_dbus_clients *clients,
DBusMessage *signal);
void ofono_dbus_clients_signal_property_changed(struct ofono_dbus_clients *dc,
const char *path, const char *interface, const char *name,
int type, const void *value);
#endif /* OFONO_DBUS_CLIENTS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -3,7 +3,7 @@
* oFono - Open Telephony stack for Linux
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2016 Jolla Ltd.
* Copyright (C) 2013-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __OFONO_DBUS_H
@@ -83,6 +79,8 @@ extern "C" {
DBUS_TYPE_VARIANT_AS_STRING \
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
#define OFONO_ERROR_INTERFACE "org.ofono.Error"
DBusConnection *ofono_dbus_get_connection(void);
void ofono_dbus_dict_append(DBusMessageIter *dict, const char *key, int type,
@@ -110,6 +108,36 @@ int ofono_dbus_signal_dict_property_changed(DBusConnection *conn,
const char *name, int type,
const void *value);
/* Since mer/1.23+git31 */
DBusMessage *ofono_dbus_signal_new_property_changed(const char *path,
const char *interface,
const char *name,
int type, const void *value);
/* Since mer/1.24+git2 */
DBusMessage *ofono_dbus_error_invalid_args(DBusMessage *msg);
DBusMessage *ofono_dbus_error_invalid_format(DBusMessage *msg);
DBusMessage *ofono_dbus_error_not_implemented(DBusMessage *msg);
DBusMessage *ofono_dbus_error_failed(DBusMessage *msg);
DBusMessage *ofono_dbus_error_busy(DBusMessage *msg);
DBusMessage *ofono_dbus_error_not_found(DBusMessage *msg);
DBusMessage *ofono_dbus_error_not_active(DBusMessage *msg);
DBusMessage *ofono_dbus_error_not_supported(DBusMessage *msg);
DBusMessage *ofono_dbus_error_not_available(DBusMessage *msg);
DBusMessage *ofono_dbus_error_timed_out(DBusMessage *msg);
DBusMessage *ofono_dbus_error_sim_not_ready(DBusMessage *msg);
DBusMessage *ofono_dbus_error_in_use(DBusMessage *msg);
DBusMessage *ofono_dbus_error_not_attached(DBusMessage *msg);
DBusMessage *ofono_dbus_error_attach_in_progress(DBusMessage *msg);
DBusMessage *ofono_dbus_error_not_registered(DBusMessage *msg);
DBusMessage *ofono_dbus_error_canceled(DBusMessage *msg);
DBusMessage *ofono_dbus_error_access_denied(DBusMessage *msg);
DBusMessage *ofono_dbus_error_emergency_active(DBusMessage *msg);
DBusMessage *ofono_dbus_error_incorrect_password(DBusMessage *msg);
DBusMessage *ofono_dbus_error_not_allowed(DBusMessage *msg);
DBusMessage *ofono_dbus_error_not_recognized(DBusMessage *msg);
DBusMessage *ofono_dbus_error_network_terminated(DBusMessage *msg);
#ifdef __cplusplus
}
#endif

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 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
@@ -128,6 +129,8 @@ void ofono_gprs_context_set_ipv4_gateway(struct ofono_gprs_context *gc,
const char *gateway);
void ofono_gprs_context_set_ipv4_dns_servers(struct ofono_gprs_context *gc,
const char **dns);
void ofono_gprs_context_set_ipv4_proxy_cscf(struct ofono_gprs_context *gc,
const char **pcscf); /* Since mer/1.23+git30 */
void ofono_gprs_context_set_ipv6_address(struct ofono_gprs_context *gc,
const char *address);
@@ -137,10 +140,15 @@ void ofono_gprs_context_set_ipv6_gateway(struct ofono_gprs_context *gc,
const char *gateway);
void ofono_gprs_context_set_ipv6_dns_servers(struct ofono_gprs_context *gc,
const char **dns);
void ofono_gprs_context_set_ipv6_proxy_cscf(struct ofono_gprs_context *gc,
const char **pcscf); /* Since mer/1.23+git30 */
void ofono_gprs_context_signal_change(struct ofono_gprs_context *gc,
unsigned int cid);
enum ofono_gprs_context_type ofono_gprs_context_get_assigned_type(
struct ofono_gprs_context *gc); /* Since mer/1.24+git2 */
#ifdef __cplusplus
}
#endif

View File

@@ -3,6 +3,7 @@
* oFono - Open Telephony stack for Linux
*
* Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2015-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -55,6 +56,14 @@ int ofono_gprs_provision_driver_register(
void ofono_gprs_provision_driver_unregister(
const struct ofono_gprs_provision_driver *driver);
/* Since mer/1.24+git2 */
ofono_bool_t ofono_gprs_provision_get_settings(const char *mcc,
const char *mnc, const char *spn,
struct ofono_gprs_provision_data **settings,
int *count);
void ofono_gprs_provision_free_settings(
struct ofono_gprs_provision_data *settings,
int count);
#ifdef __cplusplus
}
#endif

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2017-2021 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
@@ -87,6 +88,9 @@ void ofono_gprs_attached_update(struct ofono_gprs *gprs);
const struct ofono_gprs_primary_context *ofono_gprs_context_settings_by_type
(struct ofono_gprs *gprs, enum ofono_gprs_context_type type);
/* Since mer/1.24+git2 */
ofono_bool_t ofono_gprs_get_roaming_allowed(struct ofono_gprs *gprs);
#ifdef __cplusplus
}
#endif

View File

@@ -38,7 +38,7 @@ typedef void (*ofono_lte_cb_t)(const struct ofono_error *error, void *data);
struct ofono_lte_driver {
const char *name;
int (*probe)(struct ofono_lte *lte, void *data);
int (*probe)(struct ofono_lte *lte, unsigned int vendor, void *data);
void (*remove)(struct ofono_lte *lte);
void (*set_default_attach_info)(const struct ofono_lte *lte,
const struct ofono_lte_default_attach_info *info,
@@ -50,6 +50,7 @@ int ofono_lte_driver_register(const struct ofono_lte_driver *d);
void ofono_lte_driver_unregister(const struct ofono_lte_driver *d);
struct ofono_lte *ofono_lte_create(struct ofono_modem *modem,
unsigned int vendor,
const char *driver, void *data);
void ofono_lte_register(struct ofono_lte *lte);

67
ofono/include/misc.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2021 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 __OFONO_MISC_H
#define __OFONO_MISC_H
/*
* Miscellaneous utilities which do not fall into any other category.
*
* This file exists since mer/1.24+git2
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <ofono/netreg.h>
const char *ofono_netreg_status_to_string(enum ofono_netreg_status status);
const char *ofono_access_technology_to_string(enum ofono_access_technology t);
char *ofono_sim_string_to_utf8(const unsigned char *buffer, int length);
void ofono_sim_string_free(char *str);
void ofono_encode_hex(const void *in, unsigned int n, char out[/* 2*n+1 */]);
#define OFONO_UNPACK_7BIT_USSD (0x01) /* flags */
unsigned int ofono_unpack_7bit(const void *in, unsigned int len,
unsigned int flags, void *out_buf, unsigned int out_buf_size);
#define OFONO_PHONE_NUMBER_BUFFER_SIZE (OFONO_MAX_PHONE_NUMBER_LENGTH + 2)
const char *ofono_phone_number_to_string(const struct ofono_phone_number *ph,
char buffer[/* OFONO_PHONE_NUMBER_BUFFER_SIZE */]);
#define OFONO_EF_PATH_BUFFER_SIZE 6
unsigned int ofono_get_ef_path_2g(unsigned short id,
unsigned char path[/* OFONO_EF_PATH_BUFFER_SIZE */]);
unsigned int ofono_get_ef_path_3g(unsigned short id,
unsigned char path[/* OFONO_EF_PATH_BUFFER_SIZE */]);
ofono_bool_t ofono_parse_get_response_2g(const void *response, unsigned int len,
unsigned int *file_len, unsigned int *record_len,
unsigned int *structure, unsigned char *access,
unsigned char *file_status);
ofono_bool_t ofono_parse_get_response_3g(const void *response, unsigned int len,
unsigned int *file_len, unsigned int *record_len,
unsigned int *structure, unsigned char *access,
unsigned short *efid);
ofono_bool_t ofono_decode_cbs_dcs_charset(unsigned char dcs,
enum ofono_sms_charset *charset);
#ifdef __cplusplus
}
#endif
#endif /* __OFONO_MISC_H */

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -86,6 +87,9 @@ const char *ofono_modem_get_path(struct ofono_modem *modem);
struct ofono_sim *ofono_modem_get_sim(struct ofono_modem *modem);
struct ofono_gprs *ofono_modem_get_gprs(struct ofono_modem *modem);
struct ofono_voicecall *ofono_modem_get_voicecall(struct ofono_modem *modem);
struct ofono_netreg *ofono_modem_get_netreg(struct ofono_modem *modem);
struct ofono_radio_settings *ofono_modem_get_radio_settings
(struct ofono_modem *modem); /* Since mer/1.24+git2 */
void ofono_modem_set_data(struct ofono_modem *modem, void *data);
void *ofono_modem_get_data(struct ofono_modem *modem);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2016-2017 Jolla Ltd.
* Copyright (C) 2016-2021 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
@@ -13,13 +13,15 @@
* GNU General Public License for more details.
*/
#ifndef MTU_WATCH_H
#define MTU_WATCH_H
#ifndef __OFONO_MTU_LIMIT_H
#define __OFONO_MTU_LIMIT_H
struct mtu_watch;
/* This API exists since mer/1.24+git2 */
struct mtu_watch *mtu_watch_new(int max_mtu);
void mtu_watch_free(struct mtu_watch *mw);
void mtu_watch_set_ifname(struct mtu_watch *mw, const char *ifname);
struct ofono_mtu_limit;
#endif /* MTU_WATCH_H */
struct ofono_mtu_limit *ofono_mtu_limit_new(int max_mtu);
void ofono_mtu_limit_free(struct ofono_mtu_limit *ml);
void ofono_mtu_limit_set_ifname(struct ofono_mtu_limit *ml, const char *ifname);
#endif /* __OFONO_MTU_LIMIT_H */

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 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
@@ -28,8 +29,28 @@ extern "C" {
#include <ofono/types.h>
struct ofono_modem;
struct ofono_netreg;
enum ofono_netreg_status {
OFONO_NETREG_STATUS_NONE = -1,
/* 27.007 Section 7.2 <stat> */
OFONO_NETREG_STATUS_NOT_REGISTERED = 0,
OFONO_NETREG_STATUS_REGISTERED = 1,
OFONO_NETREG_STATUS_SEARCHING = 2,
OFONO_NETREG_STATUS_DENIED = 3,
OFONO_NETREG_STATUS_UNKNOWN = 4,
OFONO_NETREG_STATUS_ROAMING = 5
}; /* Since mer/1.24+git2 */
/* 27.007 Section 7.3 <stat> */
enum ofono_operator_status {
OFONO_OPERATOR_STATUS_UNKNOWN = 0,
OFONO_OPERATOR_STATUS_AVAILABLE = 1,
OFONO_OPERATOR_STATUS_CURRENT = 2,
OFONO_OPERATOR_STATUS_FORBIDDEN = 3
}; /* Since mer/1.24+git2 */
/* Theoretical limit is 16, but each GSM char can be encoded into
* * 3 UTF8 characters resulting in 16*3=48 chars
* */
@@ -39,8 +60,8 @@ struct ofono_network_operator {
char name[OFONO_MAX_OPERATOR_NAME_LENGTH + 1];
char mcc[OFONO_MAX_MCC_LENGTH + 1];
char mnc[OFONO_MAX_MNC_LENGTH + 1];
int status;
int tech;
enum ofono_operator_status status;
enum ofono_access_technology tech;
};
typedef void (*ofono_netreg_operator_cb_t)(const struct ofono_error *error,
@@ -110,13 +131,17 @@ void *ofono_netreg_get_data(struct ofono_netreg *netreg);
int ofono_netreg_get_location(struct ofono_netreg *netreg);
int ofono_netreg_get_cellid(struct ofono_netreg *netreg);
int ofono_netreg_get_status(struct ofono_netreg *netreg);
enum ofono_netreg_status ofono_netreg_get_status(struct ofono_netreg *netreg);
int ofono_netreg_get_technology(struct ofono_netreg *netreg);
const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg);
const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg);
const char *ofono_netreg_get_name(struct ofono_netreg *netreg);
struct sim_spdi *ofono_netreg_get_spdi(struct ofono_netreg *netreg);
/* Since mer/1.24+git2 */
ofono_bool_t ofono_netreg_spdi_lookup(struct ofono_netreg *netreg,
const char *mcc, const char *mnc);
#ifdef __cplusplus
}
#endif

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2015-2021 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
@@ -139,6 +140,8 @@ struct ofono_modem *ofono_radio_settings_get_modem(
const char *ofono_radio_access_mode_to_string(enum ofono_radio_access_mode m);
ofono_bool_t ofono_radio_access_mode_from_string(const char *str,
enum ofono_radio_access_mode *mode);
enum ofono_radio_access_mode ofono_radio_access_max_mode( /* mer/1.24+git2 */
enum ofono_radio_access_mode mask);
#ifdef __cplusplus
}

View File

@@ -4,6 +4,7 @@
*
* Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2015-2021 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
@@ -27,17 +28,21 @@
extern "C" {
#endif
struct ofono_sim_mnclength_driver {
const char *name;
int (*get_mnclength)(const char *imsi);
/* Since mer/1.24+git2 */
int (*get_mnclength_mccmnc)(int mcc, int mnc);
};
int ofono_sim_mnclength_driver_register(
struct ofono_sim_mnclength_driver *driver);
const struct ofono_sim_mnclength_driver *driver);
void ofono_sim_mnclength_driver_unregister(
const struct ofono_sim_mnclength_driver *driver);
/* Since mer/1.24+git2 */
int ofono_sim_mnclength_get_mnclength(const char *imsi);
int ofono_sim_mnclength_get_mnclength_mccmnc(int mcc, int mnc);
#ifdef __cplusplus
}

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 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
@@ -210,6 +211,10 @@ struct ofono_sim_driver {
void (*logical_access)(struct ofono_sim *sim, int session_id,
const unsigned char *pdu, unsigned int len,
ofono_sim_logical_access_cb_t cb, void *data);
/* Since mer/1.23+git28 */
void (*open_channel2)(struct ofono_sim *sim, const unsigned char *aid,
unsigned int len, ofono_sim_open_channel_cb_t cb,
void *data);
};
int ofono_sim_driver_register(const struct ofono_sim_driver *d);
@@ -236,6 +241,10 @@ const unsigned char *ofono_sim_get_cphs_service_table(struct ofono_sim *sim);
enum ofono_sim_password_type ofono_sim_get_password_type(struct ofono_sim *sim);
void ofono_sim_refresh_full(struct ofono_sim *sim); /* Since mer/1.24+git2 */
enum ofono_sim_password_type ofono_sim_puk2pin( /* Since mer/1.24+git2 */
enum ofono_sim_password_type type);
unsigned int ofono_sim_add_state_watch(struct ofono_sim *sim,
ofono_sim_state_event_cb_t cb,
void *data, ofono_destroy_func destroy);

159
ofono/include/slot.h Normal file
View File

@@ -0,0 +1,159 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017-2021 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 __OFONO_SLOT_H
#define __OFONO_SLOT_H
/*
* Slots are built-in non-removable modems. Which may or may not apprear
* in the list reported by org.ofono.Manager.GetModems D-Bus call.
*
* This API exists since mer/1.24+git2
*/
#ifdef __cplusplus
extern "C" {
#endif
struct ofono_modem;
#include <ofono/types.h>
#include <ofono/radio-settings.h>
enum ofono_slot_sim_presence {
OFONO_SLOT_SIM_UNKNOWN,
OFONO_SLOT_SIM_ABSENT,
OFONO_SLOT_SIM_PRESENT
};
/* Should be treated as a bitmask although currently it's not */
enum ofono_slot_data_role {
OFONO_SLOT_DATA_NONE = 0,
OFONO_SLOT_DATA_MMS = 0x01,
OFONO_SLOT_DATA_INTERNET = 0x02
};
enum ofono_slot_property {
OFONO_SLOT_PROPERTY_ANY,
OFONO_SLOT_PROPERTY_ENABLED,
OFONO_SLOT_PROPERTY_SIM_PRESENCE,
OFONO_SLOT_PROPERTY_DATA_ROLE
#define OFONO_SLOT_PROPERTY_LAST OFONO_SLOT_PROPERTY_DATA_ROLE
};
enum ofono_slot_manager_property {
OFONO_SLOT_MANAGER_PROPERTY_ANY,
OFONO_SLOT_MANAGER_PROPERTY_MMS_IMSI,
OFONO_SLOT_MANAGER_PROPERTY_MMS_PATH,
OFONO_SLOT_MANAGER_PROPERTY_DEFAULT_VOICE_IMSI,
OFONO_SLOT_MANAGER_PROPERTY_DEFAULT_DATA_IMSI,
OFONO_SLOT_MANAGER_PROPERTY_DEFAULT_VOICE_PATH,
OFONO_SLOT_MANAGER_PROPERTY_DEFAULT_DATA_PATH,
OFONO_SLOT_MANAGER_PROPERTY_READY
#define OFONO_SLOT_MANAGER_PROPERTY_LAST OFONO_SLOT_MANAGER_PROPERTY_READY
};
enum ofono_slot_flags {
OFONO_SLOT_NO_FLAGS = 0,
/* Normally we should be able to have two simultaneously active
* data contexts - one for mobile data and one for MMS. The flag
* below says that for whatever reason it's impossible and mobile
* data has to be disconnected before we can send or receive MMS.
* On such devices it may not be a good idea to automatically
* download MMS because that would kill active mobile data
* connections. */
OFONO_SLOT_FLAG_SINGLE_CONTEXT = 0x01
};
typedef struct ofono_slot {
const char *path;
const char *imei;
const char *imeisv;
ofono_bool_t enabled;
enum ofono_slot_sim_presence sim_presence;
enum ofono_slot_data_role data_role;
} const *ofono_slot_ptr;
struct ofono_slot_manager {
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 ofono_slot_ptr *slots;
ofono_bool_t ready;
};
#define OFONO_SLOT_API_VERSION (1)
struct ofono_slot_driver {
const char *name;
int api_version; /* OFONO_SLOT_API_VERSION */
struct ofono_slot_driver_data *(*init)(struct ofono_slot_manager *m);
unsigned int (*start)(struct ofono_slot_driver_data *d);
void (*cancel)(struct ofono_slot_driver_data *d, unsigned int id);
void (*cleanup)(struct ofono_slot_driver_data *d);
};
typedef void (*ofono_slot_property_cb)(struct ofono_slot *slot,
enum ofono_slot_property property, void* user_data);
typedef void (*ofono_slot_manager_property_cb)(struct ofono_slot_manager *m,
enum ofono_slot_property property, void* user_data);
struct ofono_slot_driver_data;
struct ofono_slot_driver_reg;
struct ofono_slot_driver_reg *ofono_slot_driver_register
(const struct ofono_slot_driver *driver);
struct ofono_slot_driver_data *ofono_slot_driver_get_data
(struct ofono_slot_driver_reg *reg);
void ofono_slot_driver_unregister(struct ofono_slot_driver_reg *reg);
void ofono_slot_driver_started(struct ofono_slot_driver_reg *reg);
struct ofono_slot_manager *ofono_slot_manager_ref(struct ofono_slot_manager *m);
void ofono_slot_manager_unref(struct ofono_slot_manager *m);
void ofono_slot_manager_error(struct ofono_slot_manager *m, const char *key,
const char *message);
unsigned long ofono_slot_manager_add_property_handler
(struct ofono_slot_manager *m, enum ofono_slot_manager_property p,
ofono_slot_manager_property_cb cb, void* data);
void ofono_slot_manager_remove_handler(struct ofono_slot_manager *m,
unsigned long id);
void ofono_slot_manager_remove_handlers(struct ofono_slot_manager *m,
unsigned long *ids, unsigned int n);
struct ofono_cell_info;
struct ofono_slot *ofono_slot_add(struct ofono_slot_manager *m,
const char *path, enum ofono_radio_access_mode techs, const char *imei,
const char *imeisv, enum ofono_slot_sim_presence sim_presence,
enum ofono_slot_flags flags);
struct ofono_slot *ofono_slot_ref(struct ofono_slot *s);
void ofono_slot_unref(struct ofono_slot *s);
void ofono_slot_error(struct ofono_slot *s, const char *key, const char *msg);
void ofono_slot_set_cell_info(struct ofono_slot *s, struct ofono_cell_info *ci);
unsigned long ofono_slot_add_property_handler(struct ofono_slot *s,
enum ofono_slot_property p, ofono_slot_property_cb cb, void* data);
void ofono_slot_remove_handler(struct ofono_slot *s, unsigned long id);
void ofono_slot_remove_handlers(struct ofono_slot *s, unsigned long *ids,
unsigned int n);
void ofono_slot_set_sim_presence(struct ofono_slot *s,
enum ofono_slot_sim_presence sim_presence);
#ifdef __cplusplus
}
#endif
#endif /* __OFONO_SLOT_H */

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 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,11 +43,61 @@ typedef int ofono_bool_t;
typedef void (*ofono_destroy_func)(void *data);
enum ofono_access_technology {
OFONO_ACCESS_TECHNOLOGY_NONE = -1,
/* 27.007 Section 7.3 <AcT> */
OFONO_ACCESS_TECHNOLOGY_GSM = 0,
OFONO_ACCESS_TECHNOLOGY_GSM_COMPACT = 1,
OFONO_ACCESS_TECHNOLOGY_UTRAN = 2,
OFONO_ACCESS_TECHNOLOGY_GSM_EGPRS = 3,
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA = 4,
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSUPA = 5,
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA = 6,
OFONO_ACCESS_TECHNOLOGY_EUTRAN = 7
};
/* 27.007 Section 6.2 */
enum ofono_clir_option {
OFONO_CLIR_OPTION_DEFAULT = 0,
OFONO_CLIR_OPTION_INVOCATION,
OFONO_CLIR_OPTION_SUPPRESSION,
OFONO_CLIR_OPTION_INVOCATION = 1,
OFONO_CLIR_OPTION_SUPPRESSION = 2,
};
/* 27.007 Section 7.6 */
enum ofono_clip_validity {
OFONO_CLIP_VALIDITY_VALID = 0,
OFONO_CLIP_VALIDITY_WITHHELD = 1,
OFONO_CLIP_VALIDITY_NOT_AVAILABLE = 2
};
/* 27.007 Section 7.30 */
enum ofono_cnap_validity {
OFONO_CNAP_VALIDITY_VALID = 0,
OFONO_CNAP_VALIDITY_WITHHELD = 1,
OFONO_CNAP_VALIDITY_NOT_AVAILABLE = 2
};
/* 27.007 Section 7.18 */
enum ofono_call_status {
OFONO_CALL_STATUS_ACTIVE = 0,
OFONO_CALL_STATUS_HELD = 1,
OFONO_CALL_STATUS_DIALING = 2,
OFONO_CALL_STATUS_ALERTING = 3,
OFONO_CALL_STATUS_INCOMING = 4,
OFONO_CALL_STATUS_WAITING = 5,
OFONO_CALL_STATUS_DISCONNECTED
};
/* 27.007 Section 7.18 */
enum ofono_call_direction {
OFONO_CALL_DIRECTION_MOBILE_ORIGINATED = 0,
OFONO_CALL_DIRECTION_MOBILE_TERMINATED = 1
};
enum ofono_sms_charset {
OFONO_SMS_CHARSET_7BIT = 0,
OFONO_SMS_CHARSET_8BIT = 1,
OFONO_SMS_CHARSET_UCS2 = 2
};
enum ofono_error_type {
@@ -96,13 +147,13 @@ struct ofono_cdma_phone_number {
struct ofono_call {
unsigned int id;
int type;
int direction;
int status;
enum ofono_call_direction direction;
enum ofono_call_status status;
struct ofono_phone_number phone_number;
struct ofono_phone_number called_number;
char name[OFONO_MAX_CALLER_NAME_LENGTH + 1];
int clip_validity;
int cnap_validity;
enum ofono_clip_validity clip_validity;
enum ofono_cnap_validity cnap_validity;
};
struct ofono_network_time {

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,37 +22,6 @@ extern "C" {
#include <ofono/voicecall.h>
/* 27.007 Section 7.6 */
enum ofono_clip_validity {
OFONO_CLIP_VALIDITY_VALID = 0,
OFONO_CLIP_VALIDITY_WITHHELD,
OFONO_CLIP_VALIDITY_NOT_AVAILABLE
};
/* 27.007 Section 7.18 */
enum ofono_call_status {
OFONO_CALL_STATUS_ACTIVE = 0,
OFONO_CALL_STATUS_HELD,
OFONO_CALL_STATUS_DIALING,
OFONO_CALL_STATUS_ALERTING,
OFONO_CALL_STATUS_INCOMING,
OFONO_CALL_STATUS_WAITING,
OFONO_CALL_STATUS_DISCONNECTED
};
/* 27.007 Section 7.18 */
enum ofono_call_direction {
OFONO_CALL_DIRECTION_MOBILE_ORIGINATED = 0,
OFONO_CALL_DIRECTION_MOBILE_TERMINATED
};
/* 27.007 Section 7.30 */
enum ofono_cnap_validity {
OFONO_CNAP_VALIDITY_VALID = 0,
OFONO_CNAP_VALIDITY_WITHHELD,
OFONO_CNAP_VALIDITY_NOT_AVAILABLE
};
enum ofono_voicecall_filter_dial_result {
OFONO_VOICECALL_FILTER_DIAL_CONTINUE, /* Run the next filter */
OFONO_VOICECALL_FILTER_DIAL_BLOCK /* Don't dial*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017-2019 Jolla Ltd.
* Copyright (C) 2017-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,21 +17,12 @@
#define OFONO_WATCH_H
#include <ofono/gprs-context.h>
#include <ofono/netreg.h>
struct ofono_modem;
struct ofono_sim;
struct ofono_netreg;
enum ofono_netreg_status {
OFONO_NETREG_STATUS_NONE = -1,
OFONO_NETREG_STATUS_NOT_REGISTERED = 0,
OFONO_NETREG_STATUS_REGISTERED = 1,
OFONO_NETREG_STATUS_SEARCHING = 2,
OFONO_NETREG_STATUS_DENIED = 3,
OFONO_NETREG_STATUS_UNKNOWN = 4,
OFONO_NETREG_STATUS_ROAMING = 5
};
/* This object watches ofono modem and various other things */
struct ofono_watch {
const char *path;

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