Compare commits

...

88 Commits

Author SHA1 Message Date
Pekka Vuorela
a7227c6cad Merge pull request #43 from sailfishos/conf_unit_test
[ofono] Don't care about whitespace in config unit test. JB#61330
2024-02-19 16:01:47 +02:00
Pekka Vuorela
cff7c7adb1 [ofono] Don't care about whitespace in config unit test. JB#61330
New glib keeps some extra line feed on the merged conf file data.
It shouldn't really matter so ignore such differences on the test.
2024-02-19 15:56:39 +02:00
Matti Lehtimäki
a50522b062 Merge pull request #42 from sailfishos/jb61571
Backport two patches from upstream to fix CVE-2023-4233 and CVE-2023-4234
2024-02-19 14:13:18 +02:00
Denis Grigorev
bb7d65f41a smsutil: Validate the length of the address field
This addresses CVE-2023-4233.
2024-02-16 17:50:58 +02:00
Denis Grigorev
278f28d15c smsutil: Check that submit report fits in memory
This addresses CVE-2023-4234.
2024-02-16 17:50:43 +02:00
Matti Lehtimäki
3afa0876c6 Merge pull request #40 from sailfishos/jb58763
[ofono] Add support for NR networks. JB#58763
2023-04-14 22:36:31 +03:00
Matti Lehtimäki
04162f719e [ofono] Add support for NR networks. JB#58763 2023-01-02 11:26:51 +02:00
Slava Monich
4ae4d688ce Merge pull request #41 from monich/uaf
Fix use after free
2023-01-02 11:13:43 +02:00
Slava Monich
224b551feb [voicecall] Fix use after free. JB#54354
Thanks to Denis Grigorev for pointing it out.
2023-01-02 00:38:40 +02:00
Slava Monich
6acf808d89 Merge pull request #38 from monich/conf-mask
Allow merging mask conf values
2022-11-07 16:37:19 +02:00
Slava Monich
942b2efc3b [ofono] Allow merging mask conf values. JB#59210
To allow syntax like disableFeatures += voice
2022-11-07 16:17:36 +02:00
Slava Monich
301b880a87 Merge pull request #37 from monich/cbs-topics-max
Widen the range of allowed cell broadcast channels
2022-10-27 02:12:01 +03:00
Slava Monich
933525829f [cbs] Widen the range of allowed cell broadcast channels. JB#5761 2022-10-25 13:39:33 +03:00
Slava Monich
d8df18c80c Updated upstream hash to point to 1.29 2022-10-25 13:25:52 +03:00
Slava Monich
47fd559c1b Merge pull request #36 from monich/jb58727
Remove event source after closing BT socket
2022-09-08 01:18:26 +03:00
Slava Monich
8fa9a7068f [hfp_ag_bluez5] Remove event source after closing BT socket. JB#58727
Otherwise GIOChannel stays alive and glib main loop keeps polling
invalid fd and eating up CPU time.
2022-09-07 17:21:24 +03:00
Slava Monich
10c1d7ac75 [ims] Tweak the treatment of the default Registration value
To handle the case if it's not IMS_REG_AUTO
2022-05-09 17:57:41 +03:00
Slava Monich
81ad45dfd9 Merge pull request #33 from monich/ims
org.ofono.IpMultimediaSystem D-Bus API tweaks
2022-04-21 04:33:24 +03:00
Slava Monich
0e27cf811b [ims] Extend org.ofono.IpMultimediaSystem D-Bus API. JB#57999
The following property has been added to the API:

	string Registration [readwrite, Sailfish OS specific]

		The IMS registration strategy. Valid values are:

			"disabled" keep registration off
			"enabled"  manual registration
			"auto"     keep registration on

		The Register() method, if implemented, will fail
		with [service].Error.NotAllowed if the value of
		this property is "disabled".
2022-04-21 03:40:28 +03:00
Slava Monich
5ec5081b7d [watch] Added reg_tech watch. JB#57999 2022-04-20 20:23:02 +03:00
Slava Monich
d2cae30a03 [ims] D-Bus access control for org.ofono.IpMultimediaSystem. JB#57408 2022-04-14 01:28:01 +03:00
Slava Monich
e0ea7b54c6 [gprs] Fixed ofono_gprs_context memory leak. JB#54354 2022-03-14 05:06:41 +02:00
Slava Monich
01c5e7fc1a Version 1.29 2022-03-14 04:48:41 +02:00
Slava Monich
291530d291 [sim] OFONO_SIM_DRIVER_API_VERSION 2. JB#54354 2022-03-14 04:47:31 +02:00
Slava Monich
108611ef72 Merge pull request #24 from sailfish-on-dontbeevil/branch-1.29
[ofono] Upgrade ofono baseline to 1.29. JB#54354
2022-03-14 04:44:50 +02:00
Marcel Holtmann
a3c9fc793c Release 1.29 2022-03-11 15:35:22 +00:00
Richard Röjfors
03491c78e7 ublox: gprs-context: Fix router mode IP settings.
The ublox modems always run DHCP when in router mode.
Unfortunately the code overwrote the IP settings with
static IP settings while activating.

Now we respect the networking_mode regardless if
we read settings during activation or read settings
phase.
2022-03-11 15:35:22 +00:00
Antara Borwankar
c534b7e9b0 xmm7modem: Changes in plugin for DSSA functionality
Changed the sim driver vendor for xmm7modem from
OFONO_VENDOR_IFX to OFONO_VENDOR_XMM to handle DSSA functionality.
2022-03-11 15:35:22 +00:00
Antara Borwankar
35e7cd19e6 xmm7modem: handling of dual sim single active feature
Handled DSSA use case for xmm7modem. Added driver function
to switch between available card slots for SIM.

Only one SIM will be active at a given time. On calling this
function the active SIM will be removed and the card slot made
inactive and SIM in the other card slot will be made active.

Use case is similar to a SIM swap/change where one SIM is replaced
another SIM in the same slot.
2022-03-11 15:35:22 +00:00
Antara Borwankar
2ed8b1bb7f sim: added error handling in set slot callback
Adding the handling of error when the driver returns
CME ERROR:4.

This error will be returned for non xmm vendor modems
using ifxmodem driver for sim.
2022-03-11 15:35:22 +00:00
Richard Röjfors
8f65b01f4c ublox: Correct the USBCONF reply prefix
According to the u-blox AT Commands Manual and my tests
the response prefix of AT+UUSBCONF is "+UUSBCONF:", including
a colon. The colon was missing in the code, causing next step
to parse a number to fail, since a colon is not a number.
2022-03-11 15:35:22 +00:00
Richard Röjfors
1aa2ac5e67 ublox: Do not leave vendor_family unset
In a recent patch vendor family was only set if the device
did not support USBCONF, but that resulted in drivers
being registered the "generic" vendor. That caused
for instance netreg to use incorrect cmer mode and fail
on TOBY-L210.
2022-03-11 15:35:22 +00:00
Denis Kenzior
cb8a13433f sim: Initialize card_slot_count and active_card_slot
Initialize both to 1 so that SimManager does not erroneously show
ActiveCardSlot as 0 for drivers that do not (yet) setup these values.
2022-03-11 15:35:22 +00:00
Denis Kenzior
ee1c34cd7f sim: Emit PropertyChanged for ActiveCardSlot changes 2022-03-11 15:35:22 +00:00
Antara Borwankar
2b89f6d488 sim: handling of dual sim single active feature
Added implementation for handling CardSlotCount and ActiveCardSlot
properties for DSSA use case.
2022-03-11 15:35:22 +00:00
Antara Borwankar
32b886d89d sim: Added set function for CardSlotCount and ActiveCardSlot
Adding set function definition for CardSlotCount and ActiveCardSlot
properties.
2022-03-11 15:35:22 +00:00
Antara Borwankar
a9a3e024e1 doc: Added new properties to SimManager for DSSA
Adding two new properties to sim manager interface to handle
dual SIM single active use case.

CardSlotCount [readonly]
Contains the count of number of SIM card slots available.

ActiveCardSlot [readwrite]
Contains the index of the currently active SIM card slot
for dual SIM single active mode.
2022-03-11 15:35:22 +00:00
Jonas Bonn
8c432e5426 ublox: do not set bridge mode for TOBY L2
Trying to set the networking mode to "bridge" mode in the plugin is bogus
because the setting does not apply until after the device has been
reset.  Instead, the current setting should be queried.

If a user wants to set the modem networking mode, the setting should be
made outside of ofono.

The gprs-context driver has already been adjusted to query the
networking mode and to set things up accordingly.
2022-03-11 15:35:22 +00:00
Jonas Bonn
fc26876503 ublox: gprs-context: query networking mode for TOBY L2
The TOBY L2 may run in either "bridge" mode or "router" mode.  For this
model, query the configured mode so that the appropriate settings are
communicated when the context is activated.
2022-03-11 15:35:22 +00:00
Jonas Bonn
7461d52b10 ublox: TOBY L4 supports only router mode
The TOBY L4 supports only "router mode" where the modem presents a
network interface that one can run a DHCP client against.  Behind this
interface, the modem takes care of routing packets via NAT by:

i)  selecting the relevant context based on destination IP
ii) using the first activated context as the default route

In order to have the connection manager, thus, do the right thing, the
context only needs to report itself as being active and with the IP
settings set to method "dhcp".  There's no need for the connection manager
to know details like what IP address the context was assigned.

Tested with connman that does the right thing when it finds an active
"dhcp" context.
2022-03-11 15:35:22 +00:00
Jonas Bonn
9e2fd992b5 ublox: pass model_id to gprs-context driver
Depending on the transport used on the data connection we want either
the "atmodem" (PPP) driver or the "ubloxmodem".  For the "ubloxmodem",
we want to pass the model data so this patch wrangles some parameters to
make sure that right driver and right variant data are passed.
2022-03-11 15:35:22 +00:00
Jonas Bonn
1295539515 ublox: gprs-context: take model parameter 2022-03-11 15:35:22 +00:00
Jonas Bonn
65aa5aab14 ublox: pass model id to LTE plugin 2022-03-11 15:35:22 +00:00
Jonas Bonn
8da2178a96 ublox: extend LTE driver
There are a couple of semi-independent changes here:

* use the 'vendor' parameter to pass the modem 'model'
* support TOBY L4 modem which uses a fixed CID for configuring the EPS
default bearer
* add the setup of authentication parameters that was recently added to
the atmodem LTE driver
2022-03-11 15:35:22 +00:00
Jonas Bonn
181c74b1a9 Separate ATE and AT+CMEE commands
The TOBY L4 doesn't seem to like seeing these two commands on the same
line...
2022-03-11 15:35:22 +00:00
Jonas Bonn
a30ef13844 udevng: detect ublox TOBY L4
ttyACM0 (USB interface 02) is reportedly unreliable (breaking DHCP setup)
so the recommended approach is to use ttyACM2 (USB interface 06)
exclusively.
2022-03-11 15:35:22 +00:00
Jonas Bonn
ec85e50ab4 ublox: add TOBY L4 models 2022-03-11 15:35:22 +00:00
Jonas Bonn
1cedb9d750 ublox: add device flags
Some aspects of a device are detectable at runtime, like the USB profile
detection that was added in a patch preceding this one.  This patch
switches the driver over from creating a new "vendor id" for each
profile to just setting a flag.  This is more easily extensible as we
detect other features of the modem.
2022-03-11 15:35:22 +00:00
Jonas Bonn
a412839f45 udevng: ublox: Model string no longer used 2022-03-11 15:35:22 +00:00
Jonas Bonn
86af7cd7c9 ublox: query USBCONF for applicable devices
The TOBY L2 series of modems presents a number of different
configurations with different throughtput characteristics.  These
configurations are packaged up as USB profiles; moreover, changing the
profile actually changes the USB model ID so this is even more like
selecting a different "device" altogether.  Nonetheless, all we need to
know is which profile is selected in order to set things up correctly
and this can be queried directly.

This patch adds a call to UUSBCONF for applicable modems in order to
query the USB configuration to find out which profile is active.
2022-03-11 15:35:22 +00:00
Jonas Bonn
050332577c ublox: add model flag HAVE_USBCONF
This flag should be set on devices that support multiple USB profiles
and will be used to determine whether or not querying USB profiles is
appropriate/necessary.
2022-03-11 15:35:22 +00:00
Jonas Bonn
339814e429 ublox: query device model
This patch adds a call to CGMM into the modem_enable path in order to
establish the specific device model.  From this device model string, a
model-specific capabilities structure can be selected.
2022-03-11 15:35:22 +00:00
Jonas Bonn
278d7236c9 ublox: create model data structures
This sets up some device model data structures and adds some helpers for
manipulating them.  These data structures are a first step to trying to
support the large number of devices that ublox produces with a common
driver structure.
2022-03-11 15:35:22 +00:00
Jonas Bonn
15a9ea2977 ublox: make device selection more flexible
Many ublox modems can sit on either the USB bus or talk directly to a
UART.  The udev plugin mostly takes care of figuring out what ports to
talk to and the protocol is common for all devices after that.

This patch simplifies the setup a bit:
i)  There must always be an aux channel for communication with the modem
ii)  The aux channel may be found behind the string Aux for USB modems
or Device for serial modems
iii)  If the Modem string is set, use it; if not set, assume it's not
available.
2022-03-11 15:35:22 +00:00
Jonas Bonn
9910ab1693 atmodem: Remove TOBY_L2 vendor 2022-03-11 15:35:22 +00:00
Jonas Bonn
d5a3613fd4 ublox: drop vendor type for Toby L2 model 2022-03-11 15:35:22 +00:00
Jonas Bonn
d337893b39 atmodem: drop vendor type for Toby L2 model
The 'Toby L2'-specific vendor type is used only to prevent the CMER
command from attempting to set mode '3'.  For all u-blox models, mode
'3' is just an alias for mode '1'.  As such, mode '1' can be used in
place of mode '3', removing the model-specific quirk in favour of a
vendor-specific quirk.

With this change, the L2-specific vendor type is no longer needed.
2022-03-11 15:35:22 +00:00
Jonas Bonn
9ef41fdc2f Fix whitespace weirdness 2022-03-11 15:35:22 +00:00
Anirudh Gargi
c779a8b19d sim: fix segfault in sim atom
While adding the sim pin cache feature, pin_name could cause issue in
cases when sim pin is not there.

log:
ofonod[27810]: drivers/atmodem/sim.c:at_cpin_cb() crsm_pin_cb: READY
ofonod[27810]: src/sim.c:sim_pin_query_cb() sim->pin_type: 0, pin_type: 0
ofonod[27810]: Aborting (signal 11) [./src/ofonod]
ofonod[27810]: ++++++++ backtrace ++++++++
ofonod[27810]: #0  0x7fb7a7586cb0 in /lib/x86_64-linux-gnu/libc.so.6
ofonod[27810]: #1  0x7fb7a7693cd8 in /lib/x86_64-linux-gnu/libc.so.6
ofonod[27810]: #2  0x4d899b in sim_pin_query_cb() at src/sim.c:3174
ofonod[27810]: #3  0x4649e7 in at_cpin_cb() at drivers/atmodem/sim.c:1304
ofonod[27810]: #4  0x4a5d70 in at_chat_finish_command() at gatchat/gatchat.c:462
2022-03-11 15:35:22 +00:00
Denis Kenzior
81c7f886cb ifxmodem: Clean up the previous commit slightly
The if statements were over 80 characters and breaking them up made the
code look a bit uglier.  So refactor the if statements to just figure
out the data path 'n' parameter or return an error.  On success, form
the datapath string and return it.

Also bump the buffer size and use snprintf to be safe(r).
2022-03-11 15:35:22 +00:00
Antara Borwankar
4adac31b51 xmm7modem: data channel setup for xmm7modem
Added the implementation required to setup data channel
in ifxmodem gprs-context driver for xmm7modem vendor
2022-03-11 15:35:22 +00:00
Antara Borwankar
31bebd7ecf gprs-context: Adding get function for inteface
Added definition of get function to get interface value in
gprs-context
2022-03-11 15:35:22 +00:00
Antara Borwankar
f1965b1e2b gprs-context: adding get function for network interface
Added declaration of get function to get network interface
for gprs-context
2022-03-11 15:35:22 +00:00
Philippe De Swert
fed8c5b171 common: Add new NB-IoT technologies
Add lte-cat-m1 and lte-cat-nb1 technology identifiers.
2022-03-11 15:35:22 +00:00
Christophe Ronco
5e1f159ad1 qmi: support sim hotplug
Use card status indication to detect SIM removal and insertions
2022-03-11 15:35:22 +00:00
Antara Borwankar
972aea87e8 xmm7modem: Change in xmm7mode plugin for multiple PDP
Made changes in xmm7modem plugin to allow mutiple PDP context
activation and to assign correct network interface to the
activated PDP context.
2022-03-11 15:35:22 +00:00
Antara Borwankar
f4df805783 udevng: Detect multiple network interfaces for xmm7xxx 2022-03-11 15:35:22 +00:00
Denis Kenzior
1066668a4b gprs: Let gprs_context interface be settable once
This patch allows a driver to set the interface only once, instead of at
every context activation.  The previous way was originally designed for
PPP and RAW_IP based contexts which would have a (potentially)
differently named interface after each context activation due to use of
TUN/TAP.  This also worked for static high-speed interface setups as
well, since these usually had a single interface only.

For devices that support multiple high-speed interfaces it would be
advantageous to have each gprs_context get an interface assignment right
in the modem driver and skip having to setup the interface on every
activation.
2022-03-11 15:35:22 +00:00
Pičugins Arsenijs
c5029eafcf sim800: fix typo in model check code
Fixing a copy-paste error in SIM800 code
that results in a SIM900 modem being
detected as a SIM800 modem.
2022-03-11 15:35:22 +00:00
Nicolas Serafini
6ce1e081a4 qmimodem: Notify when SIM is initialized
Since the commit that introduced the notification API of a SIM inserted
and initialized I can not unlock the SIM card on a WP7607 modem.

The previously mentioned commit: 54d56d763e40bc44c99a9b24aa0477bd373ea085
2022-03-11 15:35:22 +00:00
Pavel Machek
91435c39ed test: better help text for dial-number
Better help text for "dial-number". Without details, user may be
tempted to pass 0|1 (as send-sms uses) or true|false.
2022-03-11 15:35:22 +00:00
Nandini Rebello
531afae6b2 modem: add support to clear cached pins.
If the modem is powered off via D-Bus, clear any cached PINs to make
sure that automatic PIN entry behavior is not activated.
2022-03-11 15:35:22 +00:00
Denis Kenzior
1c8a577a4b sim: Fix memory leaks introduced by sim pin caching 2022-03-11 15:35:22 +00:00
Nandini Rebello
bd175869f4 sim: Sim PIN1 cache upon modem reset/crash
Adding SIM PIN caching feature to oFono. oFono now caches the SIM PIN1
type against the ICCID throughout its lifetime in a link list and
enters implicitly upon modem reset/crash.

Note, that this behavior can violate 3GPP spec 21.111, section 5.3 -
User Data stored in ME if that section is interpreted very strictly.
However, our interpretation is that firmware resets are allowed, based
on historic precedent.  Helps in user experience by not barring out
cellular services unless pin is entered manually.

Handles cases of incorrect pin and sim pin changed externally.
Clear cached PIN incase modem disabled manually and selectively when
sim is removed.

Seperate 'pin_cache_enter_cb' added without dbus calls to handle
implict entering of cached pin.

For now this behavior is applicable to all modems by default.  In the
future it may be needed to make this behavior opt in or otherwise
configurable.
2022-03-11 15:35:22 +00:00
Marcel Holtmann
bcb08afc50 gitignore: unit/test-idmap binary 2022-03-11 15:35:22 +00:00
Slava Monich
eb8bfb57e9 [dbus-access] Added access control entry for SendDataMessage. JB#56657 2022-03-11 17:09:33 +02:00
Slava Monich
871eab499c Housekeeping 2022-03-11 17:09:17 +02:00
Slava Monich
dae12e74a4 Merge pull request #17 from LaakkonenJussi/jb56657
Add support for sending SMS data messages
2022-03-11 17:05:08 +02:00
Jussi Laakkonen
9f486aa91a [sms] Support setting endianess for SMS data messages. JB#56657
This implements support for selecting endianess for the SMS data message
multi-byte parameters. By default big endian is used but little endian
is required in some special protocols. Thus, omitting flag value results
in the "GSM" setting which is the big endian used by default.

This required adding a new sms_datagram_prepare_with_endianess() plugin
API call that is called by the original sms_datagram_prepare() with GSM
encoding.

This affects only the new SendDataMessage D-Bus API. A value 0x02 for
little endian is added to enum ofono_sms_data_flag().
2022-03-09 11:18:08 +02:00
Jussi Laakkonen
b015849e98 [sms] Add support for sending SMS data messages. Fixes JB#56657
This adds a new D-Bus API call "SendDataMessage" to be used for sending
a SMS data message. This is required especially by AML but can be
utilized for other uses as well.

The given message data is defined as a byte array so pre-encoded data
is only supported. Additionally source and destination ports as well as
flags are to be defined for the SMS data message. Flag
OFONO_SMS_DATA_FLAG_DELIVERY_REPORT (0x01) determine the need for
delivery reports. Other flags may be added later on.

This also implements the filter functionality for the SMS data messages.
This can be utilized by the plugins to react to the sent SMS data
messages appropriately.
2022-03-09 11:18:03 +02:00
Slava Monich
6c77fa2ddd Merge pull request #31 from monich/sim_api_ext
Add mechanism for extending ofono_sim_driver API
2022-02-23 20:10:26 +02:00
Slava Monich
09bd3cc5ac [ofono] Add mechanism for extending ofono_sim_driver API
This way struct ofono_sim_driver can be extended without having to
recompile all plugins in the world.
2022-02-23 20:09:47 +02:00
Slava Monich
1758eb3b2a Merge pull request #27 from monich/imei
Add API for querying IMEI from the modem
2022-02-23 19:59:39 +02:00
Slava Monich
faae02c2f4 Merge pull request #32 from LaakkonenJussi/allow_emerg_call_filter
Allow filtering for emergency calls
2022-02-23 19:56:22 +02:00
Jussi Laakkonen
d2abaa7776 [voicecall] Allow filtering for emergency calls. JB#56657
This removes the exceptions made for emergency calls to disallow
filtering of them via plugins. Thus, this allows the plugins to detect
if an emergency call is made and make an action based on it.
2022-02-23 14:36:37 +02:00
Slava Monich
78e83f877c [ofono] Added API for querying IMEI from the modem. JB#56657
ofono_devinfo_get_serial(ofono_modem_get_devinfo(modem))
2022-02-16 17:05:03 +02:00
Slava Monich
2b00591782 Merge pull request #23 from monich/ims
Expose ext_info bits to the plugins
2022-02-12 21:04:56 +02:00
Slava Monich
18b38db35f [ims] Expose ext_info bits to the plugins. JB#57408 2022-02-12 20:59:23 +02:00
62 changed files with 2338 additions and 342 deletions

View File

@@ -1,3 +1,9 @@
ver 1.29:
Fix issue with QMI and SIM initialized notification.
Add support for multiple PDP contexts and xmm7xxx modems.
Add support for handling Dual SIM Single Active feature
Add support for SIM PIN caching feature.
ver 1.28:
Fix issue with SIM initialization and Gemalto modems.

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(ofono, 1.28)
AC_INIT(ofono, 1.29)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)

View File

@@ -16,7 +16,7 @@ Methods dict GetProperties()
changeable. On success a PropertyChanged signal
will be emitted.
Possible Errors: [service].Error.InProgress
Possible Errors: [service].Error.AccessDenied
[service].Error.InvalidArguments
[service].Error.Failed
@@ -27,8 +27,10 @@ Methods dict GetProperties()
initiated successfully. The actual registration state
will be reflected by the 'Registered' property.
Possible Errors: [service].Error.InProgress
Possible Errors: [service].Error.AccessDenied
[service].Error.NotAllowed
[service].Error.NotImplemented
[service].Error.Failed
void Unregister()
@@ -37,8 +39,9 @@ Methods dict GetProperties()
be initiated successfully. The actual unregistration
state will be reflected by the 'Registered' property.
Possible Errors: [service].Error.InProgress
Possible Errors: [service].Error.AccessDenied
[service].Error.NotImplemented
[service].Error.Failed
Signals PropertyChanged(string property, variant value)
@@ -57,3 +60,15 @@ Properties boolean Registered [readonly]
boolean SmsCapable [readonly, optional]
Boolean representing whether SMS-over-IMS is available.
string Registration [readwrite, Sailfish OS specific]
The IMS registration strategy. Valid values are:
"disabled" keep registration off
"enabled" manual registration
"auto" keep registration on
The Register() method, if implemented, will fail
with [service].Error.NotAllowed if the value of
this property is "disabled".

View File

@@ -205,3 +205,15 @@ Properties boolean Present [readonly]
Contains the SIM's ImsPrivateIdentity, read from the
ISIM.
uint32 CardSlotCount [readonly, experimental]
Contains the count of number of SIM card slots available.
uint32 ActiveCardSlot [readwrite, experimental]
Contains the index of the currently active SIM card slot
for dual SIM single active mode.
This property will range from 1 (default) to
CardSlotCount (max) value.

View File

@@ -455,7 +455,6 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data)
FALSE, gprs, NULL);
break;
case OFONO_VENDOR_UBLOX:
case OFONO_VENDOR_UBLOX_TOBY_L2:
g_at_chat_register(gd->chat, "+UREG:", ublox_ureg_notify,
FALSE, gprs, NULL);
g_at_chat_send(gd->chat, "AT+UREG=1", none_prefix,

View File

@@ -1559,12 +1559,12 @@ static void creg_notify(GAtResult *result, gpointer user_data)
option_query_tech_cb, tq, g_free) > 0)
return;
break;
case OFONO_VENDOR_GEMALTO:
if (g_at_chat_send(nd->chat, "AT^SMONI",
smoni_prefix,
gemalto_query_tech_cb, tq, g_free) > 0)
return;
break;
case OFONO_VENDOR_GEMALTO:
if (g_at_chat_send(nd->chat, "AT^SMONI",
smoni_prefix,
gemalto_query_tech_cb, tq, g_free) > 0)
return;
break;
}
g_free(tq);
@@ -1655,8 +1655,11 @@ static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
DBG("");
switch (nd->vendor) {
case OFONO_VENDOR_UBLOX_TOBY_L2:
/* UBX-13002752 R33: TOBY L2 doesn't support mode 2 and 3 */
case OFONO_VENDOR_UBLOX:
/* For all u-blox models, mode 3 is equivalent to mode 1;
* since some models do not support setting modes 2 nor 3
* (see UBX-13002752), we prefer mode 1 for all models.
*/
mode = "1";
break;
default:

View File

@@ -75,6 +75,7 @@ static const char *cuad_prefix[] = { "+CUAD:", NULL };
static const char *ccho_prefix[] = { "+CCHO:", NULL };
static const char *crla_prefix[] = { "+CRLA:", NULL };
static const char *cgla_prefix[] = { "+CGLA:", NULL };
static const char *xcmscsc_prefix[] = { "+XCMSCSC:", NULL};
static const char *none_prefix[] = { NULL };
static void append_file_path(char *buf, const unsigned char *path,
@@ -1160,6 +1161,7 @@ static void at_pin_retries_query(struct ofono_sim *sim,
DBG("");
switch (sd->vendor) {
case OFONO_VENDOR_XMM:
case OFONO_VENDOR_IFX:
if (g_at_chat_send(sd->chat, "AT+XPINCNT", xpincnt_prefix,
xpincnt_cb, cbd, g_free) > 0)
@@ -1221,7 +1223,6 @@ static void at_pin_retries_query(struct ofono_sim *sim,
return;
break;
case OFONO_VENDOR_UBLOX:
case OFONO_VENDOR_UBLOX_TOBY_L2:
if (g_at_chat_send(sd->chat, "AT+UPINCNT", upincnt_prefix,
upincnt_cb, cbd, g_free) > 0)
return;
@@ -1921,6 +1922,83 @@ static void at_logical_access(struct ofono_sim *sim, int session_id,
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
}
static void xcmscsc_query_cb(gboolean ok, GAtResult *result, gpointer user)
{
struct ofono_sim *sim = user;
struct sim_data *sd = ofono_sim_get_data(sim);
GAtResultIter iter;
int active_slot;
if (!ok)
goto done;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+XCMSCSC:"))
goto done;
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
g_at_result_iter_next_number(&iter, &active_slot);
/* set active SIM slot */
ofono_sim_set_active_card_slot(sim, active_slot + 1);
done:
/* Query supported <fac>s */
g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
at_clck_query_cb, sim, NULL);
}
static void at_xcmscsc_test_cb(gboolean ok, GAtResult *result, gpointer user)
{
struct ofono_sim *sim = user;
struct sim_data *sd = ofono_sim_get_data(sim);
GAtResultIter iter;
int card_slot_count;
if (!ok)
goto done;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+XCMSCSC:"))
goto done;
g_at_result_iter_skip_next(&iter);
g_at_result_iter_skip_next(&iter);
if (!g_at_result_iter_open_list(&iter))
goto done;
g_at_result_iter_skip_next(&iter);
if (!g_at_result_iter_next_number(&iter, &card_slot_count))
goto done;
/* Set num slots */
ofono_sim_set_card_slot_count(sim, card_slot_count + 1);
/*
* enable reporting of MSIM remap status information
* and enable automatic acceptance of MSIM Remap
* acknowledgement
*/
g_at_chat_send(sd->chat, "AT+XCMSRS=2", none_prefix,
NULL, NULL, NULL);
/* Query active card slot */
g_at_chat_send(sd->chat, "AT+XCMSCSC?", xcmscsc_prefix,
xcmscsc_query_cb, sim, NULL);
return;
done:
/* Query supported <fac>s */
g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
at_clck_query_cb, sim, NULL);
}
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
void *data)
{
@@ -1939,6 +2017,10 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
if (at_clck_cpwd_fac[i])
sd->passwd_type_mask |= (1 << i);
if (sd->vendor == OFONO_VENDOR_XMM)
return g_at_chat_send(sd->chat, "AT+XCMSCSC=?", xcmscsc_prefix,
at_xcmscsc_test_cb, sim, NULL) ? 0 : -1;
/* Query supported <fac>s */
return g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
at_clck_query_cb, sim, NULL) ? 0 : -1;
@@ -1958,6 +2040,46 @@ static void at_sim_remove(struct ofono_sim *sim)
g_free(sd);
}
static void xcmscsc_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_set_active_card_slot_cb_t cb = cbd->cb;
struct ofono_error error;
decode_at_error(&error, g_at_result_final_response(result));
if (cb)
cb(&error, cbd->data);
}
static void at_set_active_card_slot(struct ofono_sim *sim, unsigned int index,
ofono_sim_set_active_card_slot_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char cmd[43];
if (sd->vendor != OFONO_VENDOR_XMM) {
struct ofono_error error;
error.type = OFONO_ERROR_TYPE_CME;
error.error = 4;
cb(&error, data);
return;
}
/* Enable single SIM mode for indicated card slot id */
snprintf(cmd, sizeof(cmd), "AT+XCMSCSC=1,0,%u,1", index);
if (g_at_chat_send(sd->chat, cmd, none_prefix, xcmscsc_cb,
cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
static const struct ofono_sim_driver driver = {
.name = "atmodem",
.probe = at_sim_probe,
@@ -1983,7 +2105,8 @@ static const struct ofono_sim_driver driver = {
.session_read_binary = at_session_read_binary,
.session_read_record = at_session_read_record,
.session_read_info = at_session_read_info,
.logical_access = at_logical_access
.logical_access = at_logical_access,
.set_active_card_slot = at_set_active_card_slot
};
static const struct ofono_sim_driver driver_noef = {

View File

@@ -46,7 +46,6 @@ enum ofono_vendor {
OFONO_VENDOR_QUECTEL,
OFONO_VENDOR_QUECTEL_M95,
OFONO_VENDOR_UBLOX,
OFONO_VENDOR_UBLOX_TOBY_L2,
OFONO_VENDOR_XMM,
OFONO_VENDOR_GEMALTO,
};

View File

@@ -260,6 +260,45 @@ error:
failed_setup(gc, NULL, TRUE);
}
static void cgdata_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_gprs_context *gc = user_data;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
DBG("ok %d", ok);
if (!ok) {
ofono_error("Failed to establish session");
failed_setup(gc, result, TRUE);
return;
}
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
}
static const char *get_datapath(struct ofono_modem *modem,
const char *interface)
{
static char datapath[256];
char n;
if (!strcmp(interface,
ofono_modem_get_string(modem, "NetworkInterface")))
n = '0';
else if (!strcmp(interface,
ofono_modem_get_string(modem, "NetworkInterface2")))
n = '1';
else if (!strcmp(interface,
ofono_modem_get_string(modem, "NetworkInterface3")))
n = '2';
else
return NULL;
snprintf(datapath, sizeof(datapath), "%s%c",
ofono_modem_get_string(modem, "DataPath"), n);
return datapath;
}
static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_gprs_context *gc = user_data;
@@ -269,8 +308,11 @@ static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
const char *laddrnetmask = NULL;
const char *gw = NULL;
const char *interface;
const char *dns[3];
const char *ctrlpath;
const char *datapath;
char buf[512];
const char *interface;
DBG("ok %d", ok);
@@ -327,9 +369,10 @@ static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
DBG("DNS2: %s\n", gcd->dns2);
DBG("Gateway: %s\n", gcd->gateway);
interface = ofono_modem_get_string(modem, "NetworkInterface");
ctrlpath = ofono_modem_get_string(modem, "CtrlPath");
interface = ofono_gprs_context_get_interface(gc);
datapath = get_datapath(modem, interface);
ofono_gprs_context_set_interface(gc, interface);
ofono_gprs_context_set_ipv4_address(gc, gcd->address, TRUE);
if (gcd->netmask[0])
@@ -340,7 +383,17 @@ static void cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
snprintf(buf, sizeof(buf), "AT+XDATACHANNEL=1,1,\"%s\",\"%s\",2,%u",
ctrlpath, datapath, gcd->active_context);
g_at_chat_send(gcd->chat, buf, none_prefix, NULL, NULL, NULL);
snprintf(buf, sizeof(buf), "AT+CGDATA=\"M-RAW_IP\",%u",
gcd->active_context);
if (g_at_chat_send(gcd->chat, buf, none_prefix, cgdata_cb,
gc, NULL) > 0)
return;
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
}
static void ifx_read_settings(struct ofono_gprs_context *gc)

View File

@@ -250,6 +250,7 @@ static void process_uim_state(struct ofono_sim *sim, uint8_t state)
switch (state) {
case QMI_DMS_UIM_STATE_INIT_COMPLETE:
ofono_sim_inserted_notify(sim, TRUE);
ofono_sim_initialized_notify(sim);
break;
case QMI_DMS_UIM_STATE_INIT_FAILED:
case QMI_DMS_UIM_STATE_NOT_PRESENT:

View File

@@ -524,7 +524,7 @@ static bool get_card_status(const struct qmi_uim_slot_info *slot,
return need_retry;
}
static enum get_card_status_result handle_get_card_status_result(
static enum get_card_status_result handle_get_card_status_data(
struct qmi_result *result, struct sim_status *sim_stat)
{
const void *ptr;
@@ -533,9 +533,6 @@ static enum get_card_status_result handle_get_card_status_result(
uint8_t i;
enum get_card_status_result res = GET_CARD_STATUS_RESULT_ERROR;
if (qmi_result_set_error(result, NULL))
goto done;
ptr = qmi_result_get(result, QMI_UIM_RESULT_CARD_STATUS, &len);
if (!ptr)
goto done;
@@ -578,6 +575,15 @@ done:
return res;
}
static enum get_card_status_result handle_get_card_status_result(
struct qmi_result *result, struct sim_status *sim_stat)
{
if (qmi_result_set_error(result, NULL))
return GET_CARD_STATUS_RESULT_ERROR;
return handle_get_card_status_data(result, sim_stat);
}
static gboolean query_passwd_state_retry(gpointer userdata)
{
struct cb_data *cbd = userdata;
@@ -789,6 +795,34 @@ static void get_card_status_cb(struct qmi_result *result, void *user_data)
case 0x00: /* Absent */
case 0x02: /* Error */
break;
case 0x01: /* Present */
ofono_sim_inserted_notify(sim, TRUE);
ofono_sim_initialized_notify(sim);
break;
}
}
static void card_status_notify(struct qmi_result *result, void *user_data)
{
struct ofono_sim *sim = user_data;
struct sim_data *data = ofono_sim_get_data(sim);
struct sim_status sim_stat;
DBG("");
if (handle_get_card_status_data(result, &sim_stat) !=
GET_CARD_STATUS_RESULT_OK) {
data->app_type = 0; /* Unknown */
sim_stat.card_state = 0x00; /* Absent */
} else {
data->app_type = sim_stat.app_type;
}
switch (sim_stat.card_state) {
case 0x00: /* Absent */
case 0x02: /* Error */
ofono_sim_inserted_notify(sim, FALSE);
break;
case 0x01: /* Present */
ofono_sim_inserted_notify(sim, TRUE);
break;
@@ -810,6 +844,9 @@ static void event_registration_cb(struct qmi_result *result, void *user_data)
goto error;
DBG("event mask 0x%04x", data->event_mask);
if (data->event_mask & 0x0001)
qmi_service_register(data->uim, QMI_UIM_GET_CARD_STATUS_EVENT,
card_status_notify, sim, NULL);
if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
get_card_status_cb, sim, NULL) > 0)

View File

@@ -29,7 +29,7 @@
#define QMI_UIM_EVENT_REGISTRATION 46 /* Register for indications */
#define QMI_UIM_GET_CARD_STATUS 47 /* Get card status */
#define QMI_UIM_GET_CARD_STATUS_EVENT 50 /* Card status indication */
/* Register for indications */
#define QMI_UIM_PARAM_EVENT_MASK 0x01 /* uint32 */

View File

@@ -43,12 +43,20 @@
static const char *none_prefix[] = { NULL };
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
static const char *uipaddr_prefix[] = { "+UIPADDR:", NULL };
static const char *ubmconf_prefix[] = { "+UBMCONF:", NULL };
enum netmode {
NETWORKING_MODE_ROUTER,
NETWORKING_MODE_BRIDGE,
};
struct gprs_context_data {
const struct ublox_model *model;
GAtChat *chat;
unsigned int active_context;
ofono_gprs_context_cb_t cb;
void *cb_data;
enum netmode networking_mode;
};
static void uipaddr_cb(gboolean ok, GAtResult *result, gpointer user_data)
@@ -227,6 +235,14 @@ static void ublox_read_settings(struct ofono_gprs_context *gc)
{
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
if (gcd->networking_mode == NETWORKING_MODE_ROUTER) {
/* Use DHCP */
set_gprs_context_interface(gc);
ofono_gprs_context_set_ipv4_address(gc, NULL, 0);
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
return;
}
if (ublox_send_cgcontrdp(gc) < 0)
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
}
@@ -461,8 +477,44 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
gcd->active_context = 0;
}
static void at_ubmconf_read_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct ofono_gprs_context *gc = user_data;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
GAtResultIter iter;
int mode;
if (!ok)
goto error;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+UBMCONF:"))
goto error;
if (!g_at_result_iter_next_number(&iter, &mode))
goto error;
switch (mode) {
case 1:
gcd->networking_mode = NETWORKING_MODE_ROUTER;
break;
case 2:
gcd->networking_mode = NETWORKING_MODE_BRIDGE;
break;
default:
goto error;
}
return;
error:
ofono_error("AT+UBMCONF? failed; assuming router mode");
gcd->networking_mode = NETWORKING_MODE_ROUTER;
}
static int ublox_gprs_context_probe(struct ofono_gprs_context *gc,
unsigned int vendor, void *data)
unsigned int model_id, void *data)
{
GAtChat *chat = data;
struct gprs_context_data *gcd;
@@ -473,10 +525,23 @@ static int ublox_gprs_context_probe(struct ofono_gprs_context *gc,
if (gcd == NULL)
return -ENOMEM;
gcd->model = ublox_model_from_id(model_id);
if (!gcd->model)
return -EINVAL;
gcd->chat = g_at_chat_clone(chat);
ofono_gprs_context_set_data(gc, gcd);
if (ublox_is_toby_l2(gcd->model)) {
g_at_chat_send(chat, "AT+UBMCONF?", ubmconf_prefix,
at_ubmconf_read_cb, gc, NULL);
} else if (ublox_is_toby_l4(gcd->model)) {
gcd->networking_mode = NETWORKING_MODE_ROUTER;
} else {
gcd->networking_mode = NETWORKING_MODE_ROUTER;
}
g_at_chat_register(chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
return 0;

View File

@@ -39,24 +39,85 @@
#include "ubloxmodem.h"
static const char *ucgdflt_prefix[] = { "+UCGDFLT:", NULL };
static const char *none_prefix[] = { NULL };
struct lte_driver_data {
GAtChat *chat;
const struct ublox_model *model;
struct ofono_lte_default_attach_info pending_info;
};
static void ucgdflt_cb(gboolean ok, GAtResult *result, gpointer user_data)
static void at_lte_set_auth_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_lte_cb_t cb = cbd->cb;
struct ofono_error error;
DBG("ok %d", ok);
decode_at_error(&error, g_at_result_final_response(result));
cb(&error, cbd->data);
}
static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_lte_cb_t cb = cbd->cb;
void *data = cbd->data;
struct lte_driver_data *ldd = cbd->user;
struct ofono_error error;
char buf[32 + OFONO_GPRS_MAX_USERNAME_LENGTH +
OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
enum ofono_gprs_auth_method auth_method;
int cid;
if (!ok) {
decode_at_error(&error, g_at_result_final_response(result));
cb(&error, data);
return;
}
if (ublox_is_toby_l2(ldd->model)) {
/* If CGDCONT has already been used to set up cid 4 then
* the EPS default bearer will be configured from another
* cid (see documentation for how this is selected). Avoid
* doing so as this assumes as much...
*/
cid = 4;
} else if (ublox_is_toby_l4(ldd->model)) {
cid = 1;
} else {
ofono_error("Unknown model; "
"unable to determine EPS default bearer CID");
goto out;
}
auth_method = ldd->pending_info.auth_method;
/* change the authentication method if the parameters are invalid */
if (!*ldd->pending_info.username || !*ldd->pending_info.password)
auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
/* In contrast to CGAUTH, all four parameters are _required_ here;
* if auth type is NONE then username and password must be set to
* empty strings.
*/
sprintf(buf, "AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"",
cid,
at_util_gprs_auth_method_to_auth_prot(auth_method),
ldd->pending_info.username,
ldd->pending_info.password);
cbd = cb_data_ref(cbd);
if (g_at_chat_send(ldd->chat, buf, none_prefix,
at_lte_set_auth_cb, cbd, cb_data_unref) > 0)
return;
out:
cb_data_unref(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
static void ublox_lte_set_default_attach_info(const struct ofono_lte *lte,
const struct ofono_lte_default_attach_info *info,
ofono_lte_cb_t cb, void *data)
@@ -67,17 +128,32 @@ static void ublox_lte_set_default_attach_info(const struct ofono_lte *lte,
DBG("LTE config with APN: %s", info->apn);
if (strlen(info->apn) > 0)
snprintf(buf, sizeof(buf), "AT+UCGDFLT=0,\"IP\",\"%s\"",
info->apn);
else
snprintf(buf, sizeof(buf), "AT+UCGDFLT=0");
cbd->user = ldd;
memcpy(&ldd->pending_info, info, sizeof(ldd->pending_info));
/* We can't do much in case of failure so don't check response. */
if (g_at_chat_send(ldd->chat, buf, ucgdflt_prefix,
ucgdflt_cb, cbd, g_free) > 0)
if (ublox_is_toby_l2(ldd->model)) {
if (strlen(info->apn) > 0)
snprintf(buf, sizeof(buf), "AT+UCGDFLT=0,%s,\"%s\"",
at_util_gprs_proto_to_pdp_type(info->proto),
info->apn);
else
snprintf(buf, sizeof(buf), "AT+UCGDFLT=0");
} else if (ublox_is_toby_l4(ldd->model)) {
if (strlen(info->apn) > 0)
snprintf(buf, sizeof(buf), "AT+CGDCONT=1,%s,\"%s\"",
at_util_gprs_proto_to_pdp_type(info->proto),
info->apn);
else
snprintf(buf, sizeof(buf), "AT+CGDCONT=1");
}
if (g_at_chat_send(ldd->chat, buf, none_prefix,
at_lte_set_default_attach_info_cb,
cbd, cb_data_unref) > 0)
return;
cb_data_unref(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
@@ -91,7 +167,7 @@ static gboolean lte_delayed_register(gpointer user_data)
}
static int ublox_lte_probe(struct ofono_lte *lte,
unsigned int vendor, void *data)
unsigned int model_id, void *data)
{
GAtChat *chat = data;
struct lte_driver_data *ldd;
@@ -103,6 +179,7 @@ static int ublox_lte_probe(struct ofono_lte *lte,
return -ENOMEM;
ldd->chat = g_at_chat_clone(chat);
ldd->model = ublox_model_from_id(model_id);
ofono_lte_set_data(lte, ldd);

View File

@@ -23,6 +23,8 @@
#include <config.h>
#endif
#include <string.h>
#include <glib.h>
#include <gatchat.h>
@@ -33,6 +35,83 @@
#include "ubloxmodem.h"
const struct ublox_model ublox_models[] = {
{
.name = "SARA-G270",
},
/* TOBY L2 series */
{
.name = "TOBY-L200",
.flags = UBLOX_F_TOBY_L2|UBLOX_F_HAVE_USBCONF,
},
{
.name = "TOBY-L201",
.flags = UBLOX_F_TOBY_L2|UBLOX_F_HAVE_USBCONF,
},
{
.name = "TOBY-L210",
.flags = UBLOX_F_TOBY_L2|UBLOX_F_HAVE_USBCONF,
},
{
.name = "TOBY-L220",
.flags = UBLOX_F_TOBY_L2|UBLOX_F_HAVE_USBCONF,
},
{
.name = "TOBY-L280",
.flags = UBLOX_F_TOBY_L2|UBLOX_F_HAVE_USBCONF,
},
/* TOBY L4 series */
{
.name = "TOBY-L4006",
.flags = UBLOX_F_TOBY_L4,
},
{
.name = "TOBY-L4106",
.flags = UBLOX_F_TOBY_L4,
},
{
.name = "TOBY-L4206",
.flags = UBLOX_F_TOBY_L4,
},
{
.name = "TOBY-L4906",
.flags = UBLOX_F_TOBY_L4,
},
{ /* sentinel */ },
};
const struct ublox_model *ublox_model_from_name(const char *name)
{
const struct ublox_model *m;
for (m = ublox_models; m->name; m++) {
if (!strcmp(name, m->name))
return m;
}
return NULL;
}
const struct ublox_model *ublox_model_from_id(int id)
{
return ublox_models + id;
}
int ublox_model_to_id(const struct ublox_model *model)
{
return model - ublox_models;
}
int ublox_is_toby_l2(const struct ublox_model *model)
{
return model->flags & UBLOX_F_TOBY_L2;
}
int ublox_is_toby_l4(const struct ublox_model *model)
{
return model->flags & UBLOX_F_TOBY_L4;
}
static int ubloxmodem_init(void)
{
ublox_gprs_context_init();

View File

@@ -23,6 +23,23 @@
#define UBLOXMODEM "ubloxmodem"
enum ublox_flags {
UBLOX_F_TOBY_L2 = (1 << 0),
UBLOX_F_TOBY_L4 = (1 << 1),
UBLOX_F_HAVE_USBCONF = (1 << 2),
};
struct ublox_model {
char *name;
int flags;
};
const struct ublox_model *ublox_model_from_name(const char *name);
const struct ublox_model *ublox_model_from_id(int id);
int ublox_model_to_id(const struct ublox_model *model);
int ublox_is_toby_l2(const struct ublox_model *model);
int ublox_is_toby_l4(const struct ublox_model *model);
extern void ublox_gprs_context_init(void);
extern void ublox_gprs_context_exit(void);

View File

@@ -23,14 +23,17 @@ extern "C" {
#endif
#include <ofono/types.h>
#include <stdint.h>
enum ofono_cell_type {
OFONO_CELL_TYPE_GSM,
OFONO_CELL_TYPE_WCDMA,
OFONO_CELL_TYPE_LTE
OFONO_CELL_TYPE_LTE,
OFONO_CELL_TYPE_NR /* Since 1.29+git8 */
};
#define OFONO_CELL_INVALID_VALUE (INT_MAX)
#define OFONO_CELL_INVALID_VALUE_INT64 (INT64_MAX)
struct ofono_cell_info_gsm {
int mcc; /* Mobile Country Code (0..999) */
@@ -70,6 +73,22 @@ struct ofono_cell_info_lte {
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
};
/* Since 1.29+git8 */
struct ofono_cell_info_nr {
int mcc; /* Mobile Country Code (0..999) */
int mnc; /* Mobile Network Code (0..999) */
int64_t nci; /* NR Cell Identity */
int pci; /* Physical cell id (0..1007) */
int tac; /* Tracking area code */
int nrarfcn; /* 22-bit NR Absolute RC Channel Number */
int ssRsrp; /* SS Reference Signal Receive Power TS 38.215 */
int ssRsrq; /* SS Reference Signal Receive Quality TS 38.215 and 38.133 */
int ssSinr; /* SS Reference Signal-to-Noise Ratio TS 38.215 and 38.133*/
int csiRsrp; /* CSI Reference Signal Receive Power TS 38.215 */
int csiRsrq; /* CSI Reference Signal Receive Quality TS 38.215 */
int csiSinr; /* CSI Reference Signal-to-Noise Ratio TS 38.215 and 38.133 */
};
typedef struct ofono_cell {
enum ofono_cell_type type;
ofono_bool_t registered;
@@ -77,6 +96,7 @@ typedef struct ofono_cell {
struct ofono_cell_info_gsm gsm;
struct ofono_cell_info_wcdma wcdma;
struct ofono_cell_info_lte lte;
struct ofono_cell_info_nr nr; /* Since 1.29+git8 */
} info;
} *ofono_cell_ptr;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2019-2021 Jolla Ltd.
* Copyright (C) 2019-2022 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
@@ -41,6 +41,8 @@ enum ofono_dbus_access_intf {
OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS, /* org.ofono.RadioSettings */
OFONO_DBUS_ACCESS_INTF_STK, /* org.ofono.SimToolkit */
OFONO_DBUS_ACCESS_INTF_OEMRAW, /* org.ofono.OemRaw */
/* Since 1.29+git3 */
OFONO_DBUS_ACCESS_INTF_IMS, /* org.ofono.IpMultimediaSystem */
OFONO_DBUS_ACCESS_INTF_COUNT
};
@@ -53,6 +55,7 @@ enum ofono_dbus_access_message_method {
/* OFONO_DBUS_ACCESS_INTF_MESSAGEMGR */
enum ofono_dbus_access_messagemgr_method {
OFONO_DBUS_ACCESS_MESSAGEMGR_SEND_MESSAGE,
OFONO_DBUS_ACCESS_MESSAGEMGR_SEND_DATA_MESSAGE, /* Since 1.28+git5 */
OFONO_DBUS_ACCESS_MESSAGEMGR_METHOD_COUNT
};
@@ -131,6 +134,15 @@ enum ofono_dbus_access_oemraw_method {
OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_IMS */
enum ofono_dbus_access_ims_method {
/* Since 1.29+git3 */
OFONO_DBUS_ACCESS_IMS_SET_PROPERTY,
OFONO_DBUS_ACCESS_IMS_REGISTER,
OFONO_DBUS_ACCESS_IMS_UNREGISTER,
OFONO_DBUS_ACCESS_IMS_METHOD_COUNT
};
#define OFONO_DBUS_ACCESS_PRIORITY_LOW (-100)
#define OFONO_DBUS_ACCESS_PRIORITY_DEFAULT (0)
#define OFONO_DBUS_ACCESS_PRIORITY_HIGH (100)
@@ -158,7 +170,7 @@ 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 */
/* Since 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);

View File

@@ -3,6 +3,7 @@
* oFono - Open Telephony stack for Linux
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2022 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
@@ -65,6 +66,9 @@ void *ofono_devinfo_get_data(struct ofono_devinfo *info);
struct ofono_modem *ofono_devinfo_get_modem(struct ofono_devinfo *info);
/* Since 1.28+git4 */
const char *ofono_devinfo_get_serial(struct ofono_devinfo *info);
#ifdef __cplusplus
}
#endif

View File

@@ -93,6 +93,8 @@ void ofono_gprs_context_set_type(struct ofono_gprs_context *gc,
enum ofono_gprs_context_type ofono_gprs_context_get_type(
struct ofono_gprs_context *gc);
const char *ofono_gprs_context_get_interface(struct ofono_gprs_context *gc);
void ofono_gprs_context_set_interface(struct ofono_gprs_context *gc,
const char *interface);

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. All rights reserved.
* Copyright (C) 2022 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
@@ -30,6 +31,10 @@ extern "C" {
struct ofono_ims;
/* ext_info bits */
#define OFONO_IMS_VOICE_CAPABLE 0x1
#define OFONO_IMS_SMS_CAPABLE 0x4
typedef void (*ofono_ims_register_cb_t)(const struct ofono_error *error,
void *data);
typedef void (*ofono_ims_status_cb_t)(const struct ofono_error *error,

View File

@@ -3,7 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 Jolla Ltd.
* Copyright (C) 2015-2022 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
@@ -29,6 +29,7 @@ extern "C" {
#include <ofono/types.h>
struct ofono_devinfo;
struct ofono_modem;
struct ofono_gprs;
struct ofono_sim;
@@ -92,7 +93,9 @@ 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 */
(struct ofono_modem *modem); /* Since 1.24+git2 */
struct ofono_devinfo *ofono_modem_get_devinfo
(struct ofono_modem *modem); /* Since 1.28+git4 */
void ofono_modem_set_data(struct ofono_modem *modem, void *data);
void *ofono_modem_get_data(struct ofono_modem *modem);

View File

@@ -34,6 +34,7 @@ enum ofono_radio_access_mode {
OFONO_RADIO_ACCESS_MODE_GSM = 0x1,
OFONO_RADIO_ACCESS_MODE_UMTS = 0x2,
OFONO_RADIO_ACCESS_MODE_LTE = 0x4,
OFONO_RADIO_ACCESS_MODE_NR = 0x8, /* Since 1.29+git8 */
};
enum ofono_radio_band_gsm {

View File

@@ -3,7 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 Jolla Ltd.
* Copyright (C) 2015-2022 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
@@ -138,6 +138,10 @@ typedef void (*ofono_sim_close_channel_cb_t)(const struct ofono_error *error,
typedef void (*ofono_sim_logical_access_cb_t)(const struct ofono_error *error,
const unsigned char *resp, unsigned int len, void *data);
typedef void (*ofono_sim_set_active_card_slot_cb_t)(
const struct ofono_error *error,
void *data);
struct ofono_sim_driver {
const char *name;
int (*probe)(struct ofono_sim *sim, unsigned int vendor, void *data);
@@ -211,15 +215,23 @@ 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 */
/* API version 1 (since 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);
/* API version 2 (since 1.29+git1) */
void (*set_active_card_slot)(struct ofono_sim *sim, unsigned int index,
ofono_sim_set_active_card_slot_cb_t cb, void *data);
};
int ofono_sim_driver_register(const struct ofono_sim_driver *d);
void ofono_sim_driver_unregister(const struct ofono_sim_driver *d);
#define OFONO_SIM_DRIVER_API_VERSION 2
#define ofono_sim_driver_register(d) /* Since 1.28+git4 */ \
ofono_sim_driver_register_version(d, OFONO_SIM_DRIVER_API_VERSION)
int ofono_sim_driver_register_version(const struct ofono_sim_driver *d, int v);
struct ofono_sim *ofono_sim_create(struct ofono_modem *modem,
unsigned int vendor,
const char *driver, void *data);
@@ -229,6 +241,9 @@ void ofono_sim_remove(struct ofono_sim *sim);
void ofono_sim_set_data(struct ofono_sim *sim, void *data);
void *ofono_sim_get_data(struct ofono_sim *sim);
void ofono_sim_set_card_slot_count(struct ofono_sim *sim, unsigned int val);
void ofono_sim_set_active_card_slot(struct ofono_sim *sim,
unsigned int val);
const char *ofono_sim_get_imsi(struct ofono_sim *sim);
const char *ofono_sim_get_mcc(struct ofono_sim *sim);
@@ -241,8 +256,8 @@ 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 */
void ofono_sim_refresh_full(struct ofono_sim *sim); /* Since 1.24+git2 */
enum ofono_sim_password_type ofono_sim_puk2pin( /* Since 1.24+git2 */
enum ofono_sim_password_type type);
unsigned int ofono_sim_add_state_watch(struct ofono_sim *sim,

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2022 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
@@ -60,6 +61,11 @@ struct ofono_sms_driver {
ofono_sms_bearer_set_cb_t, void *data);
};
enum ofono_sms_data_flag {
OFONO_SMS_DATA_FLAG_DELIVERY_REPORT = 0x01,
OFONO_SMS_DATA_FLAG_USE_LITTLE_ENDIAN = 0x02
}; /* Since 1.28+git5 */
void ofono_sms_deliver_notify(struct ofono_sms *sms, const unsigned char *pdu,
int len, int tpdu_len);
void ofono_sms_status_notify(struct ofono_sms *sms, const unsigned char *pdu,

View File

@@ -55,7 +55,13 @@ enum ofono_access_technology {
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA = 4,
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSUPA = 5,
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA = 6,
OFONO_ACCESS_TECHNOLOGY_EUTRAN = 7
OFONO_ACCESS_TECHNOLOGY_EUTRAN = 7,
OFONO_ACCESS_TECHNOLOGY_NB_IOT_M1 = 8,
OFONO_ACCESS_TECHNOLOGY_NB_IOT_NB1 = 9,
OFONO_ACCESS_TECHNOLOGY_EUTRA_5GCN = 10, /* Since 1.29+git8 */
OFONO_ACCESS_TECHNOLOGY_NR_5GCN = 11, /* Since 1.29+git8 */
OFONO_ACCESS_TECHNOLOGY_NG_RAN = 12, /* Since 1.29+git8 */
OFONO_ACCESS_TECHNOLOGY_EUTRA_NR = 13, /* Since 1.29+git8 */
};
/* 27.007 Section 6.2 */

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017-2021 Jolla Ltd.
* Copyright (C) 2017-2022 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
@@ -36,13 +36,15 @@ struct ofono_watch {
const char *spn;
/* OFONO_ATOM_TYPE_NETREG */
struct ofono_netreg *netreg;
/* Since mer/1.21+git47 */
/* Since 1.21+git47 */
enum ofono_netreg_status reg_status;
const char *reg_mcc;
const char *reg_mnc;
const char *reg_name;
/* OFONO_ATOM_TYPE_GPRS */
struct ofono_gprs *gprs;
/* Since 1.29+git3 */
enum ofono_access_technology reg_tech;
};
typedef void (*ofono_watch_cb_t)(struct ofono_watch *w, void *user_data);
@@ -78,7 +80,7 @@ void ofono_watch_remove_handlers(struct ofono_watch *w, unsigned long *ids,
#define ofono_watch_remove_all_handlers(w,ids) \
ofono_watch_remove_handlers(w, ids, sizeof(ids)/sizeof((ids)[0]))
/* Since mer/1.21+git47 */
/* Since 1.21+git47 */
unsigned long ofono_watch_add_reg_status_changed_handler(struct ofono_watch *w,
ofono_watch_cb_t cb, void *user_data);
unsigned long ofono_watch_add_reg_mcc_changed_handler(struct ofono_watch *w,
@@ -93,6 +95,10 @@ unsigned long ofono_watch_add_gprs_settings_changed_handler
(struct ofono_watch *watch, ofono_watch_gprs_settings_cb_t cb,
void *user_data);
/* Since 1.29+git3 */
unsigned long ofono_watch_add_reg_tech_changed_handler(struct ofono_watch *w,
ofono_watch_cb_t cb, void *user_data);
#endif /* OFONO_WATCH_H */
/*

View File

@@ -2,6 +2,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2011 Intel Corporation. All rights reserved.
* Copyright (C) 2018-2022 Jolla Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -52,6 +53,11 @@ typedef struct GAtResult GAtResult;
#define HFP_AG_DRIVER "hfp-ag-driver"
struct watch_fd {
guint id;
int fd;
};
static gboolean hfp_ag_enabled;
static guint service_watch_id;
static guint modemwatch_id;
@@ -145,11 +151,12 @@ static struct ofono_handsfree_card_driver hfp_ag_driver = {
static void connection_destroy(gpointer data)
{
int fd = GPOINTER_TO_INT(data);
struct watch_fd *watch = data;
DBG("fd %d", fd);
DBG("fd %d", watch->fd);
close(fd);
g_source_remove(watch->id);
g_free(watch);
}
static gboolean io_hup_cb(GIOChannel *io, GIOCondition cond, gpointer data)
@@ -169,7 +176,8 @@ static DBusMessage *profile_new_connection(DBusConnection *conn,
DBusMessageIter entry;
const char *device;
GIOChannel *io;
int fd, fd_dup;
int fd;
struct watch_fd *watch;
struct sockaddr_rc saddr;
socklen_t optlen;
struct ofono_emulator *em;
@@ -252,10 +260,12 @@ static DBusMessage *profile_new_connection(DBusConnection *conn,
emulator = em;
ofono_emulator_register(em, fd);
fd_dup = dup(fd);
io = g_io_channel_unix_new(fd_dup);
g_io_add_watch_full(io, G_PRIORITY_DEFAULT, G_IO_HUP, io_hup_cb,
g_strdup(device), g_free);
watch = g_new(struct watch_fd, 1);
watch->fd = dup(fd);
io = g_io_channel_unix_new(watch->fd);
g_io_channel_set_close_on_unref(io, TRUE);
watch->id = g_io_add_watch_full(io, G_PRIORITY_DEFAULT, G_IO_HUP,
io_hup_cb, g_strdup(device), g_free);
g_io_channel_unref(io);
card = ofono_handsfree_card_create(0,
@@ -269,8 +279,7 @@ static DBusMessage *profile_new_connection(DBusConnection *conn,
ofono_emulator_set_handsfree_card(em, card);
g_hash_table_insert(connection_hash, g_strdup(device),
GINT_TO_POINTER(fd_dup));
g_hash_table_insert(connection_hash, g_strdup(device), watch);
return dbus_message_new_method_return(msg);
@@ -304,7 +313,7 @@ static DBusMessage *profile_disconnection(DBusConnection *conn,
{
DBusMessageIter iter;
const char *device;
gpointer fd;
struct watch_fd *watch;
DBG("Profile handler RequestDisconnection");
@@ -318,11 +327,11 @@ static DBusMessage *profile_disconnection(DBusConnection *conn,
DBG("%s", device);
fd = g_hash_table_lookup(connection_hash, device);
if (fd == NULL)
watch = g_hash_table_lookup(connection_hash, device);
if (watch == NULL)
goto invalid;
shutdown(GPOINTER_TO_INT(fd), SHUT_RDWR);
shutdown(watch->fd, SHUT_RDWR);
g_hash_table_remove(connection_hash, device);

View File

@@ -115,7 +115,7 @@ static void check_model(gboolean ok, GAtResult *result, gpointer user_data)
if (strstr(model, "SIM800"))
data->modem_type = SIM800;
else if (strstr(model, "SIM900"))
data->modem_type = SIM800;
data->modem_type = SIM900;
else
data->modem_type = SIMCOM_UNKNOWN;
}

View File

@@ -42,23 +42,24 @@
#include <ofono/lte.h>
#include <ofono/voicecall.h>
#include <drivers/atmodem/atutil.h>
#include <drivers/atmodem/vendor.h>
#include <drivers/ubloxmodem/ubloxmodem.h>
static const char *uusbconf_prefix[] = { "+UUSBCONF:", NULL };
static const char *none_prefix[] = { NULL };
enum supported_models {
SARA_G270 = 1102,
TOBYL2_COMPATIBLE_MODE = 1141,
TOBYL2_MEDIUM_THROUGHPUT_MODE = 1143,
TOBYL2_HIGH_THROUGHPUT_MODE = 1146,
enum ublox_device_flags {
UBLOX_DEVICE_F_HIGH_THROUGHPUT_MODE = (1 << 0),
};
struct ublox_data {
GAtChat *modem;
GAtChat *aux;
int model_id;
enum ofono_vendor vendor_family;
const struct ublox_model *model;
int flags;
};
static void ublox_debug(const char *str, void *user_data)
@@ -144,77 +145,151 @@ static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
return;
}
if (data->model_id == TOBYL2_HIGH_THROUGHPUT_MODE)
/* use bridged mode until routed mode support is added */
g_at_chat_send(data->aux, "AT+UBMCONF=2", none_prefix,
NULL, NULL, NULL);
ofono_modem_set_powered(modem, TRUE);
}
static void query_usbconf_cb(gboolean ok,
GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
struct ublox_data *data = ofono_modem_get_data(modem);
GAtResultIter iter;
int profile;
if (!ok) {
ofono_error("Unable to query USB configuration");
goto error;
}
g_at_result_iter_init(&iter, result);
retry:
if (!g_at_result_iter_next(&iter, "+UUSBCONF:")) {
ofono_error("Unable to query USB configuration");
goto error;
}
if (!g_at_result_iter_next_number(&iter, &profile))
goto retry;
switch (profile) {
case 0: /* Fairly back compatible */
case 1: /* Fairly back compatible plus audio */
break;
case 2: /* Low/medium throughput */
ofono_error("Medium throughput mode not supported");
goto error;
case 3: /* High throughput mode */
data->flags |= UBLOX_DEVICE_F_HIGH_THROUGHPUT_MODE;
break;
default:
ofono_error("Unexpected USB profile: %d", profile);
goto error;
}
if (g_at_chat_send(data->aux, "AT+CFUN=4", none_prefix,
cfun_enable, modem, NULL))
return;
error:
g_at_chat_unref(data->aux);
data->aux = NULL;
g_at_chat_unref(data->modem);
data->modem = NULL;
ofono_modem_set_powered(modem, FALSE);
}
static void query_model_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
struct ublox_data *data = ofono_modem_get_data(modem);
struct ofono_error error;
const char *model;
const struct ublox_model *m;
decode_at_error(&error, g_at_result_final_response(result));
if (!ok)
goto fail;
if (at_util_parse_attr(result, "", &model) == FALSE) {
ofono_error("Failed to query modem model");
goto fail;
}
m = ublox_model_from_name(model);
if (!m) {
ofono_error("Unrecognized model: %s", model);
goto fail;
}
data->model = m;
DBG("Model: %s", data->model->name);
data->vendor_family = OFONO_VENDOR_UBLOX;
if (data->model->flags & UBLOX_F_HAVE_USBCONF) {
if (g_at_chat_send(data->aux, "AT+UUSBCONF?", uusbconf_prefix,
query_usbconf_cb, modem, NULL))
return;
ofono_error("Unable to query USB configuration");
goto fail;
}
if (g_at_chat_send(data->aux, "AT+CFUN=4", none_prefix,
cfun_enable, modem, NULL))
return;
fail:
g_at_chat_unref(data->aux);
data->aux = NULL;
g_at_chat_unref(data->modem);
data->modem = NULL;
ofono_modem_set_powered(modem, FALSE);
}
static int ublox_enable(struct ofono_modem *modem)
{
struct ublox_data *data = ofono_modem_get_data(modem);
const char *model_str = NULL;
DBG("%p", modem);
model_str = ofono_modem_get_string(modem, "Model");
if (model_str == NULL)
return -EINVAL;
/*
* Toby L2 devices are more complex and special than previously
* supported U-Blox devices. So they need a vendor of their own.
data->aux = open_device(modem, "Aux", "Aux: ");
/* If this is a serial modem then the device may be behind
* the 'Device' attribute instead...
*/
data->model_id = atoi(model_str);
switch (data->model_id) {
case SARA_G270:
data->vendor_family = OFONO_VENDOR_UBLOX;
break;
case TOBYL2_COMPATIBLE_MODE:
case TOBYL2_HIGH_THROUGHPUT_MODE:
data->vendor_family = OFONO_VENDOR_UBLOX_TOBY_L2;
break;
case TOBYL2_MEDIUM_THROUGHPUT_MODE:
DBG("low/medium throughtput profile unsupported");
break;
default:
DBG("unknown ublox model id %d", data->model_id);
return -EINVAL;
if (data->aux == NULL) {
data->aux = open_device(modem, "Device", "Aux: ");
if (data->aux == NULL)
return -EINVAL;
}
data->aux = open_device(modem, "Aux", "Aux: ");
if (data->aux == NULL)
return -EINVAL;
if (data->vendor_family == OFONO_VENDOR_UBLOX) {
data->modem = open_device(modem, "Modem", "Modem: ");
if (data->modem == NULL) {
g_at_chat_unref(data->aux);
data->aux = NULL;
return -EIO;
}
data->modem = open_device(modem, "Modem", "Modem: ");
if (data->modem) {
g_at_chat_set_slave(data->modem, data->aux);
g_at_chat_send(data->modem, "ATE0 +CMEE=1", none_prefix,
NULL, NULL, NULL);
g_at_chat_send(data->modem, "AT&C0", NULL, NULL, NULL, NULL);
}
/* The modem can take a while to wake up if just powered on. */
g_at_chat_set_wakeup_command(data->aux, "AT\r", 1000, 11000);
g_at_chat_send(data->aux, "ATE0 +CMEE=1", none_prefix,
g_at_chat_send(data->aux, "ATE0", none_prefix,
NULL, NULL, NULL);
g_at_chat_send(data->aux, "AT+CMEE=1", none_prefix,
NULL, NULL, NULL);
g_at_chat_send(data->aux, "AT+CFUN=4", none_prefix,
cfun_enable, modem, NULL);
if (g_at_chat_send(data->aux, "AT+CGMM", NULL,
query_model_cb, modem, NULL) > 0)
return -EINPROGRESS;
return -EINPROGRESS;
g_at_chat_unref(data->aux);
data->aux = NULL;
return -EINVAL;
}
static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data)
@@ -308,19 +383,34 @@ static void ublox_post_sim(struct ofono_modem *modem)
struct ofono_gprs *gprs;
struct ofono_gprs_context *gc;
GAtChat *chat = data->modem ? data->modem : data->aux;
const char *driver = data->model_id == TOBYL2_HIGH_THROUGHPUT_MODE ?
"ubloxmodem" : "atmodem";
const char *driver;
/* Toby L2: Create same number of contexts as supported PDP contexts. */
int ncontexts = data->model_id == TOBYL2_HIGH_THROUGHPUT_MODE ? 8 : 1;
int ncontexts = data->flags & UBLOX_DEVICE_F_HIGH_THROUGHPUT_MODE ? 8 : 1;
int variant;
DBG("%p", modem);
gprs = ofono_gprs_create(modem, data->vendor_family, "atmodem",
data->aux);
if (ublox_is_toby_l4(data->model)) {
driver = "ubloxmodem";
variant = ublox_model_to_id(data->model);
} else if (ublox_is_toby_l2(data->model)) {
if (data->flags & UBLOX_DEVICE_F_HIGH_THROUGHPUT_MODE) {
driver = "ubloxmodem";
variant = ublox_model_to_id(data->model);
} else {
driver = "atmodem";
variant = OFONO_VENDOR_UBLOX;
}
} else {
driver = "atmodem";
variant = OFONO_VENDOR_UBLOX;
}
while (ncontexts) {
gc = ofono_gprs_context_create(modem, data->vendor_family,
driver, chat);
gc = ofono_gprs_context_create(modem, variant, driver, chat);
if (gprs && gc)
ofono_gprs_add_context(gprs, gc);
@@ -328,7 +418,8 @@ static void ublox_post_sim(struct ofono_modem *modem)
--ncontexts;
}
ofono_lte_create(modem, 0, "ubloxmodem", data->aux);
ofono_lte_create(modem,
ublox_model_to_id(data->model), "ubloxmodem", data->aux);
}
static void ublox_post_online(struct ofono_modem *modem)

View File

@@ -1090,11 +1090,17 @@ static gboolean setup_ublox(struct modem_info *modem)
* - high throughput profile : 224/1/3
*/
} else if (g_strcmp0(info->interface, "2/2/1") == 0) {
if (g_strcmp0(info->number, "02") == 0)
aux = info->devnode;
else if (g_strcmp0(info->number, "00") == 0)
if (!g_strcmp0(modem->model, "1010")) {
if (g_strcmp0(info->number, "06") == 0)
aux = info->devnode;
} else {
if (g_strcmp0(info->number, "02") == 0)
aux = info->devnode;
}
if (g_strcmp0(info->number, "00") == 0)
mdm = info->devnode;
} else if (g_strcmp0(info->interface, "2/6/0") == 0 ||
g_strcmp0(info->interface, "2/13/0") == 0 ||
g_strcmp0(info->interface, "10/0/0") == 0 ||
g_strcmp0(info->interface, "224/1/3") == 0) {
net = info->devnode;
@@ -1111,7 +1117,6 @@ static gboolean setup_ublox(struct modem_info *modem)
ofono_modem_set_string(modem->modem, "Aux", aux);
ofono_modem_set_string(modem->modem, "Modem", mdm);
ofono_modem_set_string(modem->modem, "Model", modem->model);
ofono_modem_set_string(modem->modem, "NetworkInterface", net);
return TRUE;
@@ -1179,7 +1184,7 @@ static gboolean setup_gemalto(struct modem_info* modem)
static gboolean setup_xmm7xxx(struct modem_info *modem)
{
const char *mdm = NULL, *net = NULL;
const char *mdm = NULL, *net = NULL, *net2 = NULL, *net3 = NULL;
GSList *list;
DBG("%s %s %s %s %s %s\n", modem->syspath, modem->devname,
@@ -1199,6 +1204,10 @@ static gboolean setup_xmm7xxx(struct modem_info *modem)
} else if (g_strcmp0(info->subsystem, "net") == 0) {
if (g_strcmp0(info->number, "06") == 0)
net = info->devnode;
if (g_strcmp0(info->number, "08") == 0)
net2 = info->devnode;
if (g_strcmp0(info->number, "0a") == 0)
net3 = info->devnode;
}
} else {
if (g_strcmp0(info->subsystem, "tty") == 0) {
@@ -1219,6 +1228,15 @@ static gboolean setup_xmm7xxx(struct modem_info *modem)
ofono_modem_set_string(modem->modem, "Modem", mdm);
ofono_modem_set_string(modem->modem, "NetworkInterface", net);
if (net2)
ofono_modem_set_string(modem->modem, "NetworkInterface2", net2);
if (net3)
ofono_modem_set_string(modem->modem, "NetworkInterface3", net3);
ofono_modem_set_string(modem->modem, "CtrlPath", "/USBCDC/0");
ofono_modem_set_string(modem->modem, "DataPath", "/USBHS/NCM/");
return TRUE;
}
@@ -1678,6 +1696,8 @@ static struct {
{ "quectelqmi", "qcserial", "2c7c", "0121" },
{ "quectelqmi", "qmi_wwan", "2c7c", "0125" },
{ "quectelqmi", "qcserial", "2c7c", "0125" },
{ "ublox", "cdc_acm", "1546", "1010" },
{ "ublox", "cdc_ncm", "1546", "1010" },
{ "ublox", "cdc_acm", "1546", "1102" },
{ "ublox", "rndis_host", "1546", "1146" },
{ "ublox", "cdc_acm", "1546", "1146" },

View File

@@ -1223,7 +1223,7 @@ static void xmm7xxx_pre_sim(struct ofono_modem *modem)
DBG("%p", modem);
ofono_devinfo_create(modem, OFONO_VENDOR_IFX, "atmodem", data->chat);
data->sim = ofono_sim_create(modem, OFONO_VENDOR_IFX, "atmodem",
data->sim = ofono_sim_create(modem, OFONO_VENDOR_XMM, "atmodem",
data->chat);
}
@@ -1269,6 +1269,7 @@ static void xmm7xxx_post_online(struct ofono_modem *modem)
struct xmm7xxx_data *data = ofono_modem_get_data(modem);
struct ofono_gprs *gprs;
struct ofono_gprs_context *gc;
const char *interface = NULL;
DBG("%p", modem);
@@ -1276,11 +1277,39 @@ static void xmm7xxx_post_online(struct ofono_modem *modem)
gprs = ofono_gprs_create(modem, OFONO_VENDOR_IFX, "atmodem",
data->chat);
interface = ofono_modem_get_string(modem, "NetworkInterface");
gc = ofono_gprs_context_create(modem, OFONO_VENDOR_XMM, "ifxmodem",
data->chat);
if (gprs && gc)
if (gprs && gc) {
ofono_gprs_add_context(gprs, gc);
ofono_gprs_context_set_interface(gc, interface);
}
interface = ofono_modem_get_string(modem, "NetworkInterface2");
if (interface) {
gc = ofono_gprs_context_create(modem, OFONO_VENDOR_XMM,
"ifxmodem", data->chat);
if (gprs && gc) {
ofono_gprs_add_context(gprs, gc);
ofono_gprs_context_set_interface(gc, interface);
}
}
interface = ofono_modem_get_string(modem, "NetworkInterface3");
if (interface) {
gc = ofono_gprs_context_create(modem, OFONO_VENDOR_XMM,
"ifxmodem", data->chat);
if (gprs && gc) {
ofono_gprs_add_context(gprs, gc);
ofono_gprs_context_set_interface(gc, interface);
}
}
ofono_ims_create(modem, "xmm7modem", data->chat);
ofono_netmon_create(modem, 0, "xmm7modem", data->chat);

View File

@@ -771,7 +771,7 @@ static void sim_cbmi_read_cb(int ok, int length, int record,
mi = (data[i] << 8) + data[i+1];
if (mi > 999)
if (mi > CBS_MAX_TOPIC)
continue;
range = g_new0(struct cbs_topic_range, 1);
@@ -818,7 +818,7 @@ static void sim_cbmir_read_cb(int ok, int length, int record,
min = (data[i] << 8) + data[i+1];
max = (data[i+2] << 8) + data[i+3];
if (min > 999 || max > 999 || min > max)
if (min > CBS_MAX_TOPIC || max > CBS_MAX_TOPIC || min > max)
continue;
range = g_new0(struct cbs_topic_range, 1);

View File

@@ -57,14 +57,19 @@ struct cell_property {
const char *name;
glong off;
int flag;
int type;
};
#define CELL_GSM_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct ofono_cell_info_gsm,name), value }
{ #name, G_STRUCT_OFFSET(struct ofono_cell_info_gsm,name), value, DBUS_TYPE_INT32 }
#define CELL_WCDMA_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct ofono_cell_info_wcdma,name), value }
{ #name, G_STRUCT_OFFSET(struct ofono_cell_info_wcdma,name), value, DBUS_TYPE_INT32 }
#define CELL_LTE_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct ofono_cell_info_lte,name), value }
{ #name, G_STRUCT_OFFSET(struct ofono_cell_info_lte,name), value, DBUS_TYPE_INT32 }
#define CELL_NR_PROPERTY(value,name) \
{ #name, G_STRUCT_OFFSET(struct ofono_cell_info_nr,name), value, DBUS_TYPE_INT32 }
#define CELL_NR_PROPERTY64(value,name) \
{ #name, G_STRUCT_OFFSET(struct ofono_cell_info_nr,name), value, DBUS_TYPE_INT64 }
static const struct cell_property cell_gsm_properties [] = {
CELL_GSM_PROPERTY(0x001,mcc),
@@ -104,6 +109,21 @@ static const struct cell_property cell_lte_properties [] = {
CELL_LTE_PROPERTY(0x800,timingAdvance)
};
static const struct cell_property cell_nr_properties [] = {
CELL_NR_PROPERTY(0x001,mcc),
CELL_NR_PROPERTY(0x002,mnc),
CELL_NR_PROPERTY64(0x004,nci),
CELL_NR_PROPERTY(0x008,pci),
CELL_NR_PROPERTY(0x010,tac),
CELL_NR_PROPERTY(0x020,nrarfcn),
CELL_NR_PROPERTY(0x040,ssRsrp),
CELL_NR_PROPERTY(0x080,ssRsrq),
CELL_NR_PROPERTY(0x100,ssSinr),
CELL_NR_PROPERTY(0x200,csiRsrp),
CELL_NR_PROPERTY(0x400,csiRsrq),
CELL_NR_PROPERTY(0x800,csiSinr),
};
#define CELL_PROPERTY_REGISTERED 0x1000
typedef void (*cell_info_dbus_append_fn)(DBusMessageIter *it,
@@ -124,6 +144,8 @@ static const char *cell_info_dbus_cell_type_str(enum ofono_cell_type type)
return "wcdma";
case OFONO_CELL_TYPE_LTE:
return "lte";
case OFONO_CELL_TYPE_NR:
return "nr";
default:
return "unknown";
}
@@ -142,6 +164,9 @@ static const struct cell_property *cell_info_dbus_cell_properties
case OFONO_CELL_TYPE_LTE:
*count = G_N_ELEMENTS(cell_lte_properties);
return cell_lte_properties;
case OFONO_CELL_TYPE_NR:
*count = G_N_ELEMENTS(cell_nr_properties);
return cell_nr_properties;
default:
*count = 0;
return NULL;
@@ -202,10 +227,18 @@ static void cell_info_dbus_append_properties(DBusMessageIter *it,
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &dict);
for (i = 0; i < n; i++) {
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
if (value != OFONO_CELL_INVALID_VALUE) {
ofono_dbus_dict_append(&dict, prop[i].name,
DBUS_TYPE_INT32, &value);
if (prop[i].type == DBUS_TYPE_INT64) {
gint64 value = G_STRUCT_MEMBER(gint64, &cell->info, prop[i].off);
if (value != OFONO_CELL_INVALID_VALUE_INT64) {
ofono_dbus_dict_append(&dict, prop[i].name,
DBUS_TYPE_INT64, &value);
}
} else {
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
if (value != OFONO_CELL_INVALID_VALUE) {
ofono_dbus_dict_append(&dict, prop[i].name,
DBUS_TYPE_INT32, &value);
}
}
}
dbus_message_iter_close_container(it, &dict);
@@ -375,11 +408,20 @@ static int cell_info_dbus_compare(const struct ofono_cell *c1,
for (i = 0; i < n; i++) {
const glong offset = prop[i].off;
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
if (prop[i].type == DBUS_TYPE_INT64) {
gint64 v1 = G_STRUCT_MEMBER(gint64, &c1->info, offset);
gint64 v2 = G_STRUCT_MEMBER(gint64, &c2->info, offset);
if (v1 != v2) {
mask |= prop[i].flag;
if (v1 != v2) {
mask |= prop[i].flag;
}
} else {
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
if (v1 != v2) {
mask |= prop[i].flag;
}
}
}
@@ -427,7 +469,7 @@ static void cell_info_dbus_property_changed(CellInfoDBus *dbus,
ofono_dbus_clients_signal_property_changed(
dbus->clients, entry->path,
CELL_DBUS_INTERFACE, prop[i].name,
DBUS_TYPE_INT32,
prop[i].type,
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
mask &= ~prop[i].flag;
}

View File

@@ -70,6 +70,23 @@ int ofono_cell_compare_location(const struct ofono_cell *c1,
} else {
return l1->tac - l2->tac;
}
} else if (c1->type == OFONO_CELL_TYPE_NR) {
const struct ofono_cell_info_nr *n1 =
&c1->info.nr;
const struct ofono_cell_info_nr *n2 =
&c2->info.nr;
if (n1->mcc != n2->mcc) {
return n1->mcc - n2->mcc;
} else if (n1->mnc != n2->mnc) {
return n1->mnc - n2->mnc;
} else if (n1->nci != n2->nci) {
return n1->nci - n2->nci;
} else if (n1->pci != n2->pci) {
return n1->pci - n2->pci;
} else {
return n1->tac - n2->tac;
}
} else {
ofono_warn("Unexpected cell type");
return 0;

View File

@@ -706,8 +706,20 @@ const char *registration_tech_to_string(enum ofono_access_technology tech)
return "hspa";
case ACCESS_TECHNOLOGY_EUTRAN:
return "lte";
case ACCESS_TECHNOLOGY_NB_IOT_M1:
return "lte-cat-m1";
case ACCESS_TECHNOLOGY_NB_IOT_NB1:
return "lte-cat-nb1";
case ACCESS_TECHNOLOGY_EUTRA_5GCN:
return "lte";
case ACCESS_TECHNOLOGY_NR_5GCN:
case ACCESS_TECHNOLOGY_NG_RAN:
case ACCESS_TECHNOLOGY_EUTRA_NR:
return "nr";
case OFONO_ACCESS_TECHNOLOGY_NONE:
break;
default:
return "";
}
return "";
}

View File

@@ -42,6 +42,18 @@
OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA /* 6 */
#define ACCESS_TECHNOLOGY_EUTRAN \
OFONO_ACCESS_TECHNOLOGY_EUTRAN /* 7 */
#define ACCESS_TECHNOLOGY_NB_IOT_M1 \
OFONO_ACCESS_TECHNOLOGY_NB_IOT_M1 /* 8 */
#define ACCESS_TECHNOLOGY_NB_IOT_NB1 \
OFONO_ACCESS_TECHNOLOGY_NB_IOT_NB1 /* 9 */
#define ACCESS_TECHNOLOGY_EUTRA_5GCN \
OFONO_ACCESS_TECHNOLOGY_EUTRA_5GCN /* 10 */
#define ACCESS_TECHNOLOGY_NR_5GCN \
OFONO_ACCESS_TECHNOLOGY_NR_5GCN /* 11 */
#define ACCESS_TECHNOLOGY_NG_RAN \
OFONO_ACCESS_TECHNOLOGY_NG_RAN /* 12 */
#define ACCESS_TECHNOLOGY_EUTRA_NR \
OFONO_ACCESS_TECHNOLOGY_EUTRA_NR /* 13 */
/* 27.007 Section 7.2 <stat> */
#define NETWORK_REGISTRATION_STATUS_NOT_REGISTERED \

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2015-2021 Jolla Ltd.
* Copyright (C) 2015-2022 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
@@ -243,6 +243,7 @@ static void conf_merge_group(GKeyFile *conf, GKeyFile *k, const char *group)
group, key, &count, NULL);
key[len-1] = 0;
g_strchomp(key); /* Strip spaces before + */
conf_list_append(conf, k, group, key,
values, count, last == '?');
g_strfreev(values);
@@ -252,6 +253,7 @@ static void conf_merge_group(GKeyFile *conf, GKeyFile *k, const char *group)
group, key, &count, NULL);
key[len-1] = 0;
g_strchomp(key); /* Strip spaces before - */
conf_list_remove(conf, k, group, key,
values, count);
g_strfreev(values);
@@ -531,13 +533,16 @@ gboolean ofono_conf_get_mask(GKeyFile *file, const char *group,
char **values, **ptr;
if (comment) *comment = 0;
values = g_strsplit(str, "+", -1);
values = g_strsplit_set(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)) {
if (!s[0]) {
/* Ignore empty entries */
continue;
} else if (!strcasecmp(s, name)) {
found_str = name;
if (result) {
*result |= value;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2019-2021 Jolla Ltd.
* Copyright (C) 2019-2022 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
@@ -46,6 +46,8 @@ const char *ofono_dbus_access_intf_name(enum ofono_dbus_access_intf intf)
return OFONO_STK_INTERFACE;
case OFONO_DBUS_ACCESS_INTF_OEMRAW:
return "org.ofono.OemRaw";
case OFONO_DBUS_ACCESS_INTF_IMS:
return OFONO_IMS_INTERFACE;
case OFONO_DBUS_ACCESS_INTF_COUNT:
break;
}
@@ -68,6 +70,8 @@ const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
switch ((enum ofono_dbus_access_messagemgr_method)method) {
case OFONO_DBUS_ACCESS_MESSAGEMGR_SEND_MESSAGE:
return "SendMessage";
case OFONO_DBUS_ACCESS_MESSAGEMGR_SEND_DATA_MESSAGE:
return "SendDataMessage";
case OFONO_DBUS_ACCESS_MESSAGEMGR_METHOD_COUNT:
break;
}
@@ -186,6 +190,18 @@ const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
break;
}
break;
case OFONO_DBUS_ACCESS_INTF_IMS:
switch ((enum ofono_dbus_access_ims_method)method) {
case OFONO_DBUS_ACCESS_IMS_SET_PROPERTY:
return "SetProperty";
case OFONO_DBUS_ACCESS_IMS_REGISTER:
return "Register";
case OFONO_DBUS_ACCESS_IMS_UNREGISTER:
return "Unregister";
case OFONO_DBUS_ACCESS_IMS_METHOD_COUNT:
break;
}
break;
case OFONO_DBUS_ACCESS_INTF_COUNT:
break;
}

View File

@@ -110,7 +110,6 @@ struct ipv6_settings {
};
struct context_settings {
char *interface;
struct ipv4_settings *ipv4;
struct ipv6_settings *ipv6;
};
@@ -121,6 +120,7 @@ struct ofono_gprs_context {
ofono_bool_t inuse;
const struct ofono_gprs_context_driver *driver;
void *driver_data;
char *interface;
struct context_settings *settings;
struct ofono_atom *atom;
};
@@ -361,12 +361,10 @@ static void context_settings_free(struct context_settings *settings)
g_free(settings->ipv6);
settings->ipv6 = NULL;
}
g_free(settings->interface);
settings->interface = NULL;
}
static void context_settings_append_ipv4(struct context_settings *settings,
const char *interface,
DBusMessageIter *iter)
{
DBusMessageIter variant;
@@ -391,7 +389,7 @@ static void context_settings_append_ipv4(struct context_settings *settings,
goto done;
ofono_dbus_dict_append(&array, "Interface",
DBUS_TYPE_STRING, &settings->interface);
DBUS_TYPE_STRING, &interface);
if (settings->ipv4->proxy)
ofono_dbus_dict_append(&array, "Proxy", DBUS_TYPE_STRING,
@@ -433,6 +431,7 @@ done:
}
static void context_settings_append_ipv4_dict(struct context_settings *settings,
const char *interface,
DBusMessageIter *dict)
{
DBusMessageIter entry;
@@ -443,12 +442,13 @@ static void context_settings_append_ipv4_dict(struct context_settings *settings,
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
context_settings_append_ipv4(settings, &entry);
context_settings_append_ipv4(settings, interface, &entry);
dbus_message_iter_close_container(dict, &entry);
}
static void context_settings_append_ipv6(struct context_settings *settings,
const char *interface,
DBusMessageIter *iter)
{
DBusMessageIter variant;
@@ -472,7 +472,7 @@ static void context_settings_append_ipv6(struct context_settings *settings,
goto done;
ofono_dbus_dict_append(&array, "Interface",
DBUS_TYPE_STRING, &settings->interface);
DBUS_TYPE_STRING, &interface);
if (settings->ipv6->ip)
ofono_dbus_dict_append(&array, "Address", DBUS_TYPE_STRING,
@@ -503,6 +503,7 @@ done:
}
static void context_settings_append_ipv6_dict(struct context_settings *settings,
const char *interface,
DBusMessageIter *dict)
{
DBusMessageIter entry;
@@ -513,13 +514,14 @@ static void context_settings_append_ipv6_dict(struct context_settings *settings,
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
context_settings_append_ipv6(settings, &entry);
context_settings_append_ipv6(settings, interface, &entry);
dbus_message_iter_close_container(dict, &entry);
}
static void signal_settings(struct pri_context *ctx, const char *prop,
void (*append)(struct context_settings *, DBusMessageIter *))
void (*append)(struct context_settings *,
const char *, DBusMessageIter *))
{
DBusConnection *conn = ofono_dbus_get_connection();
@@ -527,6 +529,7 @@ static void signal_settings(struct pri_context *ctx, const char *prop,
DBusMessage *signal;
DBusMessageIter iter;
struct context_settings *settings;
const char *interface;
signal = dbus_message_new_signal(path,
OFONO_CONNECTION_CONTEXT_INTERFACE,
@@ -538,12 +541,15 @@ static void signal_settings(struct pri_context *ctx, const char *prop,
dbus_message_iter_init_append(signal, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &prop);
if (ctx->context_driver)
if (ctx->context_driver) {
settings = ctx->context_driver->settings;
else
interface = ctx->context_driver->interface;
} else {
settings = NULL;
interface = NULL;
}
append(settings, &iter);
append(settings, interface, &iter);
g_dbus_send_message(conn, signal);
}
@@ -781,18 +787,16 @@ static void pri_setproxy(const char *interface, const char *proxy)
static void pri_reset_context_settings(struct pri_context *ctx)
{
struct context_settings *settings;
char *interface;
const char *interface;
gboolean signal_ipv4;
gboolean signal_ipv6;
if (ctx->context_driver == NULL)
return;
interface = ctx->context_driver->interface;
settings = ctx->context_driver->settings;
interface = settings->interface;
settings->interface = NULL;
signal_ipv4 = settings->ipv4 != NULL;
signal_ipv6 = settings->ipv6 != NULL;
@@ -809,8 +813,6 @@ static void pri_reset_context_settings(struct pri_context *ctx)
}
pri_ifupdown(interface, FALSE);
g_free(interface);
}
static void pri_update_mms_context_settings(struct pri_context *ctx)
@@ -826,10 +828,10 @@ static void pri_update_mms_context_settings(struct pri_context *ctx)
DBG("proxy %s port %u", ctx->proxy_host, ctx->proxy_port);
pri_set_ipv4_addr(settings->interface, settings->ipv4->ip);
pri_set_ipv4_addr(gc->interface, settings->ipv4->ip);
if (ctx->proxy_host)
pri_setproxy(settings->interface, ctx->proxy_host);
pri_setproxy(gc->interface, ctx->proxy_host);
}
static gboolean pri_str_changed(const char *val, const char *newval)
@@ -1056,6 +1058,7 @@ static void append_context_properties(struct pri_context *ctx,
dbus_bool_t value;
const char *strvalue;
struct context_settings *settings;
const char *interface;
ofono_dbus_dict_append(dict, "Name", DBUS_TYPE_STRING, &name);
@@ -1092,13 +1095,16 @@ static void append_context_properties(struct pri_context *ctx,
DBUS_TYPE_STRING, &strvalue);
}
if (ctx->context_driver)
if (ctx->context_driver) {
settings = ctx->context_driver->settings;
else
interface = ctx->context_driver->interface;
} else {
settings = NULL;
interface = NULL;
}
context_settings_append_ipv4_dict(settings, dict);
context_settings_append_ipv6_dict(settings, dict);
context_settings_append_ipv4_dict(settings, interface, dict);
context_settings_append_ipv6_dict(settings, interface, dict);
}
static DBusMessage *pri_get_properties(DBusConnection *conn,
@@ -1147,8 +1153,8 @@ static void pri_activate_callback(const struct ofono_error *error, void *data)
__ofono_dbus_pending_reply(&ctx->pending,
dbus_message_new_method_return(ctx->pending));
if (gc->settings->interface != NULL) {
pri_ifupdown(gc->settings->interface, TRUE);
if (gc->interface != NULL) {
pri_ifupdown(gc->interface, TRUE);
if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS &&
gc->settings->ipv4)
@@ -1241,8 +1247,8 @@ static void pri_read_settings_callback(const struct ofono_error *error,
pri_ctx->active = TRUE;
if (gc->settings->interface != NULL) {
pri_ifupdown(gc->settings->interface, TRUE);
if (gc->interface != NULL) {
pri_ifupdown(gc->interface, TRUE);
pri_context_signal_settings(pri_ctx, gc->settings->ipv4 != NULL,
gc->settings->ipv6 != NULL);
@@ -1810,7 +1816,7 @@ static gboolean context_dbus_unregister(struct pri_context *ctx)
if (ctx->active == TRUE) {
const char *interface =
ctx->context_driver->settings->interface;
ctx->context_driver->interface;
if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS)
pri_set_ipv4_addr(interface, NULL);
@@ -3112,6 +3118,11 @@ done:
g_free(gc->settings);
gc->settings = NULL;
}
if (gc->interface) {
g_free(gc->interface);
gc->interface = NULL;
}
}
void ofono_gprs_add_context(struct ofono_gprs *gprs,
@@ -3295,13 +3306,16 @@ enum ofono_gprs_context_type ofono_gprs_context_get_type(
return gc->type;
}
const char *ofono_gprs_context_get_interface(struct ofono_gprs_context *gc)
{
return gc->interface;
}
void ofono_gprs_context_set_interface(struct ofono_gprs_context *gc,
const char *interface)
{
struct context_settings *settings = gc->settings;
g_free(settings->interface);
settings->interface = g_strdup(interface);
g_free(gc->interface);
gc->interface = g_strdup(interface);
}
void ofono_gprs_context_set_ipv4_address(struct ofono_gprs_context *gc,

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. All rights reserved.
* Copyright (C) 2022 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
@@ -35,9 +36,28 @@
#include "ofono.h"
#include "common.h"
#include "storage.h"
#include "dbus-queue.h"
#define VOICE_CAPABLE_FLAG 0x1
#define SMS_CAPABLE_FLAG 0x4
#define VOICE_CAPABLE_FLAG OFONO_IMS_VOICE_CAPABLE
#define SMS_CAPABLE_FLAG OFONO_IMS_SMS_CAPABLE
#define RECHECK_TIMEOUT_SEC (10)
enum ims_reg_strategy {
IMS_REG_DISABLED,
IMS_REG_ENABLED,
IMS_REG_AUTO
#define IMS_REG_DEFAULT IMS_REG_AUTO
};
enum ims_watch_events {
WATCH_EVENT_REG_TECH,
WATCH_EVENT_IMSI,
WATCH_EVENT_COUNT
};
struct ims_call;
struct ofono_ims {
int reg_info;
@@ -45,11 +65,313 @@ struct ofono_ims {
const struct ofono_ims_driver *driver;
void *driver_data;
struct ofono_atom *atom;
DBusMessage *pending;
struct ofono_watch *watch;
struct ofono_dbus_queue *q;
struct ims_call *pending;
struct ims_call *tail;
enum ims_reg_strategy reg_strategy;
gboolean reg_check_pending;
gulong watch_id[WATCH_EVENT_COUNT];
char *imsi;
GKeyFile *settings;
guint recheck_timeout_id;
};
/* Calls to the driver are serialized */
typedef void (*ims_cb_t)(void);
typedef void (*ims_submit_cb_t)(struct ims_call *call);
struct ims_call {
struct ims_call *next;
struct ofono_ims *ims;
ims_submit_cb_t submit;
union {
ofono_ims_register_cb_t register_cb;
ofono_ims_status_cb_t status_cb;
ims_cb_t fn;
} cb;
void *data;
};
#define CALLBACK(f) ((ims_cb_t)(f))
#define REGISTRATION_PROP "Registration"
#define SETTINGS_STORE "ims"
#define SETTINGS_GROUP "Settings"
#define REGISTRATION_KEY REGISTRATION_PROP
static GSList *g_drivers = NULL;
static const char *reg_strategy_name[] = { "disabled", "enabled", "auto" };
static gboolean ims_registration_recheck_cb(gpointer user_data);
static gboolean ims_ret_strategy_from_string(const char *str,
enum ims_reg_strategy *value)
{
if (str) {
int i;
for (i = 0; i < G_N_ELEMENTS(reg_strategy_name); i++) {
if (!g_strcmp0(str, reg_strategy_name[i])) {
*value = i;
return TRUE;
}
}
}
return FALSE;
}
static inline gboolean ims_dbus_access_allowed(DBusMessage *msg,
enum ofono_dbus_access_ims_method method)
{
return ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
OFONO_DBUS_ACCESS_INTF_IMS, method, NULL);
}
static void ims_call_done(struct ims_call *call)
{
struct ofono_ims *ims = call->ims;
ims->pending = call->next;
g_slice_free(struct ims_call, call);
if (ims->pending) {
ims->pending->submit(ims->pending);
} else {
ims->tail = NULL;
}
}
static void ims_call_submit(struct ofono_ims *ims, ims_submit_cb_t submit,
ims_cb_t cb, void *data)
{
struct ims_call *call = g_slice_new0(struct ims_call);
call->ims = ims;
call->submit = submit;
call->cb.fn = cb;
call->data = data;
if (ims->pending) {
ims->tail->next = call;
ims->tail = call;
} else {
ims->pending = ims->tail = call;
submit(call);
}
}
static void ims_call_register_cb(const struct ofono_error *error, void *data)
{
struct ims_call *call = data;
if (call->cb.register_cb)
call->cb.register_cb(error, call->data);
ims_call_done(call);
}
static void ims_call_status_cb(const struct ofono_error *error,
int reg_info, int ext_info,
void *data)
{
struct ims_call *call = data;
if (call->cb.status_cb)
call->cb.status_cb(error, reg_info, ext_info, call->data);
ims_call_done(call);
}
static void ims_call_submit_registration_status(struct ims_call *call)
{
struct ofono_ims *ims = call->ims;
ims->driver->registration_status(ims, ims_call_status_cb, call);
}
static void ims_call_submit_register(struct ims_call *call)
{
struct ofono_ims *ims = call->ims;
ims->driver->ims_register(ims, ims_call_register_cb, call);
}
static void ims_call_submit_unregister(struct ims_call *call)
{
struct ofono_ims *ims = call->ims;
ims->driver->ims_unregister(ims, ims_call_register_cb, call);
}
static void ims_call_registration_status(struct ofono_ims *ims,
ofono_ims_status_cb_t cb, void *data)
{
ims_call_submit(ims, ims_call_submit_registration_status,
CALLBACK(cb), data);
}
static void ims_call_register(struct ofono_ims *ims,
ofono_ims_register_cb_t cb, void *data)
{
ims_call_submit(ims, ims_call_submit_register, CALLBACK(cb), data);
}
static void ims_call_unregister(struct ofono_ims *ims,
ofono_ims_register_cb_t cb, void *data)
{
ims_call_submit(ims, ims_call_submit_unregister, CALLBACK(cb), data);
}
static gboolean ims_supported_reg_tech(struct ofono_ims *ims)
{
return ims->watch &&
ims->watch->reg_tech >= OFONO_ACCESS_TECHNOLOGY_EUTRAN;
}
static void ims_registration_check(struct ofono_ims *ims)
{
if (!ims->reg_check_pending)
return;
ims->reg_check_pending = FALSE;
if (ims->recheck_timeout_id) {
g_source_remove(ims->recheck_timeout_id);
ims->recheck_timeout_id = 0;
}
DBG("checking ims state");
switch (ims->reg_strategy) {
case IMS_REG_DISABLED:
/* Keep registration off */
if (ims->reg_info && ims->driver &&
ims->driver->ims_unregister) {
DBG("auto-unregistering");
ims_call_unregister(ims, NULL, NULL);
ims->recheck_timeout_id =
g_timeout_add_seconds(RECHECK_TIMEOUT_SEC,
ims_registration_recheck_cb, ims);
} else {
DBG("ims is disabled, leaving it unregistered");
}
return;
case IMS_REG_ENABLED:
/* Any state is acceptable */
DBG("ims is enabled, no action needed");
return;
case IMS_REG_AUTO:
break;
}
/* Keep registration on (default behavior) */
if (!ims->reg_info && ims_supported_reg_tech(ims) &&
ims->driver && ims->driver->ims_register) {
DBG("auto-registering");
ims_call_register(ims, NULL, NULL);
ims->recheck_timeout_id =
g_timeout_add_seconds(RECHECK_TIMEOUT_SEC,
ims_registration_recheck_cb, ims);
} else {
DBG("leaving ims registered");
}
}
static gboolean ims_registration_recheck_cb(gpointer user_data)
{
struct ofono_ims *ims = user_data;
ims->recheck_timeout_id = 0;
ims_registration_check(ims);
return G_SOURCE_REMOVE;
}
static void ims_reg_tech_changed(struct ofono_watch *watch, void *data)
{
struct ofono_ims *ims = data;
ims->reg_check_pending = TRUE;
ims_registration_check(ims);
}
static void ims_set_reg_strategy(struct ofono_ims *ims,
enum ims_reg_strategy value)
{
if (ims->reg_strategy != value) {
const char *path = __ofono_atom_get_path(ims->atom);
DBusConnection *conn = ofono_dbus_get_connection();
DBG("ims %s", reg_strategy_name[value]);
ims->reg_strategy = value;
ims->reg_check_pending = TRUE;
if (ims->settings) {
g_key_file_set_string(ims->settings, SETTINGS_GROUP,
REGISTRATION_KEY, reg_strategy_name[value]);
storage_sync(ims->imsi, SETTINGS_STORE, ims->settings);
}
ofono_dbus_signal_property_changed(conn, path,
OFONO_IMS_INTERFACE,
REGISTRATION_PROP, DBUS_TYPE_STRING,
reg_strategy_name + ims->reg_strategy);
}
}
static gboolean ims_imsi_check(struct ofono_ims *ims)
{
const char* imsi = ims->watch ? ims->watch->imsi : NULL;
if (g_strcmp0(ims->imsi, imsi)) {
if (ims->imsi) {
storage_close(ims->imsi, SETTINGS_STORE,
ims->settings, TRUE);
g_free(ims->imsi);
}
if (imsi) {
ims->settings = storage_open(imsi, SETTINGS_STORE);
ims->imsi = g_strdup(imsi);
} else {
ims->settings = NULL;
ims->imsi = NULL;
}
return TRUE;
}
return FALSE;
}
static void ims_apply_settings(struct ofono_ims *ims)
{
char* str;
if (!ims->settings)
return;
str = g_key_file_get_string(ims->settings, SETTINGS_GROUP,
REGISTRATION_KEY, NULL);
if (str) {
enum ims_reg_strategy ims_reg = IMS_REG_DEFAULT;
if (ims_ret_strategy_from_string(str, &ims_reg))
ims_set_reg_strategy(ims, ims_reg);
g_free(str);
}
}
static void ims_imsi_changed(struct ofono_watch *watch, void *data)
{
struct ofono_ims *ims = data;
if (ims_imsi_check(ims)) {
ims_apply_settings(ims);
ims_registration_check(ims);
}
}
static DBusMessage *ims_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -71,6 +393,8 @@ static DBusMessage *ims_get_properties(DBusConnection *conn,
value = ims->reg_info ? TRUE : FALSE;
ofono_dbus_dict_append(&dict, "Registered", DBUS_TYPE_BOOLEAN, &value);
ofono_dbus_dict_append(&dict, REGISTRATION_PROP, DBUS_TYPE_STRING,
reg_strategy_name + ims->reg_strategy);
if (ims->ext_info != -1) {
value = ims->ext_info & VOICE_CAPABLE_FLAG ? TRUE : FALSE;
@@ -87,6 +411,50 @@ static DBusMessage *ims_get_properties(DBusConnection *conn,
return reply;
}
static DBusMessage *ims_set_property(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ofono_ims *ims = data;
DBusMessageIter iter;
DBusMessageIter var;
const char *property;
if (!ims_dbus_access_allowed(msg, OFONO_DBUS_ACCESS_IMS_SET_PROPERTY))
return __ofono_error_access_denied(msg);
if (!dbus_message_iter_init(msg, &iter))
return __ofono_error_invalid_args(msg);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &property);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
return __ofono_error_invalid_args(msg);
dbus_message_iter_recurse(&iter, &var);
if (!g_strcmp0(property, REGISTRATION_PROP)) {
const char *str = NULL;
enum ims_reg_strategy value = IMS_REG_DEFAULT;
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &str);
if (ims_ret_strategy_from_string(str, &value)) {
ims_set_reg_strategy(ims, value);
ims_registration_check(ims);
return dbus_message_new_method_return(msg);
}
}
return __ofono_error_invalid_args(msg);
}
static void ims_set_sms_capable(struct ofono_ims *ims, ofono_bool_t status)
{
const char *path = __ofono_atom_get_path(ims->atom);
@@ -154,6 +522,7 @@ void ofono_ims_status_notify(struct ofono_ims *ims, int reg_info, int ext_info)
if (ims->ext_info == ext_info && ims->reg_info == reg_info)
return;
ims->reg_check_pending = TRUE;
new_reg_info = reg_info ? TRUE : FALSE;
ims_set_registered(ims, new_reg_info);
@@ -169,38 +538,26 @@ void ofono_ims_status_notify(struct ofono_ims *ims, int reg_info, int ext_info)
skip:
ims->reg_info = reg_info;
ims->ext_info = ext_info;
}
static void registration_status_cb(const struct ofono_error *error,
int reg_info, int ext_info,
void *data)
{
struct ofono_ims *ims = data;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error during IMS registration/unregistration");
return;
}
ofono_ims_status_notify(ims, reg_info, ext_info);
ims_registration_check(ims);
}
static void register_cb(const struct ofono_error *error, void *data)
{
struct ofono_ims *ims = data;
DBusMessage *reply;
if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
reply = dbus_message_new_method_return(ims->pending);
__ofono_dbus_queue_reply_ok(ims->q);
else
reply = __ofono_error_failed(ims->pending);
__ofono_dbus_queue_reply_failed(ims->q);
}
__ofono_dbus_pending_reply(&ims->pending, reply);
static DBusMessage *ofono_ims_register_fn(DBusMessage *msg, void *data)
{
struct ofono_ims *ims = data;
if (ims->driver->registration_status == NULL)
return;
ims_call_register(ims, register_cb, ims);
ims->driver->registration_status(ims, registration_status_cb, ims);
return NULL;
}
static DBusMessage *ofono_ims_send_register(DBusConnection *conn,
@@ -208,15 +565,25 @@ static DBusMessage *ofono_ims_send_register(DBusConnection *conn,
{
struct ofono_ims *ims = data;
if (ims->pending)
return __ofono_error_busy(msg);
if (!ims_dbus_access_allowed(msg, OFONO_DBUS_ACCESS_IMS_REGISTER))
return __ofono_error_access_denied(msg);
if (ims->driver->ims_register == NULL)
if (!ims->driver || !ims->driver->ims_register)
return __ofono_error_not_implemented(msg);
ims->pending = dbus_message_ref(msg);
if (ims->reg_strategy == IMS_REG_DISABLED)
return __ofono_error_not_allowed(msg);
ims->driver->ims_register(ims, register_cb, ims);
__ofono_dbus_queue_request(ims->q, ofono_ims_register_fn, msg, ims);
return NULL;
}
static DBusMessage *ofono_ims_unregister_fn(DBusMessage *msg, void *data)
{
struct ofono_ims *ims = data;
ims_call_unregister(ims, register_cb, ims);
return NULL;
}
@@ -226,15 +593,13 @@ static DBusMessage *ofono_ims_unregister(DBusConnection *conn,
{
struct ofono_ims *ims = data;
if (ims->pending)
return __ofono_error_busy(msg);
if (!ims_dbus_access_allowed(msg, OFONO_DBUS_ACCESS_IMS_UNREGISTER))
return __ofono_error_access_denied(msg);
if (ims->driver->ims_unregister == NULL)
if (!ims->driver || !ims->driver->ims_unregister)
return __ofono_error_not_implemented(msg);
ims->pending = dbus_message_ref(msg);
ims->driver->ims_unregister(ims, register_cb, ims);
__ofono_dbus_queue_request(ims->q, ofono_ims_unregister_fn, msg, ims);
return NULL;
}
@@ -243,6 +608,9 @@ static const GDBusMethodTable ims_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
ims_get_properties) },
{ GDBUS_METHOD("SetProperty",
GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
NULL, ims_set_property) },
{ GDBUS_ASYNC_METHOD("Register", NULL, NULL,
ofono_ims_send_register) },
{ GDBUS_ASYNC_METHOD("Unregister", NULL, NULL,
@@ -268,6 +636,25 @@ static void ims_atom_remove(struct ofono_atom *atom)
if (ims->driver && ims->driver->remove)
ims->driver->remove(ims);
while (ims->pending) {
struct ims_call *call = ims->pending;
ims->pending = call->next;
g_slice_free(struct ims_call, call);
}
if (ims->imsi) {
storage_close(ims->imsi, SETTINGS_STORE, ims->settings, TRUE);
g_free(ims->imsi);
}
if (ims->recheck_timeout_id) {
g_source_remove(ims->recheck_timeout_id);
}
__ofono_dbus_queue_free(ims->q);
ofono_watch_remove_all_handlers(ims->watch, ims->watch_id);
ofono_watch_unref(ims->watch);
g_free(ims);
}
@@ -290,6 +677,9 @@ struct ofono_ims *ofono_ims_create(struct ofono_modem *modem,
ims->reg_info = 0;
ims->ext_info = -1;
ims->reg_strategy = IMS_REG_DEFAULT;
ims->reg_check_pending = TRUE;
ims->q = __ofono_dbus_queue_new();
for (l = g_drivers; l; l = l->next) {
const struct ofono_ims_driver *drv = l->data;
@@ -353,8 +743,21 @@ static void ofono_ims_finish_register(struct ofono_ims *ims)
return;
}
ims->watch = ofono_watch_new(path);
ims->watch_id[WATCH_EVENT_REG_TECH] =
ofono_watch_add_reg_tech_changed_handler(ims->watch,
ims_reg_tech_changed, ims);
ims->watch_id[WATCH_EVENT_IMSI] =
ofono_watch_add_imsi_changed_handler(ims->watch,
ims_imsi_changed, ims);
ofono_modem_add_interface(modem, OFONO_IMS_INTERFACE);
__ofono_atom_register(ims->atom, ims_atom_unregister);
ims->reg_check_pending = TRUE;
ims_imsi_check(ims);
ims_apply_settings(ims);
ims_registration_check(ims);
}
static void registration_init_cb(const struct ofono_error *error,
@@ -373,12 +776,12 @@ static void registration_init_cb(const struct ofono_error *error,
void ofono_ims_register(struct ofono_ims *ims)
{
if (!ims->driver->registration_status) {
if (!ims->driver || !ims->driver->registration_status) {
ofono_ims_finish_register(ims);
return;
}
ims->driver->registration_status(ims, registration_init_cb, ims);
ims_call_registration_status(ims, registration_init_cb, ims);
}
void ofono_ims_remove(struct ofono_ims *ims)

View File

@@ -3,7 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 Jolla Ltd.
* Copyright (C) 2015-2022 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
@@ -1150,6 +1150,9 @@ static DBusMessage *modem_set_property(DBusConnection *conn,
if (modem->lockdown)
return __ofono_error_access_denied(msg);
if (!powered)
__ofono_sim_clear_cached_pins(modem->sim);
err = set_powered(modem, powered);
if (err < 0) {
if (err != -EINPROGRESS)
@@ -2371,7 +2374,7 @@ out:
modem->emergency--;
}
/* Since mer/1.25+git2 */
/* Since 1.25+git2 */
unsigned int ofono_modem_add_watch(ofono_modemwatch_cb_t cb, void *user,
ofono_destroy_func destroy)
@@ -2383,3 +2386,15 @@ ofono_bool_t ofono_modem_remove_watch(unsigned int id)
{
return __ofono_modemwatch_remove(id);
}
/* Since 1.28+git4 */
struct ofono_devinfo *ofono_modem_get_devinfo(struct ofono_modem *modem)
{
return __ofono_atom_find(OFONO_ATOM_TYPE_DEVINFO, modem);
}
const char *ofono_devinfo_get_serial(struct ofono_devinfo *info)
{
return info ? info->serial : NULL;
}

View File

@@ -428,6 +428,7 @@ const struct sim_aid *__ofono_sim_session_get_aid(
struct ofono_sim_aid_session *session);
const char *__ofono_sim_get_impi(struct ofono_sim *sim);
void __ofono_sim_clear_cached_pins(struct ofono_sim *sim);
#include <ofono/stk.h>
@@ -575,6 +576,9 @@ enum sms_class;
typedef void (*sms_send_text_cb_t)(struct ofono_sms *sms,
const struct sms_address *addr, const char *text, void *data);
typedef void (*sms_send_datagram_cb_t)(struct ofono_sms *sms,
const struct sms_address *addr, int dstport, int srcport,
unsigned char *bytes, unsigned int len, int flags, void *data);
typedef void (*sms_dispatch_recv_text_cb_t)
(struct ofono_sms *sms, const struct ofono_uuid *uuid,
@@ -594,6 +598,11 @@ void __ofono_sms_filter_chain_send_text(struct sms_filter_chain *chain,
const struct sms_address *addr, const char *text,
sms_send_text_cb_t sender, ofono_destroy_func destroy,
void *data);
void __ofono_sms_filter_chain_send_datagram(struct sms_filter_chain *chain,
const struct sms_address *addr, int dstport, int srcport,
unsigned char *bytes, int len, int flags,
sms_send_datagram_cb_t sender, ofono_destroy_func destroy,
void *data);
/* Does g_free(buf) when done */
void __ofono_sms_filter_chain_recv_datagram(struct sms_filter_chain *chain,

View File

@@ -65,7 +65,9 @@ struct ofono_radio_settings {
enum ofono_radio_access_mode ofono_radio_access_max_mode(
enum ofono_radio_access_mode mask)
{
return (mask & OFONO_RADIO_ACCESS_MODE_LTE) ?
return (mask & OFONO_RADIO_ACCESS_MODE_NR) ?
OFONO_RADIO_ACCESS_MODE_NR :
(mask & OFONO_RADIO_ACCESS_MODE_LTE) ?
OFONO_RADIO_ACCESS_MODE_LTE :
(mask & OFONO_RADIO_ACCESS_MODE_UMTS) ?
OFONO_RADIO_ACCESS_MODE_UMTS :
@@ -86,6 +88,8 @@ const char *ofono_radio_access_mode_to_string(enum ofono_radio_access_mode m)
return "umts";
case OFONO_RADIO_ACCESS_MODE_LTE:
return "lte";
case OFONO_RADIO_ACCESS_MODE_NR:
return "nr";
default:
return NULL;
}
@@ -110,6 +114,9 @@ ofono_bool_t ofono_radio_access_mode_from_string(const char *str,
} else if (g_str_equal(str, "lte")) {
*mode = OFONO_RADIO_ACCESS_MODE_LTE;
return TRUE;
} else if (g_str_equal(str, "nr")) {
*mode = OFONO_RADIO_ACCESS_MODE_NR;
return TRUE;
}
return FALSE;
@@ -438,7 +445,7 @@ static void radio_available_rats_query_callback(const struct ofono_error *error,
struct ofono_radio_settings *rs = data;
if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
rs->available_rats = available_rats & 0x7;
rs->available_rats = available_rats & 0xF;
else
DBG("Error while querying available rats");

View File

@@ -3,7 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 Jolla Ltd.
* Copyright (C) 2015-2022 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
@@ -132,6 +132,10 @@ struct ofono_sim {
struct ofono_atom *atom;
unsigned int hfp_watch;
unsigned int card_slot_count;
unsigned int active_card_slot;
unsigned int pending_active_card_slot;
GSList *aid_sessions;
GSList *aid_list;
char *impi;
@@ -144,6 +148,11 @@ struct ofono_sim {
bool wait_initialized : 1;
};
struct cached_pin {
char *id;
char *pin;
};
struct msisdn_set_request {
struct ofono_sim *sim;
int pending;
@@ -175,10 +184,18 @@ static const char *const passwd_name[] = {
[OFONO_SIM_PASSWORD_PHCORP_PUK] = "corppuk",
};
#undef ofono_sim_driver_register
struct ofono_sim_driver_data {
struct ofono_sim_driver driver; /* Must be first */
const struct ofono_sim_driver *d;
};
static void sim_own_numbers_update(struct ofono_sim *sim);
static GSList *g_drivers = NULL;
static GSList *cached_pins = NULL;
static const char *sim_passwd_name(enum ofono_sim_password_type type)
{
return passwd_name[type];
@@ -558,6 +575,13 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
get_pin_retries(sim, &pin_retries_dict, &dbus_retries);
ofono_dbus_dict_append_dict(&dict, "Retries", DBUS_TYPE_BYTE,
&pin_retries_dict);
ofono_dbus_dict_append(&dict, "CardSlotCount", DBUS_TYPE_UINT32,
&sim->card_slot_count);
ofono_dbus_dict_append(&dict, "ActiveCardSlot", DBUS_TYPE_UINT32,
&sim->active_card_slot);
g_free(pin_retries_dict);
g_free(dbus_retries);
@@ -567,6 +591,72 @@ done:
return reply;
}
static struct cached_pin *pin_cache_lookup(const char *iccid)
{
struct cached_pin *c;
GSList *l;
if (cached_pins == NULL)
return NULL;
for (l = cached_pins; l; l = l->next) {
c = l->data;
if (g_strcmp0(iccid, c->id) == 0)
return c;
}
return NULL;
}
static void pin_cache_update(const char *iccid, const char *pin)
{
struct cached_pin *pin_cached = pin_cache_lookup(iccid);
struct cached_pin *cpins;
if (pin_cached != NULL) {
g_free(pin_cached->pin);
pin_cached->pin = g_strdup(pin);
return;
}
cpins = g_new0(struct cached_pin, 1);
cpins->id = g_strdup(iccid);
cpins->pin = g_strdup(pin);
cached_pins = g_slist_prepend(cached_pins, cpins);
}
static void pin_cache_remove(const char *iccid)
{
struct cached_pin *pin_cached = pin_cache_lookup(iccid);
if (pin_cached == NULL)
return;
cached_pins = g_slist_remove(cached_pins, pin_cached);
g_free(pin_cached->pin);
g_free(pin_cached->id);
g_free(pin_cached);
}
static void pin_cache_enter_cb(const struct ofono_error *error, void *data)
{
struct ofono_sim *sim = data;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
pin_cache_remove(sim->iccid);
__ofono_sim_recheck_pin(sim);
return;
}
sim->wait_initialized = true;
DBG("Waiting for ofono_sim_initialized_notify");
}
static void sim_pin_retries_query_cb(const struct ofono_error *error,
int retries[OFONO_SIM_PASSWORD_INVALID],
void *data)
@@ -683,6 +773,36 @@ static gboolean sim_allow(DBusMessage *msg,
OFONO_DBUS_ACCESS_INTF_SIMMGR, method, arg);
}
static void sim_set_slot_callback(const struct ofono_error *error, void *data)
{
struct ofono_sim *sim = data;
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = __ofono_atom_get_path(sim->atom);
DBusMessage *reply;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error setting radio access mode");
sim->pending_active_card_slot = sim->active_card_slot;
reply = __ofono_error_from_error(error, sim->pending);
__ofono_dbus_pending_reply(&sim->pending, reply);
return;
}
sim->active_card_slot = sim->pending_active_card_slot;
reply = dbus_message_new_method_return(sim->pending);
__ofono_dbus_pending_reply(&sim->pending, reply);
ofono_dbus_signal_property_changed(conn, path,
OFONO_SIM_MANAGER_INTERFACE,
"ActiveCardSlot",
DBUS_TYPE_UINT32,
&sim->active_card_slot);
}
static DBusMessage *sim_set_property(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -753,6 +873,37 @@ error:
if (set_ok)
return NULL;
} else if (!strcmp(name, "ActiveCardSlot")) {
dbus_uint32_t value;
dbus_message_iter_next(&iter);
if (sim->driver->set_active_card_slot == NULL)
return __ofono_error_not_implemented(msg);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
return __ofono_error_invalid_args(msg);
dbus_message_iter_recurse(&iter, &var);
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_UINT32)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &value);
if (value <= 0 || value > sim->card_slot_count)
return __ofono_error_invalid_args(msg);
if (sim->active_card_slot == value)
return dbus_message_new_method_return(msg);
sim->pending = dbus_message_ref(msg);
sim->pending_active_card_slot = value;
sim->driver->set_active_card_slot(sim, value - 1,
sim_set_slot_callback,
sim);
return NULL;
}
return __ofono_error_invalid_args(msg);
@@ -785,6 +936,11 @@ static void sim_locked_cb(struct ofono_sim *sim, gboolean locked)
OFONO_SIM_MANAGER_INTERFACE,
"LockedPins", DBUS_TYPE_STRING,
&locked_pins);
/* Cache pin only for SIM PIN type */
if (g_strcmp0(typestr, "pin") == 0)
pin_cache_update(sim->iccid, pin);
g_strfreev(locked_pins);
sim_pin_retries_check(sim);
@@ -886,6 +1042,14 @@ static DBusMessage *sim_unlock_pin(DBusConnection *conn, DBusMessage *msg,
static void sim_change_pin_cb(const struct ofono_error *error, void *data)
{
struct ofono_sim *sim = data;
const char *typestr;
const char *old;
const char *new;
dbus_message_get_args(sim->pending, NULL, DBUS_TYPE_STRING, &typestr,
DBUS_TYPE_STRING, &old,
DBUS_TYPE_STRING, &new,
DBUS_TYPE_INVALID);
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
__ofono_dbus_pending_reply(&sim->pending,
@@ -896,6 +1060,10 @@ static void sim_change_pin_cb(const struct ofono_error *error, void *data)
return;
}
/* Cache pin only for SIM PIN type */
if (g_strcmp0(typestr, "pin") == 0)
pin_cache_update(sim->iccid, new);
__ofono_dbus_pending_reply(&sim->pending,
dbus_message_new_method_return(sim->pending));
@@ -950,8 +1118,14 @@ static DBusMessage *sim_change_pin(DBusConnection *conn, DBusMessage *msg,
static void sim_enter_pin_cb(const struct ofono_error *error, void *data)
{
struct ofono_sim *sim = data;
const char *typestr;
const char *pin;
DBusMessage *reply;
dbus_message_get_args(sim->pending, NULL, DBUS_TYPE_STRING, &typestr,
DBUS_TYPE_STRING, &pin,
DBUS_TYPE_INVALID);
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
reply = __ofono_error_failed(sim->pending);
else
@@ -963,6 +1137,10 @@ static void sim_enter_pin_cb(const struct ofono_error *error, void *data)
if (sim->initialized || error->type != OFONO_ERROR_TYPE_NO_ERROR)
goto recheck;
/* Cache pin only for SIM PIN type */
if (g_strcmp0(typestr, "pin") == 0)
pin_cache_update(sim->iccid, pin);
if (sim->pin_type == OFONO_SIM_PASSWORD_SIM_PIN ||
sim->pin_type == OFONO_SIM_PASSWORD_SIM_PUK) {
sim->wait_initialized = true;
@@ -2918,6 +3096,8 @@ void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PIN2] = -1;
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PUK2] = -1;
pin_cache_remove(sim->iccid);
sim_free_state(sim);
}
}
@@ -3191,7 +3371,8 @@ static void sim_pin_query_cb(const struct ofono_error *error,
struct ofono_sim *sim = data;
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = __ofono_atom_get_path(sim->atom);
const char *pin_name;
struct cached_pin *cpins = pin_cache_lookup(sim->iccid);
const char *pin_name = sim_passwd_name(pin_type);
char **locked_pins;
gboolean lock_changed;
@@ -3204,7 +3385,6 @@ static void sim_pin_query_cb(const struct ofono_error *error,
if (sim->pin_type != pin_type) {
sim->pin_type = pin_type;
pin_name = sim_passwd_name(pin_type);
if (pin_type != OFONO_SIM_PASSWORD_NONE &&
password_is_pin(pin_type) == FALSE)
@@ -3235,6 +3415,10 @@ static void sim_pin_query_cb(const struct ofono_error *error,
&pin_name);
}
if (g_strcmp0(pin_name, "pin") == 0 && cpins != NULL)
sim->driver->send_passwd(sim, cpins->pin,
pin_cache_enter_cb, sim);
switch (pin_type) {
case OFONO_SIM_PASSWORD_NONE:
case OFONO_SIM_PASSWORD_SIM_PIN2:
@@ -3279,21 +3463,56 @@ void __ofono_sim_recheck_pin(struct ofono_sim *sim)
int ofono_sim_driver_register(const struct ofono_sim_driver *d)
{
DBG("driver: %p, name: %s", d, d->name);
return ofono_sim_driver_register_version(d, 1);
}
int ofono_sim_driver_register_version(const struct ofono_sim_driver *d, int v)
{
struct ofono_sim_driver_data *dd;
DBG("driver: %p, v: %d, name: %s", d, v, d->name);
if (d->probe == NULL)
return -EINVAL;
g_drivers = g_slist_prepend(g_drivers, (void *) d);
/* Pad struct ofono_sim_driver with zeros if necessary */
dd = g_new0(struct ofono_sim_driver_data, 1);
dd->d = d;
switch (v) {
case 0:
memcpy(dd, d, G_STRUCT_OFFSET(struct ofono_sim_driver,
open_channel2));
break;
case 1:
memcpy(dd, d, G_STRUCT_OFFSET(struct ofono_sim_driver,
set_active_card_slot));
break;
default:
memcpy(dd, d, sizeof(*d));
break;
}
g_drivers = g_slist_prepend(g_drivers, dd);
return 0;
}
void ofono_sim_driver_unregister(const struct ofono_sim_driver *d)
{
GSList *l;
DBG("driver: %p, name: %s", d, d->name);
g_drivers = g_slist_remove(g_drivers, (void *) d);
for (l = g_drivers; l; l = l->next) {
struct ofono_sim_driver_data *dd = l->data;
if (dd->d == d) {
g_drivers = g_slist_delete_link(g_drivers, l);
g_free(dd);
break;
}
}
}
static void emulator_remove_handler(struct ofono_atom *atom, void *data)
@@ -3377,6 +3596,9 @@ struct ofono_sim *ofono_sim_create(struct ofono_modem *modem,
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
sim->pin_retries[i] = -1;
sim->active_card_slot = 1;
sim->card_slot_count = 1;
for (l = g_drivers; l; l = l->next) {
const struct ofono_sim_driver *drv = l->data;
@@ -3475,6 +3697,14 @@ void ofono_sim_register(struct ofono_sim *sim)
__ofono_atom_register(sim->atom, sim_unregister);
}
void __ofono_sim_clear_cached_pins(struct ofono_sim *sim)
{
if (cached_pins == NULL)
return;
pin_cache_remove(sim->iccid);
}
void ofono_sim_remove(struct ofono_sim *sim)
{
__ofono_atom_free(sim->atom);
@@ -3890,3 +4120,15 @@ int ofono_sim_logical_access(struct ofono_sim *sim, int session_id,
return 0;
}
void ofono_sim_set_card_slot_count(struct ofono_sim *sim, unsigned int val)
{
if (sim)
sim->card_slot_count = val;
}
void ofono_sim_set_active_card_slot(struct ofono_sim *sim, unsigned int val)
{
if (sim)
sim->active_card_slot = val;
}

View File

@@ -85,6 +85,19 @@ struct sms_filter_chain_send_text {
struct ofono_sms_address addr;
};
struct sms_filter_chain_send_datagram {
struct sms_filter_message message;
sms_send_datagram_cb_t send;
ofono_destroy_func destroy;
void *data;
int dst_port;
int src_port;
unsigned char *bytes;
unsigned int len;
int flags;
struct ofono_sms_address addr;
};
struct sms_filter_chain_recv_text {
struct sms_filter_message message;
sms_dispatch_recv_text_cb_t default_handler;
@@ -445,6 +458,140 @@ static struct sms_filter_message *sms_filter_send_text_new
return &send_msg->message;
}
/* sms_filter_chain_send_datagram */
static inline struct sms_filter_chain_send_datagram
*sms_filter_chain_send_datagram_cast
(struct sms_filter_message *msg)
{
return CAST(msg, struct sms_filter_chain_send_datagram, message);
}
static gboolean sms_filter_chain_send_datagram_can_process
(const struct ofono_sms_filter *filter)
{
return filter->filter_send_datagram != NULL;
}
static void sms_datagram_set_bytes(
struct sms_filter_chain_send_datagram *msg,
const unsigned char *bytes, unsigned int len)
{
msg->bytes = g_malloc0(sizeof(unsigned char) * len);
memcpy(msg->bytes, bytes, len);
msg->len = len;
}
static void sms_filter_chain_send_datagram_process_cb
(enum ofono_sms_filter_result res,
const struct ofono_sms_address *addr,
int dst_port, int src_port,
const unsigned char *bytes,
unsigned int len, void *data)
{
struct sms_filter_chain_send_datagram *msg = data;
if (res != OFONO_SMS_FILTER_DROP) {
/* Update the message */
if (&msg->addr != addr) {
msg->addr = *addr;
}
if (msg->bytes != bytes) {
g_free(msg->bytes);
sms_datagram_set_bytes(msg, bytes, len);
}
msg->dst_port = dst_port;
msg->src_port = src_port;
}
sms_filter_message_processed(&msg->message, res);
}
static guint sms_filter_chain_send_datagram_process
(const struct ofono_sms_filter *filter,
struct sms_filter_message *msg)
{
struct sms_filter_chain_send_datagram *send_msg =
sms_filter_chain_send_datagram_cast(msg);
struct sms_filter_chain *chain = msg->chain;
return filter->filter_send_datagram(chain->modem, &send_msg->addr,
send_msg->dst_port, send_msg->src_port,
send_msg->bytes, send_msg->len,
sms_filter_chain_send_datagram_process_cb,
send_msg);
}
static void sms_filter_chain_send_datagram_passthrough
(struct sms_filter_message *msg)
{
struct sms_filter_chain_send_datagram *send_msg =
sms_filter_chain_send_datagram_cast(msg);
if (send_msg->send) {
struct sms_filter_chain *chain = msg->chain;
struct sms_address addr;
sms_filter_convert_sms_address_back(&addr, &send_msg->addr);
send_msg->send(chain->sms, &addr, send_msg->dst_port,
send_msg->src_port, send_msg->bytes,
send_msg->len, send_msg->flags,
send_msg->data);
}
}
static void sms_filter_chain_send_datagram_destroy
(struct sms_filter_message *msg)
{
struct sms_filter_chain_send_datagram *send_msg =
sms_filter_chain_send_datagram_cast(msg);
if (send_msg->destroy) {
send_msg->destroy(send_msg->data);
}
}
static void sms_filter_chain_send_datagram_free
(struct sms_filter_message *msg)
{
struct sms_filter_chain_send_datagram *send_msg =
sms_filter_chain_send_datagram_cast(msg);
g_free(send_msg->bytes);
g_free(send_msg);
}
static struct sms_filter_message *sms_filter_send_datagram_new
(struct sms_filter_chain *chain, const struct sms_address *addr,
int dst_port, int src_port, unsigned char *bytes,
unsigned int len, int flags, sms_send_datagram_cb_t send,
void *data, ofono_destroy_func destroy)
{
static const struct sms_filter_message_fn send_datagram_fn = {
.name = "outgoing SMS data message",
.can_process = sms_filter_chain_send_datagram_can_process,
.process = sms_filter_chain_send_datagram_process,
.passthrough = sms_filter_chain_send_datagram_passthrough,
.destroy = sms_filter_chain_send_datagram_destroy,
.free = sms_filter_chain_send_datagram_free
};
struct sms_filter_chain_send_datagram *send_msg =
g_new0(struct sms_filter_chain_send_datagram, 1);
sms_filter_message_init(&send_msg->message, chain, &send_datagram_fn);
sms_filter_convert_sms_address(&send_msg->addr, addr);
send_msg->send = send;
send_msg->destroy = destroy;
send_msg->data = data;
sms_datagram_set_bytes(send_msg, bytes, len);
send_msg->dst_port = dst_port;
send_msg->src_port = src_port;
send_msg->flags = flags;
return &send_msg->message;
}
/* sms_filter_chain_recv_text */
static inline struct sms_filter_chain_recv_text *
@@ -711,6 +858,30 @@ void __ofono_sms_filter_chain_send_text(struct sms_filter_chain *chain,
}
}
void __ofono_sms_filter_chain_send_datagram(struct sms_filter_chain *chain,
const struct sms_address *addr, int dstport,
int srcport, unsigned char *bytes, int len,
int flags, sms_send_datagram_cb_t sender,
ofono_destroy_func destroy, void *data)
{
if (chain) {
if (sms_filter_list) {
sms_filter_message_process
(sms_filter_send_datagram_new(chain, addr,
dstport, srcport, bytes, len,
flags, sender, data, destroy));
return;
}
if (sender) {
sender(chain->sms, addr, dstport, srcport, bytes, len,
flags, data);
}
}
if (destroy) {
destroy(data);
}
}
/* Does g_free(buf) when done */
void __ofono_sms_filter_chain_recv_datagram(struct sms_filter_chain *chain,
const struct ofono_uuid *uuid, int dst_port, int src_port,

View File

@@ -3,7 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2015-2021 Jolla Ltd.
* Copyright (C) 2015-2022 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
@@ -1043,6 +1043,64 @@ static void sms_send_message_submit(struct ofono_sms *sms,
message->pending = NULL;
}
static void sms_send_data_message_submit(struct ofono_sms *sms,
const struct sms_address *addr, int dstport,
int srcport, unsigned char *bytes, unsigned int len,
int flags, void *data)
{
struct sms_message_data *message = data;
const char *to = sms_address_to_string(addr);
GSList *msg_list = NULL;
gboolean use_16bit_ref = FALSE;
gboolean use_delivery_reports;
int err;
struct ofono_uuid uuid;
enum ofono_sms_submit_flag submit_flags;
enum sms_datagram_endianess endianess = SMS_DATAGRAM_ENDIANESS_GSM;
if (bytes == NULL) {
__ofono_dbus_pending_reply(&message->pending,
__ofono_error_invalid_format(message->pending));
return;
}
if (flags & OFONO_SMS_DATA_FLAG_USE_LITTLE_ENDIAN)
endianess = SMS_DATAGRAM_ENDIANESS_LITTLE_ENDIAN;
use_delivery_reports = flags & OFONO_SMS_DATA_FLAG_DELIVERY_REPORT;
msg_list = sms_datagram_prepare_with_endianess(to, bytes, len, sms->ref,
use_16bit_ref, srcport, dstport, TRUE,
use_delivery_reports, endianess);
if (msg_list == NULL) {
__ofono_dbus_pending_reply(&message->pending,
__ofono_error_invalid_format(message->pending));
return;
}
submit_flags = OFONO_SMS_SUBMIT_FLAG_RETRY;
submit_flags |= OFONO_SMS_SUBMIT_FLAG_EXPOSE_DBUS;
if (use_delivery_reports)
submit_flags |= OFONO_SMS_SUBMIT_FLAG_REQUEST_SR;
err = __ofono_sms_txq_submit(sms, msg_list, submit_flags, &uuid,
message_queued, message->pending);
g_slist_free_full(msg_list, g_free);
if (err < 0) {
__ofono_dbus_pending_reply(&message->pending,
__ofono_error_failed(message->pending));
return;
}
/* Ownership has been transfered to the message queue */
message->pending = NULL;
DBG("SMS data sent");
}
static void sms_send_message_destroy(void *data)
{
struct sms_message_data *message = data;
@@ -1099,6 +1157,49 @@ static DBusMessage *sms_send_message(DBusConnection *conn, DBusMessage *msg,
return NULL;
}
static DBusMessage *sms_send_data_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ofono_sms *sms = data;
const char *to;
unsigned char *bytes = NULL;
struct sms_message_data *message;
struct sms_address addr;
dbus_int32_t srcport;
dbus_int32_t dstport;
dbus_uint32_t flags;
int len;
if (!ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
OFONO_DBUS_ACCESS_INTF_MESSAGEMGR,
OFONO_DBUS_ACCESS_MESSAGEMGR_SEND_DATA_MESSAGE, NULL))
return __ofono_error_access_denied(msg);
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &to,
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
&bytes, &len,
DBUS_TYPE_INT32, &srcport,
DBUS_TYPE_INT32, &dstport,
DBUS_TYPE_UINT32, &flags,
DBUS_TYPE_INVALID))
return __ofono_error_invalid_args(msg);
if (valid_phone_number_format(to) == FALSE)
return __ofono_error_invalid_format(msg);
message = g_new0(struct sms_message_data, 1);
message->pending = dbus_message_ref(msg);
sms_address_from_string(&addr, to);
__ofono_sms_filter_chain_send_datagram(sms->filter_chain, &addr,
dstport, srcport, bytes, len, flags,
sms_send_data_message_submit,
sms_send_message_destroy, message);
return NULL;
}
static DBusMessage *sms_get_messages(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -1216,6 +1317,15 @@ static const GDBusMethodTable sms_manager_methods[] = {
GDBUS_ARGS({ "to", "s" }, { "text", "s" }),
GDBUS_ARGS({ "path", "o" }),
sms_send_message) },
{ GDBUS_ASYNC_METHOD("SendDataMessage",
GDBUS_ARGS(
{ "to", "s" },
{ "data", "ay" },
{ "srcport", "i"},
{ "dstport", "i"},
{ "flags", "u"}),
GDBUS_ARGS({ "path", "o" }),
sms_send_data_message) },
{ GDBUS_METHOD("GetMessages",
NULL, GDBUS_ARGS({ "messages", "a(oa{sv})" }),
sms_get_messages) },

View File

@@ -628,6 +628,10 @@ gboolean sms_decode_address_field(const unsigned char *pdu, int len,
if (!next_octet(pdu, len, offset, &addr_len))
return FALSE;
/* According to 23.040 9.1.2.5 Address-Length must not exceed 20 */
if (addr_len > 20)
return FALSE;
if (sc && addr_len == 0) {
out->address[0] = '\0';
return TRUE;
@@ -941,10 +945,16 @@ static gboolean decode_submit_report(const unsigned char *pdu, int len,
return FALSE;
if (out->type == SMS_TYPE_SUBMIT_REPORT_ERROR) {
if (expected > (int) sizeof(out->submit_err_report.ud))
return FALSE;
out->submit_err_report.udl = udl;
memcpy(out->submit_err_report.ud,
pdu + offset, expected);
} else {
if (expected > (int) sizeof(out->submit_ack_report.ud))
return FALSE;
out->submit_ack_report.udl = udl;
memcpy(out->submit_ack_report.ud,
pdu + offset, expected);
@@ -3423,19 +3433,21 @@ static inline GSList *sms_list_append(GSList *l, const struct sms *in)
}
/*
* Prepares a datagram for transmission. Breaks up into fragments if
* necessary using ref as the concatenated message reference number.
* Prepares a datagram for transmission with requested endianess Breaks up
* into fragments if necessary using ref as the concatenated message reference
* number.
* Returns a list of sms messages in order.
*
* @use_delivery_reports: value for the Status-Report-Request field
* (23.040 3.2.9, 9.2.2.2)
*/
GSList *sms_datagram_prepare(const char *to,
GSList *sms_datagram_prepare_with_endianess(const char *to,
const unsigned char *data, unsigned int len,
guint16 ref, gboolean use_16bit_ref,
unsigned short src, unsigned short dst,
gboolean use_16bit_port,
gboolean use_delivery_reports)
gboolean use_delivery_reports,
enum sms_datagram_endianess endianess)
{
struct sms template;
unsigned int offset;
@@ -3462,10 +3474,22 @@ GSList *sms_datagram_prepare(const char *to,
template.submit.ud[0] += 6;
template.submit.ud[offset] = SMS_IEI_APPLICATION_ADDRESS_16BIT;
template.submit.ud[offset + 1] = 4;
template.submit.ud[offset + 2] = (dst & 0xff00) >> 8;
template.submit.ud[offset + 3] = dst & 0xff;
template.submit.ud[offset + 4] = (src & 0xff00) >> 8;
template.submit.ud[offset + 5] = src & 0xff;
switch (endianess) {
case SMS_DATAGRAM_ENDIANESS_GSM:
case SMS_DATAGRAM_ENDIANESS_BIG_ENDIAN:
template.submit.ud[offset + 2] = (dst & 0xff00) >> 8;
template.submit.ud[offset + 3] = dst & 0xff;
template.submit.ud[offset + 4] = (src & 0xff00) >> 8;
template.submit.ud[offset + 5] = src & 0xff;
break;
case SMS_DATAGRAM_ENDIANESS_LITTLE_ENDIAN:
template.submit.ud[offset + 2] = dst & 0xff;
template.submit.ud[offset + 3] = (dst & 0xff00) >> 8;
template.submit.ud[offset + 4] = src & 0xff;
template.submit.ud[offset + 5] = (src & 0xff00) >> 8;
break;
}
offset += 6;
} else {
@@ -3489,8 +3513,18 @@ GSList *sms_datagram_prepare(const char *to,
template.submit.ud[0] += 6;
template.submit.ud[offset] = SMS_IEI_CONCATENATED_16BIT;
template.submit.ud[offset + 1] = 4;
template.submit.ud[offset + 2] = (ref & 0xff00) >> 8;
template.submit.ud[offset + 3] = ref & 0xff;
switch (endianess) {
case SMS_DATAGRAM_ENDIANESS_GSM:
case SMS_DATAGRAM_ENDIANESS_BIG_ENDIAN:
template.submit.ud[offset + 2] = (ref & 0xff00) >> 8;
template.submit.ud[offset + 3] = ref & 0xff;
break;
case SMS_DATAGRAM_ENDIANESS_LITTLE_ENDIAN:
template.submit.ud[offset + 2] = ref & 0xff;
template.submit.ud[offset + 3] = (ref & 0xff00) >> 8;
break;
}
offset += 6;
} else {
@@ -3548,6 +3582,28 @@ GSList *sms_datagram_prepare(const char *to,
return r;
}
/*
* Prepares a datagram for transmission Breaks up into fragments if
* necessary using ref as the concatenated message reference number.
* Returns a list of sms messages in order.
*
* @use_delivery_reports: value for the Status-Report-Request field
* (23.040 3.2.9, 9.2.2.2)
*/
GSList *sms_datagram_prepare(const char *to,
const unsigned char *data, unsigned int len,
guint16 ref, gboolean use_16bit_ref,
unsigned short src, unsigned short dst,
gboolean use_16bit_port,
gboolean use_delivery_reports)
{
return sms_datagram_prepare_with_endianess(to, data, len, ref,
use_16bit_ref, src, dst,
use_16bit_port, use_delivery_reports,
SMS_DATAGRAM_ENDIANESS_GSM);
}
/*
* Prepares the text for transmission. Breaks up into fragments if
* necessary using ref as the concatenated message reference number.
@@ -4547,13 +4603,11 @@ out:
GSList *cbs_optimize_ranges(GSList *ranges)
{
struct cbs_topic_range *range;
unsigned char bitmap[125];
unsigned char *bitmap = g_malloc0(CBS_MAX_TOPIC / 8 + 1);
GSList *l;
unsigned short i;
GSList *ret = NULL;
memset(bitmap, 0, sizeof(bitmap));
for (l = ranges; l; l = l->next) {
range = l->data;
@@ -4567,7 +4621,7 @@ GSList *cbs_optimize_ranges(GSList *ranges)
range = NULL;
for (i = 0; i <= 999; i++) {
for (i = 0; i <= CBS_MAX_TOPIC; i++) {
int byte_offset = i / 8;
int bit = i % 8;
@@ -4595,6 +4649,7 @@ GSList *cbs_optimize_ranges(GSList *ranges)
ret = g_slist_reverse(ret);
g_free(bitmap);
return ret;
}
@@ -4607,10 +4662,10 @@ GSList *cbs_extract_topic_ranges(const char *ranges)
GSList *tmp;
while (next_range(ranges, &offset, &min, &max) == TRUE) {
if (min < 0 || min > 999)
if (min < 0 || min > CBS_MAX_TOPIC)
return NULL;
if (max < 0 || max > 999)
if (max < 0 || max > CBS_MAX_TOPIC)
return NULL;
if (max < min)

View File

@@ -23,6 +23,7 @@
#include <ofono/types.h>
#define CBS_MAX_GSM_CHARS 93
#define CBS_MAX_TOPIC 9999
#define SMS_MSGID_LEN 20
enum sms_type {
@@ -229,6 +230,12 @@ enum cbs_geo_scope {
CBS_GEO_SCOPE_CELL_NORMAL
};
enum sms_datagram_endianess {
SMS_DATAGRAM_ENDIANESS_GSM,
SMS_DATAGRAM_ENDIANESS_BIG_ENDIAN,
SMS_DATAGRAM_ENDIANESS_LITTLE_ENDIAN
};
struct sms_address {
enum sms_number_type number_type;
enum sms_numbering_plan numbering_plan;
@@ -574,6 +581,14 @@ GSList *sms_datagram_prepare(const char *to,
gboolean use_16bit_port,
gboolean use_delivery_reports);
GSList *sms_datagram_prepare_with_endianess(const char *to,
const unsigned char *data, unsigned int len,
guint16 ref, gboolean use_16bit_ref,
unsigned short src, unsigned short dst,
gboolean use_16bit_port,
gboolean use_delivery_reports,
enum sms_datagram_endianess endianess);
gboolean cbs_dcs_decode(guint8 dcs, gboolean *udhi, enum sms_class *cls,
enum sms_charset *charset, gboolean *compressed,
enum cbs_language *language, gboolean *iso639);

View File

@@ -1738,11 +1738,7 @@ static int voicecall_dial(struct ofono_voicecall *vc, const char *number,
string_to_phone_number(number, &ph);
/* No filtering for emergency calls */
if (is_emergency_number(vc, number))
vc->driver->dial(vc, &ph, clir, cb, vc);
else
dial_filter(vc, &ph, clir, cb, vc);
dial_filter(vc, &ph, clir, cb, vc);
return 0;
}
@@ -2669,9 +2665,9 @@ void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id,
if (l) {
/* Incoming call was disconnected in the process of being
* filtered. voicecall_destroy cancels it. */
voicecall_destroy(l->data);
vc->incoming_filter_list = g_slist_delete_link
(vc->incoming_filter_list, l);
voicecall_destroy(l->data);
return;
}
@@ -4262,14 +4258,10 @@ static void dial_request(struct ofono_voicecall *vc)
struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom);
__ofono_modem_inc_emergency_mode(modem);
/* No filtering for emergency calls */
vc->driver->dial(vc, &vc->dial_req->ph,
OFONO_CLIR_OPTION_DEFAULT, dial_request_cb, vc);
} else {
dial_filter(vc, &vc->dial_req->ph, OFONO_CLIR_OPTION_DEFAULT,
dial_request_cb, vc);
}
dial_filter(vc, &vc->dial_req->ph, OFONO_CLIR_OPTION_DEFAULT,
dial_request_cb, vc);
}
static void dial_req_disconnect_cb(const struct ofono_error *error, void *data)

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017-2021 Jolla Ltd.
* Copyright (C) 2017-2022 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -41,6 +41,7 @@ struct ofono_watch_object {
guint imsi_watch_id;
guint spn_watch_id;
guint netreg_watch_id;
guint netreg_status_watch_id;
guint gprs_watch_id;
};
@@ -67,6 +68,7 @@ enum ofono_watch_signal {
SIGNAL_REG_MCC_CHANGED,
SIGNAL_REG_MNC_CHANGED,
SIGNAL_REG_NAME_CHANGED,
SIGNAL_REG_TECH_CHANGED,
SIGNAL_GPRS_CHANGED,
SIGNAL_GPRS_SETTINGS_CHANGED,
SIGNAL_COUNT
@@ -84,6 +86,7 @@ enum ofono_watch_signal {
#define SIGNAL_REG_MCC_CHANGED_NAME "ofono-watch-reg-mcc-changed"
#define SIGNAL_REG_MNC_CHANGED_NAME "ofono-watch-reg-mnc-changed"
#define SIGNAL_REG_NAME_CHANGED_NAME "ofono-watch-reg-name-changed"
#define SIGNAL_REG_TECH_CHANGED_NAME "ofono-watch-reg-tech-changed"
#define SIGNAL_GPRS_CHANGED_NAME "ofono-watch-gprs-changed"
#define SIGNAL_GPRS_SETTINGS_CHANGED_NAME "ofono-watch-gprs-settings-changed"
@@ -134,11 +137,13 @@ static void ofono_watch_emit_queued_signals(struct ofono_watch_object *self)
{
int i;
g_object_ref(self);
for (i = 0; self->queued_signals && i < SIGNAL_COUNT; i++) {
if (self->queued_signals & ofono_watch_signal_bit(i)) {
ofono_watch_signal_emit(self, i);
}
}
g_object_unref(self);
}
static void ofono_watch_iccid_update(struct ofono_watch_object *self,
@@ -349,6 +354,7 @@ static void ofono_watch_netreg_update(struct ofono_watch_object *self)
struct ofono_watch *watch = &self->pub;
struct ofono_netreg *netreg = watch->netreg;
enum ofono_netreg_status status = ofono_netreg_get_status(netreg);
enum ofono_access_technology act = ofono_netreg_get_technology(netreg);
const char *mcc = ofono_netreg_get_mcc(netreg);
const char *mnc = ofono_netreg_get_mnc(netreg);
const char *name = ofono_netreg_get_name(netreg);
@@ -357,6 +363,10 @@ static void ofono_watch_netreg_update(struct ofono_watch_object *self)
watch->reg_status = status;
ofono_watch_signal_queue(self, SIGNAL_REG_STATUS_CHANGED);
}
if (watch->reg_tech != act) {
watch->reg_tech = act;
ofono_watch_signal_queue(self, SIGNAL_REG_TECH_CHANGED);
}
if (g_strcmp0(self->reg_mcc, mcc)) {
g_free(self->reg_mcc);
watch->reg_mcc = self->reg_mcc = g_strdup(mcc);
@@ -374,17 +384,49 @@ static void ofono_watch_netreg_update(struct ofono_watch_object *self)
}
}
static void ofono_watch_netreg_status_notify(int status, int lac, int ci,
int tech, const char *mcc, const char *mnc, void *user_data)
{
struct ofono_watch_object *self = OFONO_WATCH_OBJECT(user_data);
ofono_watch_netreg_update(self);
ofono_watch_emit_queued_signals(self);
}
static void ofono_watch_netreg_status_destroy(void *user_data)
{
struct ofono_watch_object *self = OFONO_WATCH_OBJECT(user_data);
ASSERT(self->netreg_status_watch_id);
self->netreg_status_watch_id = 0;
}
static void ofono_watch_set_netreg(struct ofono_watch_object *self,
struct ofono_netreg *netreg)
{
struct ofono_watch *watch = &self->pub;
if (watch->netreg != netreg) {
if (self->netreg_status_watch_id) {
__ofono_netreg_remove_status_watch(watch->netreg,
self->netreg_status_watch_id);
/* The destroy callback clears it */
ASSERT(!self->netreg_status_watch_id);
}
watch->netreg = netreg;
ofono_watch_signal_queue(self, SIGNAL_NETREG_CHANGED);
if (netreg) {
self->netreg_status_watch_id =
__ofono_netreg_add_status_watch(netreg,
ofono_watch_netreg_status_notify, self,
ofono_watch_netreg_status_destroy);
}
ofono_watch_netreg_update(self);
ofono_watch_emit_queued_signals(self);
}
ofono_watch_netreg_update(self);
ofono_watch_emit_queued_signals(self);
}
static void ofono_watch_netreg_notify(struct ofono_atom *atom,
@@ -417,6 +459,7 @@ static void ofono_watch_set_gprs(struct ofono_watch_object *self,
if (watch->gprs != gprs) {
watch->gprs = gprs;
ofono_watch_signal_queue(self, SIGNAL_GPRS_CHANGED);
ofono_watch_emit_queued_signals(self);
}
@@ -730,6 +773,7 @@ ADD_SIGNAL_HANDLER_PROC(reg_status,REG_STATUS)
ADD_SIGNAL_HANDLER_PROC(reg_mcc,REG_MCC)
ADD_SIGNAL_HANDLER_PROC(reg_mnc,REG_MNC)
ADD_SIGNAL_HANDLER_PROC(reg_name,REG_NAME)
ADD_SIGNAL_HANDLER_PROC(reg_tech,REG_TECH)
ADD_SIGNAL_HANDLER_PROC(gprs,GPRS)
static void ofono_watch_gprs_settings_signal_cb(struct ofono_watch_object *src,
@@ -775,21 +819,6 @@ void ofono_watch_remove_handlers(struct ofono_watch *watch, unsigned long *ids,
}
}
void __ofono_watch_netreg_changed(const char *path)
{
if (path && ofono_watch_table) {
struct ofono_watch_object *self =
g_hash_table_lookup(ofono_watch_table, path);
if (self) {
g_object_ref(self);
ofono_watch_netreg_update(self);
ofono_watch_emit_queued_signals(self);
g_object_unref(self);
}
}
}
void __ofono_watch_gprs_settings_changed(const char *path,
enum ofono_gprs_context_type type,
const struct ofono_gprs_primary_context *settings)
@@ -813,6 +842,7 @@ static void ofono_watch_object_init(struct ofono_watch_object *self)
struct ofono_watch *watch = &self->pub;
watch->reg_status = OFONO_NETREG_STATUS_NONE;
watch->reg_tech = OFONO_ACCESS_TECHNOLOGY_NONE;
}
static void ofono_watch_object_finalize(GObject *object)
@@ -847,6 +877,7 @@ static void ofono_watch_object_class_init(OfonoWatchObjectClass *klass)
NEW_SIGNAL(klass, REG_MCC);
NEW_SIGNAL(klass, REG_MNC);
NEW_SIGNAL(klass, REG_NAME);
NEW_SIGNAL(klass, REG_TECH);
NEW_SIGNAL(klass, GPRS);
ofono_watch_signals[SIGNAL_GPRS_SETTINGS_CHANGED] =
g_signal_new(SIGNAL_GPRS_SETTINGS_CHANGED_NAME,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2019-2022 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,7 +18,6 @@
#include <ofono/watch.h>
void __ofono_watch_netreg_changed(const char *path);
void __ofono_watch_gprs_settings_changed(const char *path,
enum ofono_gprs_context_type type,
const struct ofono_gprs_primary_context *settings);

View File

@@ -4,7 +4,8 @@ import sys
import dbus
if (len(sys.argv) < 2):
print("Usage: %s [modem] <number> [hide_callerid]" % (sys.argv[0]))
print("Usage: %s [modem] <number> [enabled|disabled|default]" % (sys.argv[0]))
print("Last argument enables/disables callerid")
sys.exit(1)
bus = dbus.SystemBus()

View File

@@ -92,9 +92,9 @@ def set_topics(cbs):
break
if topicTemp:
if int(topicTemp) > 999:
if int(topicTemp) > 9999:
invalidData = True
print("Invalid Topic ID %s (range 0-999). \
print("Invalid Topic ID %s (range 0-9999). \
\nCould not register." % topicTemp)
index = index + 1

View File

@@ -318,6 +318,28 @@ static struct ofono_cell *test_cell_init_lte(struct ofono_cell *cell)
return cell;
}
static struct ofono_cell *test_cell_init_nr(struct ofono_cell *cell)
{
struct ofono_cell_info_nr *nr = &cell->info.nr;
memset(cell, 0, sizeof(*cell));
cell->type = OFONO_CELL_TYPE_NR;
cell->registered = TRUE;
nr->mcc = 244;
nr->mnc = 91;
nr->nci = 36591883;
nr->pci = 309;
nr->tac = 4030;
nr->nrarfcn = INT_MAX;
nr->ssRsrp = 106;
nr->ssRsrq = 6;
nr->ssSinr = INT_MAX;
nr->csiRsrp = 106;
nr->csiRsrq = 6;
nr->csiSinr = INT_MAX;
return cell;
}
/* ==== Misc ==== */
static void test_misc(void)
@@ -540,6 +562,13 @@ static void test_get_all4(void)
{
struct ofono_cell cell;
test_get_all(test_cell_init_nr(&cell), "nr");
}
static void test_get_all5(void)
{
struct ofono_cell cell;
/* Invalid cell */
memset(&cell, 0xff, sizeof(cell));
test_get_all(&cell, "unknown");
@@ -1145,6 +1174,7 @@ int main(int argc, char *argv[])
g_test_add_func(TEST_("GetAll2"), test_get_all2);
g_test_add_func(TEST_("GetAll3"), test_get_all3);
g_test_add_func(TEST_("GetAll4"), test_get_all4);
g_test_add_func(TEST_("GetAll5"), test_get_all5);
g_test_add_func(TEST_("GetInterfaceVersion"), test_get_version);
g_test_add_func(TEST_("GetType"), test_get_type);
g_test_add_func(TEST_("GetRegistered"), test_get_registered);

View File

@@ -226,6 +226,35 @@ static void test_compare(void)
c2 = c1; c2.info.lte.timingAdvance++;
g_assert(!ofono_cell_compare_location(&c1, &c2));
/* NR */
c1.type = OFONO_CELL_TYPE_NR;
c2 = c1;
g_assert(!ofono_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.nr.mcc++;
g_assert(ofono_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.nr.mnc++;
g_assert(ofono_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.nr.nci++;
g_assert(ofono_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.nr.pci++;
g_assert(ofono_cell_compare_location(&c1, &c2) < 0);
c2 = c1; c2.info.nr.tac++;
g_assert(ofono_cell_compare_location(&c1, &c2) < 0);
/* Other attributes are not being compared */
c2 = c1; c2.info.nr.nrarfcn++;
g_assert(!ofono_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.nr.ssRsrp++;
g_assert(!ofono_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.nr.ssRsrq++;
g_assert(!ofono_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.nr.ssSinr++;
g_assert(!ofono_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.nr.csiRsrp++;
g_assert(!ofono_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.nr.csiRsrq++;
g_assert(!ofono_cell_compare_location(&c1, &c2));
c2 = c1; c2.info.nr.csiSinr++;
g_assert(!ofono_cell_compare_location(&c1, &c2));
/* Unknown type */
c1.type = c2.type = (enum ofono_cell_type)-1;
g_assert(!ofono_cell_compare_location(&c1, &c2));

View File

@@ -75,6 +75,7 @@ static void test_merge1(const char *conf, const char *conf1, const char *out)
char *file1 = g_strconcat(subdir, "/bar.conf", NULL);
GKeyFile *k = g_key_file_new();
char *data;
char *out_stripped = g_strstrip(g_strdup(out));
g_assert(!mkdir(subdir, 0700));
g_assert(g_file_set_contents(file, conf, -1, NULL));
@@ -84,8 +85,9 @@ static void test_merge1(const char *conf, const char *conf1, const char *out)
g_key_file_set_list_separator(k, ',');
ofono_conf_merge_files(k, file);
data = g_key_file_to_data(k, NULL, NULL);
g_strstrip(data);
DBG("\n%s", data);
g_assert(!g_strcmp0(data, out));
g_assert(!g_strcmp0(data, out_stripped));
g_free(data);
g_key_file_unref(k);
@@ -94,6 +96,7 @@ static void test_merge1(const char *conf, const char *conf1, const char *out)
remove(subdir);
remove(dir);
g_free(out_stripped);
g_free(file);
g_free(file1);
g_free(dir);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2019-2021 Jolla Ltd.
* Copyright (C) 2019-2022 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
@@ -122,6 +122,9 @@ static const struct test_method_name_data method_name_tests[] = {
},{
OFONO_DBUS_ACCESS_INTF_OEMRAW,
OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT
},{
OFONO_DBUS_ACCESS_INTF_IMS,
OFONO_DBUS_ACCESS_IMS_METHOD_COUNT
}
};

View File

@@ -1589,7 +1589,7 @@ static void test_cbs_padding_character(void)
static const char *ranges[] = { "1-5, 2, 3, 600, 569-900, 999",
"0-20, 33, 44, 50-60, 20-50, 1-5, 5, 3, 5",
NULL };
static const char *inv_ranges[] = { "1-5, 3333", "1-5, afbcd", "1-5, 3-5,,",
static const char *inv_ranges[] = { "1-5, 33333", "1-5, afbcd", "1-5, 3-5,,",
"1-5, 3-5, c", NULL };
static void test_range_minimizer(void)

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2022 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
@@ -57,17 +57,25 @@ struct ofono_gprs {
struct ofono_netreg {
struct ofono_atom atom;
struct ofono_watchlist *status_watches;
enum ofono_netreg_status status;
enum ofono_access_technology tech;
const char *mcc;
const char *mnc;
const char *name;
};
int ofono_netreg_get_status(struct ofono_netreg *netreg)
enum ofono_netreg_status ofono_netreg_get_status(struct ofono_netreg *netreg)
{
return netreg ? netreg->status : OFONO_NETREG_STATUS_NONE;
}
enum ofono_access_technology
ofono_netreg_get_technology (struct ofono_netreg *netreg)
{
return netreg ? netreg->tech : OFONO_ACCESS_TECHNOLOGY_NONE;
}
const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg)
{
return netreg ? netreg->mcc : NULL;
@@ -83,6 +91,44 @@ const char *ofono_netreg_get_name(struct ofono_netreg *netreg)
return netreg ? netreg->name : NULL;
}
static void netreg_notify(struct ofono_netreg *netreg)
{
GSList *l;
for (l = netreg->status_watches->items; l; l = l->next) {
struct ofono_watchlist_item *item = l->data;
ofono_netreg_status_notify_cb_t notify = item->notify;
notify(netreg->status, -1, -1, netreg->tech, netreg->mcc,
netreg->mnc, item->notify_data);
}
}
static unsigned int add_watch_item(struct ofono_watchlist *list,
void *notify, void *data, ofono_destroy_func destroy)
{
struct ofono_watchlist_item *watch =
g_new0(struct ofono_watchlist_item, 1);
watch->notify = notify;
watch->destroy = destroy;
watch->notify_data = data;
return __ofono_watchlist_add_item(list, watch);
}
unsigned int __ofono_netreg_add_status_watch(struct ofono_netreg *netreg,
ofono_netreg_status_notify_cb_t notify,
void *data, ofono_destroy_func destroy)
{
return add_watch_item(netreg->status_watches, notify, data, destroy);
}
gboolean __ofono_netreg_remove_status_watch(struct ofono_netreg *netreg,
unsigned int id)
{
return __ofono_watchlist_remove_item(netreg->status_watches, id);
}
/* Fake ofono_sim */
struct ofono_sim {
@@ -98,18 +144,6 @@ struct ofono_sim {
struct ofono_watchlist *state_watches;
};
static unsigned int add_watch_item(struct ofono_watchlist *list,
void *notify, void *data, ofono_destroy_func destroy)
{
struct ofono_watchlist_item *watch =
g_new0(struct ofono_watchlist_item, 1);
watch->notify = notify;
watch->destroy = destroy;
watch->notify_data = data;
return __ofono_watchlist_add_item(list, watch);
}
unsigned int ofono_sim_add_iccid_watch(struct ofono_sim *sim,
ofono_sim_iccid_event_cb_t cb, void *data,
ofono_destroy_func destroy)
@@ -342,7 +376,7 @@ unsigned int __ofono_modem_add_atom_watch(struct ofono_modem *modem,
return id;
}
static void call_watches(struct ofono_atom *atom,
static void atom_notify(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond)
{
GSList *l;
@@ -400,7 +434,7 @@ static void test_modem_register_atom(struct ofono_modem *modem,
if (!atom->registered) {
atom->registered = TRUE;
modem->atoms = g_slist_append(modem->atoms, atom);
call_watches(atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED);
atom_notify(atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED);
}
}
@@ -409,7 +443,7 @@ static void test_modem_unregister_atom(struct ofono_modem *modem,
{
if (atom->registered) {
atom->registered = FALSE;
call_watches(atom, OFONO_ATOM_WATCH_CONDITION_UNREGISTERED);
atom_notify(atom, OFONO_ATOM_WATCH_CONDITION_UNREGISTERED);
modem->atoms = g_slist_remove(modem->atoms, atom);
}
}
@@ -428,6 +462,9 @@ static void test_modem_init1(struct ofono_modem *modem, const char *path)
netreg->atom.type = OFONO_ATOM_TYPE_NETREG;
netreg->atom.modem = modem;
netreg->atom.data = netreg;
netreg->status = OFONO_NETREG_STATUS_NOT_REGISTERED;
netreg->tech = OFONO_ACCESS_TECHNOLOGY_NONE;
netreg->status_watches = __ofono_watchlist_new(g_free);
gprs->atom.type = OFONO_ATOM_TYPE_GPRS;
gprs->atom.modem = modem;
@@ -455,15 +492,17 @@ static void test_modem_init(struct ofono_modem *modem)
static void test_modem_shutdown(struct ofono_modem *modem)
{
struct ofono_sim *sim = &modem->sim;
struct ofono_netreg *netreg = &modem->netreg;
call_modemwatches(modem, FALSE);
g_modem_list = g_slist_remove(g_modem_list, modem);
g_slist_free(modem->atoms);
__ofono_watchlist_free(sim->iccid_watches);
__ofono_watchlist_free(sim->imsi_watches);
__ofono_watchlist_free(sim->state_watches);
__ofono_watchlist_free(sim->spn_watches);
__ofono_watchlist_free(netreg->status_watches);
__ofono_watchlist_free(modem->atom_watches);
__ofono_watchlist_free(modem->online_watches);
}
@@ -504,8 +543,6 @@ static void test_basic(void)
NULL, NULL));
ofono_watch_remove_handler(NULL, 0);
ofono_watch_remove_handlers(NULL, NULL, 0);
__ofono_watch_netreg_changed(NULL);
__ofono_watch_netreg_changed(TEST_PATH);
__ofono_watch_gprs_settings_changed
(NULL, OFONO_GPRS_CONTEXT_TYPE_ANY, NULL);
__ofono_watch_gprs_settings_changed
@@ -623,7 +660,7 @@ static void test_netreg(void)
struct ofono_watch *watch;
struct ofono_modem modem;
struct ofono_netreg *netreg = &modem.netreg;
gulong id[5];
gulong id[6];
int n[G_N_ELEMENTS(id)];
#define NETREG 0
@@ -631,8 +668,7 @@ static void test_netreg(void)
#define REG_MCC 2
#define REG_MNC 3
#define REG_NAME 4
__ofono_watch_netreg_changed(TEST_PATH); /* No effect (yet) */
#define REG_TECH 5
memset(&modem, 0, sizeof(modem));
__ofono_modemwatch_init();
@@ -652,16 +688,20 @@ static void test_netreg(void)
(watch, test_inc_cb, n + REG_MNC);
id[REG_NAME] = ofono_watch_add_reg_name_changed_handler
(watch, test_inc_cb, n + REG_NAME);
id[REG_TECH] = ofono_watch_add_reg_tech_changed_handler
(watch, test_inc_cb, n + REG_TECH);
test_modem_register_atom(&modem, &netreg->atom);
g_assert(watch->netreg == netreg);
g_assert(watch->reg_status == netreg->status);
g_assert(n[NETREG] == 1);
g_assert(n[REG_STATUS] == 1);
g_assert_cmpint(watch->reg_status, == ,netreg->status);
g_assert_cmpint(watch->reg_tech, == ,netreg->tech);
g_assert_cmpint(n[NETREG], == ,1);
g_assert_cmpint(n[REG_STATUS], == ,1);
g_assert_cmpint(n[REG_TECH], == ,0);
n[NETREG] = 0;
n[REG_STATUS] = 0;
netreg->status++;
__ofono_watch_netreg_changed(TEST_PATH);
netreg_notify(netreg);
g_assert(watch->reg_status == netreg->status);
g_assert(n[REG_STATUS] == 1);
n[REG_STATUS] = 0;
@@ -669,31 +709,35 @@ static void test_netreg(void)
netreg->mcc = TEST_MCC;
netreg->mnc = TEST_MNC;
netreg->name = TEST_NAME;
__ofono_watch_netreg_changed(TEST_PATH);
__ofono_watch_netreg_changed(TEST_PATH); /* This one has no effect */
__ofono_watch_netreg_changed(TEST_PATH_1); /* This one too */
g_assert(!n[REG_STATUS]);
g_assert(n[REG_MCC] == 1);
g_assert(n[REG_MNC] == 1);
g_assert(n[REG_NAME] == 1);
g_assert(!g_strcmp0(watch->reg_mcc, netreg->mcc));
g_assert(!g_strcmp0(watch->reg_mnc, netreg->mnc));
g_assert(!g_strcmp0(watch->reg_name, netreg->name));
netreg->tech = OFONO_ACCESS_TECHNOLOGY_EUTRAN;
netreg_notify(netreg);
netreg_notify(netreg); /* This one has no effect */
g_assert_cmpint(n[REG_STATUS], == ,0);
g_assert_cmpint(n[REG_MCC], == ,1);
g_assert_cmpint(n[REG_MNC], == ,1);
g_assert_cmpint(n[REG_NAME], == ,1);
g_assert_cmpint(n[REG_TECH], == ,1);
g_assert_cmpstr(watch->reg_mcc, == ,netreg->mcc);
g_assert_cmpstr(watch->reg_mnc, == ,netreg->mnc);
g_assert_cmpstr(watch->reg_name, == ,netreg->name);
n[REG_MCC] = 0;
n[REG_MNC] = 0;
n[REG_NAME] = 0;
n[REG_TECH] = 0;
test_modem_unregister_atom(&modem, &netreg->atom);
g_assert(!watch->netreg);
g_assert(watch->reg_status == OFONO_NETREG_STATUS_NONE);
g_assert_cmpint(watch->reg_status, == ,OFONO_NETREG_STATUS_NONE);
g_assert_cmpint(watch->reg_tech, == ,OFONO_ACCESS_TECHNOLOGY_NONE);
g_assert(!watch->reg_mcc);
g_assert(!watch->reg_mnc);
g_assert(!watch->reg_name);
g_assert(n[NETREG] == 1);
g_assert(n[REG_STATUS] == 1);
g_assert(n[REG_MCC] == 1);
g_assert(n[REG_MNC] == 1);
g_assert(n[REG_NAME] == 1);
g_assert_cmpint(n[NETREG], == ,1);
g_assert_cmpint(n[REG_STATUS], == ,1);
g_assert_cmpint(n[REG_MCC], == ,1);
g_assert_cmpint(n[REG_MNC], == ,1);
g_assert_cmpint(n[REG_NAME], == ,1);
g_assert_cmpint(n[REG_TECH], == ,1);
memset(n, 0, sizeof(n));
netreg->mcc = NULL;
@@ -702,20 +746,24 @@ static void test_netreg(void)
test_modem_register_atom(&modem, &netreg->atom);
g_assert(watch->netreg == netreg);
g_assert(watch->reg_status == netreg->status);
g_assert(n[NETREG] == 1);
g_assert(n[REG_STATUS] == 1);
g_assert_cmpint(watch->reg_status, == ,netreg->status);
g_assert_cmpint(watch->reg_tech, == ,netreg->tech);
g_assert_cmpint(n[NETREG], == ,1);
g_assert_cmpint(n[REG_STATUS], == ,1);
n[NETREG] = 0;
n[REG_STATUS] = 0;
n[REG_TECH] = 0;
test_modem_shutdown(&modem);
g_assert(!watch->netreg);
g_assert(watch->reg_status == OFONO_NETREG_STATUS_NONE);
g_assert(n[NETREG] == 1);
g_assert(n[REG_STATUS] == 1);
g_assert(!n[REG_MCC]);
g_assert(!n[REG_MNC]);
g_assert(!n[REG_NAME]);
g_assert_cmpint(watch->reg_status, == ,OFONO_NETREG_STATUS_NONE);
g_assert_cmpint(watch->reg_tech, == ,OFONO_ACCESS_TECHNOLOGY_NONE);
g_assert_cmpint(n[NETREG], == ,1);
g_assert_cmpint(n[REG_STATUS], == ,1);
g_assert_cmpint(n[REG_TECH], == ,1);
g_assert_cmpint(n[REG_MCC], == ,0);
g_assert_cmpint(n[REG_MNC], == ,0);
g_assert_cmpint(n[REG_NAME], == ,0);
ofono_watch_remove_all_handlers(watch, id);
ofono_watch_unref(watch);

View File

@@ -1,6 +1,6 @@
Name: ofono
Summary: Open Source Telephony
Version: 1.28
Version: 1.29
Release: 1
License: GPLv2
URL: https://github.com/sailfishos/ofono