Compare commits

...

26 Commits

Author SHA1 Message Date
Slava Monich
b098ad0d5c [ofono] Switch USSD state from USER_ACTION to IDLE. Fixes JB#38992
When a USSD notification is received in the USER_ACTION state,
the state needs to be switched to IDLE. Some networks send 0
(no further user action required) after the response timeout
expires. That should result in the user input form getting
removed from the screen.
2017-06-22 10:42:32 +03:00
Slava Monich
b018b49e91 [ofono] Workaround for broken MMS proxy IP address. JB#38990
Some operators provide IP address of the MMS proxy
prepending zeros to each number shorter then 3 digits,
e.g. "192.168.094.023" instead of "192.168.94.23".
That may look nicer but it's actually wrong because
the numbers starting with zeros are interpreted as
octal numbers. In the example above 023 actually means
16 and 094 is not a valid number at all.

In addition to publishing these broken settings on their
web sites, some of the operators send them over the air,
in which case we can't even blame the user for entering
an invalid IP address. We better be prepared to deal with
those.

Since nobody in the world seems to be actually using the
octal notation to write an IP address, let's remove the
leading zeros if we find them in the host part of the MMS
proxy URL.
2017-06-20 11:22:18 +03:00
Slava Monich
9031009858 [ofono] Reset authentication method together with other context settings. JB#38972 2017-06-17 17:27:34 +03:00
Slava Monich
48cbd95277 [ril] Respect the authentication algorithm option. JB#38972 2017-06-17 17:21:09 +03:00
Slava Monich
883b7d7b6c [ofono] Added ANY and NONE authentication methods. JB#38972
ANY is supposed to allow either PAP or CHAP to be performed at plugin's
discretion. This is now the default (rather than CHAP)

NONE disables the authentication alltogether.
2017-06-17 17:21:02 +03:00
Slava Monich
137600e58e [ofono] Renamed Sailfish OS specific provision plugin to sailfish_provision. JB#38927
plugins/provision.c is the original upstream provisioning plugin and
plugins/sailfish_provision.c is the Sailfish OS specific thing. They
are mutually exclusuve.

Sailfish OS specific plugin is enabled with --enable-sailfish-provision
configure switch. By default, the upstream plugin is used.
2017-06-17 17:20:53 +03:00
Slava Monich
d9b386a8a9 [ofono] Expose IMEI SV via org.nemomobile.ofono.ModemManager. JB#38973
Unlike org.ofono.Modem properties, it's always going to be available
even for the slots that are disabled.
2017-06-16 16:41:26 +03:00
Slava Monich
a78b7818e9 [ril] Don't auto-select the data sim on a multisim phone. JB#38719
This kind of behavior is reserved for single sim phone (for now).
2017-05-31 11:04:49 +03:00
Slava Monich
d00b999cf6 [ril] Allow (some) DEVICE_IDENTITY requests to time out. Fixes JB#38632
If GET_SIM_STATUS succeeds but DEVICE_IDENTITY keeps on failing,
allow the latter to time out. Some RILs behave that way until the
modem has been properly initialized.

Conflicts:
	ofono/drivers/ril/ril_plugin.c
2017-05-13 00:22:50 +03:00
Slava Monich
476243be6a [ril] Use DEVICE_IDENTITY request instead of GET_IMEI. Contributes to JB#38632
RIL_REQUEST_GET_IMEI has been deprecated since 2009
2017-05-13 00:21:05 +03:00
Slava Monich
adca340f4b [simfs] Prevent a crash in sim_fs_notify_file_watches. Fixes JB#38656
If no file watchers have ever been added, context->file_watches
is NULL and sim_fs_notify_file_watches() should take that into
account.
2017-05-12 23:39:37 +03:00
Slava Monich
709bb7e596 [ril] Always refresh SIM status from query_passwd_state. Fixes JB#38257
After we have entered an invalid pin too many times, RIL signals
the SIM status change, we request the new status but ofono core
asks us for the new passwd state before our SIM status query has
completed. We need to wait for the query to complete before we can
report the new status to the core.

It also won't hurt if we request a fresh SIM status every time
when query_passwd_state callback is called, just in case if RIL
fails to notify us about the SIM status change.
2017-04-27 11:18:46 +03:00
jpoutiai
aef9bbd3e0 Merge branch 'jb38053' into 'master'
[plugins] support bt call audio control. Fixes JB#38053

See merge request !110
2017-04-05 10:23:27 +00:00
Jarko Poutiainen
c6eb410f21 [plugins] support bt call audio control. Fixes JB#38053 2017-04-05 08:35:55 +03:00
Slava Monich
08b3ea3d0f Merge branch 'last_fail' into 'master'
Handle fancy variant of LAST_CALL_FAIL_CAUSE response

Some RILs get creative and invent their own formats.
They must be very proud of it.

See merge request !106
2017-03-15 21:46:11 +00:00
Slava Monich
2978862417 [ril] Handle fancy variant of LAST_CALL_FAIL_CAUSE response. Fixes JB#38079
Some RILs get creative and invent their own formats.
2017-03-15 17:19:37 +02:00
Slava Monich
19228c9e67 Merge branch 'lastcause' into 'master'
Allow to configure custom hangup reasons

One can define localHangupReasons and remoteHangupReasons in
ril_subscription.conf which will be treated as normal local or
remote hangup reasons.

See merge request !104
2017-02-24 13:11:46 +00:00
Slava Monich
9be791d531 [ofono] Allow to conifigure custom hangup reasons. Fixes JB#37879
One can define localHangupReasons and remoteHangupReasons in
ril_subscription.conf which will be treated as normal local or
remote hangup reasons. The value is a comma-separated list of
numbers, e.g.

localHangupReasons=20,39
2017-02-24 12:07:57 +02:00
Slava Monich
6b9eb7bf8f Merge branch 'voicecall' into 'master'
Don't use internal voicecall data structures

Added ofono_voicecall_find_call API instead

See merge request !105
2017-02-24 10:06:39 +00:00
Slava Monich
01f8989aee [ril] Don't use internal voicecall data structures
Use newly added ofono_voicecall_find_call API instead
2017-02-24 00:28:50 +02:00
Slava Monich
2f5efaf591 [ofono] Added ofono_voicecall_find_call API
For use by plugins
2017-02-24 00:28:18 +02:00
Slava Monich
ca1d06c37a Merge branch 'disable' into 'master'
Disable some unnecessary and harmful functionality

See merge request !103
2017-01-12 15:17:23 +00:00
Slava Monich
5f45928a84 [ofono] Disable PhoNet/ISI and QMI modem support. MER#1734
This makes ARM executable smaller by 170 KB
2017-01-12 00:47:04 +02:00
Slava Monich
19f74e6c85 [ofono] Don't allow to add or remove connection context over D-Bus. Fixes MER#1733
Quite a few things in SailfishOS assume that each modem has exactly
one internet and one mms context. However, ofono's D-Bus API allows
any application to arbitrarily add and remove connection contexts
which can screw things up quite badly. Since this functionality is
not used by SailfishOS, it should be disabled.
2017-01-12 00:27:17 +02:00
Slava Monich
41d5cfcab2 Merge branch 'modem-error' into 'master'
Count rild crashes

See merge request !102
2017-01-11 11:58:42 +00:00
Slava Monich
357c5db580 [ril] Count rild crashes. Contributes to JB#35780
org.nemomobile.ofono.ModemManager.ModemError signal is emitted
when rild crash is detected. Also, the new GetModemErrors method
allows to query how many times which instance of rild has crashed
since ofono was (re)started.
2017-01-11 13:24:23 +02:00
31 changed files with 1548 additions and 390 deletions

View File

@@ -575,6 +575,11 @@ builtin_sources += plugins/bluez5.c plugins/bluez5.h
builtin_modules += hfp_ag_bluez5
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
if SAILFISHFOS
builtin_modules += sfos_bt
builtin_sources += plugins/sfos_bt.c
endif
endif
if UPOWER
@@ -588,11 +593,20 @@ builtin_modules += nettime
builtin_sources += plugins/nettime.c
endif
if SAILFISH_PROVISION
builtin_sources += plugins/sailfish_provision.c
PROVISION = 1
else
if PROVISION
builtin_sources += plugins/provision.c
endif
endif
if PROVISION
builtin_sources += plugins/mbpi.h plugins/mbpi.c
builtin_modules += provision
builtin_sources += plugins/provision.h plugins/provision.c
builtin_sources += plugins/provision.h
builtin_modules += cdma_provision
builtin_sources += plugins/cdma-provision.c
@@ -915,9 +929,9 @@ unit_test_caif_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_caif_OBJECTS)
unit_test_provision_SOURCES = unit/test-provision.c \
plugins/provision.h plugins/provision.c \
plugins/mbpi.c src/gprs-provision.c \
src/log.c
plugins/provision.h plugins/mbpi.c \
plugins/sailfish_provision.c \
src/gprs-provision.c src/log.c
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_provision_OBJECTS)

View File

@@ -183,6 +183,13 @@ if (test "${enable_jolla_rilmodem}" = "yes"); then
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS $LIBMCE_LIBS"
fi
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
[don't allow to add or remove connection context over D-Bus]), [
if (test "${enableval}" = "no"); then
CFLAGS="$CFLAGS -DDISABLE_ADD_REMOVE_CONTEXT"
fi
])
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
[disable Qualcomm QMI modem support]),
[enable_qmimodem=${enableval}])
@@ -206,6 +213,15 @@ fi
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
AC_ARG_ENABLE(sailfishos, AC_HELP_STRING([--enable-sailfishos],
[enable sailfishos plugin]), [enable_sailfishos=${enableval}])
AM_CONDITIONAL(SAILFISHFOS, test "${enable_sailfishos}" = "yes")
AC_ARG_ENABLE(sailfish-provision, AC_HELP_STRING([--enable-sailfish-provision],
[enable Sailfish OS provisioning plugin]),
[enable_sailfish_provision=${enableval}])
AM_CONDITIONAL(SAILFISH_PROVISION, test "${enable_sailfish_provision=$}" = "yes")
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
[disable Nettime plugin]),
[enable_nettime=${enableval}])

View File

@@ -247,6 +247,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
/* We only support CHAP and PAP */
switch (ctx->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
case OFONO_GPRS_AUTH_METHOD_NONE:
case OFONO_GPRS_AUTH_METHOD_CHAP:
gcd->auth_method = G_AT_PPP_AUTH_METHOD_CHAP;
break;
@@ -294,6 +296,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
* prefix, this is the least invasive place to set it.
*/
switch (ctx->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
case OFONO_GPRS_AUTH_METHOD_NONE:
case OFONO_GPRS_AUTH_METHOD_CHAP:
snprintf(buf + len, sizeof(buf) - len - 3,
",\"CHAP:%s\"", ctx->apn);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,9 @@
#include "ril_config.h"
#include <gutil_intarray.h>
#include <gutil_ints.h>
/* Utilities for parsing ril_subscription.conf */
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
@@ -106,6 +109,51 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
}
}
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key)
{
char* value = ril_config_get_string(file, group, key);
if (value) {
char **values = g_strsplit(value, ",", -1);
char **ptr = values;
GUtilIntArray* array = gutil_int_array_new();
while (*ptr) {
const char *str = *ptr++;
char *end = NULL;
long ival = strtol(str, &end, 0);
if (str[0] && !end[0]) {
gutil_int_array_append(array, ival);
}
}
g_free(value);
g_strfreev(values);
return gutil_int_array_free_to_ints(array);
}
return NULL;
}
char *ril_config_ints_to_string(GUtilInts *ints, char separator)
{
if (ints) {
guint i, n;
const int *data = gutil_ints_get_data(ints, &n);
GString* buf = g_string_new(NULL);
for (i=0; i<n; i++) {
if (buf->len > 0) {
g_string_append_c(buf, separator);
}
g_string_append_printf(buf, "%d", data[i]);
}
return g_string_free(buf, FALSE);
}
return NULL;
}
/*
* Local Variables:
* mode: C

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,13 +22,16 @@
#define RILCONF_SETTINGS_GROUP "Settings"
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key);
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key);
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
const char *key, int *value);
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
const char *key, gboolean *value);
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
const char *key, int flag, int *flags);
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key);
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
#endif /* RIL_CONFIG_H */

View File

@@ -1,11 +1,10 @@
/*
*
* RIL constants adopted from AOSP's header:
*
* /hardware/ril/reference_ril/ril.h
*
* Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2013-2016 Jolla Ltd.
* Copyright (C) 2013-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -118,45 +117,68 @@ enum ril_radio_tech {
};
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
#define CALL_FAIL_UNOBTAINABLE_NUMBER 1
#define CALL_FAIL_NORMAL 16
#define CALL_FAIL_BUSY 17
#define CALL_FAIL_CONGESTION 34
#define CALL_FAIL_ACM_LIMIT_EXCEEDED 68
#define CALL_FAIL_CALL_BARRED 240
#define CALL_FAIL_FDN_BLOCKED 241
#define CALL_FAIL_IMSI_UNKNOWN_IN_VLR 242
#define CALL_FAIL_IMEI_NOT_ACCEPTED 243
#define CALL_FAIL_DIAL_MODIFIED_TO_USSD 244
#define CALL_FAIL_DIAL_MODIFIED_TO_SS 245
#define CALL_FAIL_DIAL_MODIFIED_TO_DIAL 246
#define CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE 1000
#define CALL_FAIL_CDMA_DROP 1001
#define CALL_FAIL_CDMA_INTERCEPT 1002
#define CALL_FAIL_CDMA_REORDER 1003
#define CALL_FAIL_CDMA_SO_REJECT 1004
#define CALL_FAIL_CDMA_RETRY_ORDER 1005
#define CALL_FAIL_CDMA_ACCESS_FAILURE 1006
#define CALL_FAIL_CDMA_PREEMPTED 1007
#define CALL_FAIL_CDMA_NOT_EMERGENCY 1008
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
enum ril_call_fail_cause {
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
CALL_FAIL_NORMAL = 16,
CALL_FAIL_BUSY = 17,
CALL_FAIL_NO_USER_RESPONDING = 18,
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
CALL_FAIL_CALL_REJECTED = 21,
CALL_FAIL_NUMBER_CHANGED = 22,
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
CALL_FAIL_FACILITY_REJECTED = 29,
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
CALL_FAIL_CONGESTION = 34,
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
CALL_FAIL_TEMPORARY_FAILURE = 41,
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
CALL_FAIL_QOS_UNAVAILABLE = 49,
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
CALL_FAIL_CALL_BARRED = 240,
CALL_FAIL_FDN_BLOCKED = 241,
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
/* Not defined in ril.h but valid 3GPP specific cause values
* for call control. See 3GPP TS 24.008 Annex H. */
#define CALL_FAIL_NO_ROUTE_TO_DESTINATION 3
#define CALL_FAIL_CHANNEL_UNACCEPTABLE 6
#define CALL_FAIL_OPERATOR_DETERMINED_BARRING 8
#define CALL_FAIL_NO_USER_RESPONDING 18
#define CALL_FAIL_USER_ALERTING_NO_ANSWER 19
#define CALL_FAIL_CALL_REJECTED 21
#define CALL_FAIL_NUMBER_CHANGED 22
#define CALL_FAIL_ANONYMOUS_CALL_REJECTION 24
#define CALL_FAIL_PRE_EMPTION 25
#define CALL_FAIL_DESTINATION_OUT_OF_ORDER 27
#define CALL_FAIL_INCOMPLETE_NUMBER 28
#define CALL_FAIL_FACILITY_REJECTED 29
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
CALL_FAIL_PRE_EMPTION = 25
};
enum ril_data_call_fail_cause {
PDP_FAIL_NONE = 0,

View File

@@ -788,7 +788,7 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
struct ril_data_priv *priv = req->data->priv;
const char *proto_str = ril_data_ofono_protocol_to_ril(setup->proto);
GRilIoRequest* ioreq;
int tech, auth;
int tech, auth = RIL_AUTH_NONE;
GASSERT(proto_str);
@@ -811,14 +811,22 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
tech = RADIO_TECH_HSPA;
}
/*
* We do the same as in $AOSP/frameworks/opt/telephony/src/java/com/
* android/internal/telephony/dataconnection/DataConnection.java,
* onConnect(), and use authentication or not depending on whether
* the user field is empty or not.
*/
auth = (setup->username && setup->username[0]) ?
RIL_AUTH_BOTH : RIL_AUTH_NONE;
if (setup->username && setup->username[0]) {
switch (setup->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
auth = RIL_AUTH_BOTH;
break;
case OFONO_GPRS_AUTH_METHOD_NONE:
auth = RIL_AUTH_NONE;
break;
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = RIL_AUTH_CHAP;
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = RIL_AUTH_PAP;
break;
}
}
/*
* TODO: add comments about tethering, other non-public

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,16 +17,24 @@
#include "ril_util.h"
#include "ril_log.h"
#include <gutil_idlequeue.h>
/*
* TODO: No public RIL api to query manufacturer or model.
* Check where to get, could /system/build.prop be updated to have good values?
*/
enum ril_devinfo_cb_tag {
DEVINFO_QUERY_SERIAL = 1,
DEVINFO_QUERY_SVN
};
struct ril_devinfo {
struct ofono_devinfo *info;
GRilIoQueue *q;
guint register_id;
guint imei_id;
GUtilIdleQueue *iq;
char *log_prefix;
char *imeisv;
char *imei;
};
@@ -36,6 +44,7 @@ struct ril_devinfo_cbd {
gpointer data;
};
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
#define ril_devinfo_cbd_free g_free
static inline struct ril_devinfo *ril_devinfo_get_data(
@@ -62,7 +71,7 @@ static void ril_devinfo_query_unsupported(struct ofono_devinfo *info,
cb(ril_error_failure(&error), "", data);
}
static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
static void ril_devinfo_query_revision_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
@@ -73,7 +82,7 @@ static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
res = grilio_parser_get_utf8(&rilp);
DBG("%s", res);
DBG_(cbd->di, "%s", res);
cbd->cb(ril_error_ok(&error), res ? res : "", cbd->data);
g_free(res);
} else {
@@ -86,23 +95,46 @@ static void ril_devinfo_query_revision(struct ofono_devinfo *info,
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG("");
grilio_queue_send_request_full(di->q, NULL, RIL_REQUEST_BASEBAND_VERSION,
ril_devinfo_query_cb, ril_devinfo_cbd_free,
DBG_(di, "");
grilio_queue_send_request_full(di->q, NULL,
RIL_REQUEST_BASEBAND_VERSION,
ril_devinfo_query_revision_cb,
ril_devinfo_cbd_free,
ril_devinfo_cbd_new(di, cb, data));
}
static gboolean ril_devinfo_query_serial_cb(void *user_data)
static void ril_devinfo_query_serial_cb(gpointer user_data)
{
struct ril_devinfo_cbd *cbd = user_data;
struct ril_devinfo *di = cbd->di;
struct ofono_error error;
GASSERT(di->imei_id);
di->imei_id = 0;
DBG_(di, "%s", di->imei);
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
return FALSE;
}
static void ril_devinfo_query_svn_cb(gpointer user_data)
{
struct ril_devinfo_cbd *cbd = user_data;
struct ril_devinfo *di = cbd->di;
struct ofono_error error;
DBG_(di, "%s", di->imeisv);
if (di->imeisv && di->imeisv[0]) {
cbd->cb(ril_error_ok(&error), di->imeisv, cbd->data);
} else {
cbd->cb(ril_error_failure(&error), "", cbd->data);
}
}
static void ril_devinfo_query(struct ril_devinfo *di,
enum ril_devinfo_cb_tag tag, GUtilIdleFunc fn,
ofono_devinfo_query_cb_t cb, void *data)
{
GVERIFY_FALSE(gutil_idle_queue_cancel_tag(di->iq, tag));
gutil_idle_queue_add_tag_full(di->iq, tag, fn,
ril_devinfo_cbd_new(di, cb, data),
ril_devinfo_cbd_free);
}
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
@@ -111,29 +143,28 @@ static void ril_devinfo_query_serial(struct ofono_devinfo *info,
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
GASSERT(!di->imei_id);
if (di->imei_id) {
g_source_remove(di->imei_id);
di->imei_id = 0;
}
DBG("%s", di->imei);
di->imei_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_devinfo_query_serial_cb,
ril_devinfo_cbd_new(di, cb, data),
ril_devinfo_cbd_free);
DBG_(di, "");
ril_devinfo_query(di, DEVINFO_QUERY_SERIAL,
ril_devinfo_query_serial_cb, cb, data);
}
static gboolean ril_devinfo_register(gpointer user_data)
static void ril_devinfo_query_svn(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb,
void *data)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG_(di, "");
ril_devinfo_query(di, DEVINFO_QUERY_SVN,
ril_devinfo_query_svn_cb, cb, data);
}
static void ril_devinfo_register(gpointer user_data)
{
struct ril_devinfo *di = user_data;
DBG("");
di->register_id = 0;
DBG_(di, "");
ofono_devinfo_register(di->info);
/* This makes the timeout a single-shot */
return FALSE;
}
static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
@@ -142,13 +173,18 @@ static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
struct ril_modem *modem = data;
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
DBG("%s %s %p", ril_modem_get_path(modem), modem->imei, di);
di->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
DBG_(di, "%s", modem->imei);
GASSERT(modem->imei);
di->q = grilio_queue_new(ril_modem_io(modem));
di->info = info;
di->imeisv = g_strdup(modem->imeisv);
di->imei = g_strdup(modem->imei);
di->register_id = g_idle_add(ril_devinfo_register, di);
di->iq = gutil_idle_queue_new();
gutil_idle_queue_add(di->iq, ril_devinfo_register, di);
ofono_devinfo_set_data(info, di);
return 0;
}
@@ -157,19 +193,14 @@ static void ril_devinfo_remove(struct ofono_devinfo *info)
{
struct ril_devinfo *di = ril_devinfo_get_data(info);
DBG("%p", di);
DBG_(di, "");
ofono_devinfo_set_data(info, NULL);
if (di->register_id > 0) {
g_source_remove(di->register_id);
}
if (di->imei_id > 0) {
g_source_remove(di->imei_id);
}
gutil_idle_queue_cancel_all(di->iq);
gutil_idle_queue_unref(di->iq);
grilio_queue_cancel_all(di->q, FALSE);
grilio_queue_unref(di->q);
g_free(di->log_prefix);
g_free(di->imeisv);
g_free(di->imei);
g_free(di);
}
@@ -178,10 +209,11 @@ const struct ofono_devinfo_driver ril_devinfo_driver = {
.name = RILMODEM_DRIVER,
.probe = ril_devinfo_probe,
.remove = ril_devinfo_remove,
.query_manufacturer = ril_devinfo_query_unsupported,
/* query_revision won't be called if query_model is missing */
.query_model = ril_devinfo_query_unsupported,
.query_revision = ril_devinfo_query_revision,
.query_serial = ril_devinfo_query_serial
.query_serial = ril_devinfo_query_serial,
.query_svn = ril_devinfo_query_svn
};
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -52,6 +52,7 @@ struct ril_modem_data {
struct ril_modem modem;
GRilIoQueue *q;
char *log_prefix;
char *imeisv;
char *imei;
char *ecclist_file;
gboolean pre_sim_done;
@@ -433,6 +434,7 @@ static void ril_modem_remove(struct ofono_modem *ofono)
grilio_queue_unref(md->q);
g_free(md->ecclist_file);
g_free(md->log_prefix);
g_free(md->imeisv);
g_free(md->imei);
g_free(md);
}
@@ -460,6 +462,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
/* Copy config */
modem->config = *slot->config;
modem->imei = md->imei = g_strdup(slot->imei);
modem->imeisv = md->imeisv = g_strdup(slot->imeisv);
modem->log_prefix = log_prefix;
modem->ecclist_file =
md->ecclist_file = g_strdup(slot->ecclist_file);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,6 +26,7 @@
#include "ril_log.h"
#include <gdbus.h>
#include <gutil_ints.h>
#include <gutil_strv.h>
#include <gutil_misc.h>
#include <mce_display.h>
@@ -40,6 +41,8 @@
#include "ofono.h"
#include "storage.h"
#define RIL_DEVICE_IDENTITY_RETRIES_LAST 2
#define RADIO_GID 1001
#define RADIO_UID 1001
#define RIL_SUB_SIZE 4
@@ -77,6 +80,8 @@
#define RILCONF_DATA_CALL_FORMAT "dataCallFormat"
#define RILCONF_DATA_CALL_RETRY_LIMIT "dataCallRetryLimit"
#define RILCONF_DATA_CALL_RETRY_DELAY "dataCallRetryDelay"
#define RILCONF_LOCAL_HANGUP_REASONS "localHangupReasons"
#define RILCONF_REMOTE_HANGUP_REASONS "remoteHangupReasons"
#define RIL_STORE "ril"
#define RIL_STORE_GROUP "Settings"
@@ -85,6 +90,12 @@
#define RIL_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
#define RIL_STORE_SLOTS_SEP ","
/* The file where error statistics is stored */
#define RIL_ERROR_STORAGE "rilerror"
/* Modem error ids, must be static strings (only one is defined for now) */
static const char RIL_ERROR_ID_RILD_RESTART[] = "rild-restart";
enum ril_plugin_io_events {
IO_EVENT_CONNECTED,
IO_EVENT_ERROR,
@@ -121,6 +132,7 @@ struct ril_slot {
struct ril_slot_info pub;
char *path;
char *imei;
char *imeisv;
char *name;
char *sockpath;
char *sub;
@@ -148,6 +160,7 @@ struct ril_slot {
gulong io_event_id[IO_EVENT_COUNT];
gulong imei_req_id;
gulong sim_card_state_event_id;
gboolean received_sim_status;
guint trace_id;
guint dump_id;
guint retry_id;
@@ -166,6 +179,7 @@ static void ril_debug_grilio_notify(struct ofono_debug_desc *desc);
static void ril_debug_mce_notify(struct ofono_debug_desc *desc);
static void ril_plugin_debug_notify(struct ofono_debug_desc *desc);
static void ril_plugin_retry_init_io(struct ril_slot *slot);
static void ril_plugin_check_modem(struct ril_slot *slot);
GLOG_MODULE_DEFINE("rilmodem");
@@ -208,6 +222,12 @@ static struct ofono_debug_desc ril_plugin_debug OFONO_DEBUG_ATTR = {
.notify = ril_plugin_debug_notify
};
static inline const char *ril_slot_debug_prefix(const struct ril_slot *slot)
{
/* slot->path always starts with a slash, skip it */
return slot->path + 1;
}
static struct ril_plugin_priv *ril_plugin_cast(struct ril_plugin *pub)
{
return G_CAST(pub, struct ril_plugin_priv, pub);
@@ -232,7 +252,7 @@ static void ril_plugin_foreach_slot(struct ril_plugin_priv *plugin,
static void ril_plugin_send_screen_state(struct ril_slot *slot)
{
if (slot->io) {
if (slot->io && slot->io->connected) {
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1); /* Number of params */
grilio_request_append_int32(req, slot->plugin->display_on);
@@ -338,6 +358,7 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
ril_sim_card_unref(slot->sim_card);
slot->sim_card_state_event_id = 0;
slot->sim_card = NULL;
slot->received_sim_status = FALSE;
}
if (slot->io) {
@@ -469,14 +490,23 @@ static int ril_plugin_update_modem_paths(struct ril_plugin_priv *plugin)
if (plugin->default_data_imsi) {
slot = ril_plugin_find_slot_imsi(plugin->slots,
plugin->default_data_imsi);
} else if (plugin->data_slot) {
/* Make sure that the slot is enabled and SIM is in */
slot = ril_plugin_find_slot_imsi(plugin->slots,
} else if (!ril_plugin_multisim(plugin)) {
if (plugin->data_slot) {
/* Make sure that the slot is enabled and SIM is in */
slot = ril_plugin_find_slot_imsi(plugin->slots,
plugin->data_slot->modem ?
ofono_sim_get_imsi(plugin->data_slot->sim) :
NULL);
} else {
/* Check if anything is available */
slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
}
} else {
slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
/*
* Should we automatically select the default data sim
* on a multisim phone that has only one sim inserted?
*/
slot = NULL;
}
if (slot && !slot->radio->online) {
@@ -568,14 +598,79 @@ static void ril_plugin_update_ready(struct ril_plugin_priv *plugin)
}
}
static void ril_plugin_device_identity_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_slot *slot = user_data;
char *imei = NULL;
char *imeisv = NULL;
GASSERT(slot->imei_req_id);
slot->imei_req_id = 0;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
guint32 n;
/*
* RIL_REQUEST_DEVICE_IDENTITY
*
* "response" is const char **
* ((const char **)response)[0] is IMEI (for GSM)
* ((const char **)response)[1] is IMEISV (for GSM)
* ((const char **)response)[2] is ESN (for CDMA)
* ((const char **)response)[3] is MEID (for CDMA)
*/
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &n) && n >= 2) {
imei = grilio_parser_get_utf8(&rilp);
imeisv = grilio_parser_get_utf8(&rilp);
DBG("%s %s", imei, imeisv);
} else {
DBG("parsing failure!");
}
/*
* slot->imei should be either NULL (when we get connected
* to rild the very first time) or match the already known
* IMEI (if rild crashed and we have reconnected)
*/
if (slot->imei && imei && strcmp(slot->imei, imei)) {
ofono_warn("IMEI has changed \"%s\" -> \"%s\"",
slot->imei, imei);
}
} else {
ofono_error("Slot %u IMEI query error: %s", slot->config.slot,
ril_error_to_string(status));
}
if (slot->imei) {
/* We assume that IMEI never changes */
g_free(imei);
} else {
slot->pub.imei =
slot->imei = imei ? imei : g_strdup_printf("%d", slot->index);
}
if (slot->imeisv) {
g_free(imeisv);
} else {
slot->pub.imeisv =
slot->imeisv = (imeisv ? imeisv : g_strdup(""));
}
ril_plugin_check_modem(slot);
ril_plugin_update_ready(slot->plugin);
}
static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
{
struct ril_slot *slot = data;
struct ril_plugin_priv *plugin = slot->plugin;
const struct ril_sim_card_status *status = card->status;
gboolean present;
if (card && card->status &&
card->status->card_state == RIL_CARDSTATE_PRESENT) {
if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
DBG("SIM found in slot %u", slot->config.slot);
present = TRUE;
} else {
@@ -583,6 +678,36 @@ static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
present = FALSE;
}
if (status) {
if (!slot->received_sim_status && slot->imei_req_id) {
/*
* We have received the SIM status but haven't yet
* got IMEI from the modem. Some RILs behave this
* way if the modem doesn't have IMEI initialized
* yet. Cancel the current request (with unlimited
* number of retries) and give a few more tries
* (this time, limited number).
*
* Some RILs fail RIL_REQUEST_DEVICE_IDENTITY until
* the modem hasn't been properly initialized.
*/
GRilIoRequest* req = grilio_request_new();
DBG("Giving slot %u last chance", slot->config.slot);
grilio_request_set_retry(req, RIL_RETRY_MS,
RIL_DEVICE_IDENTITY_RETRIES_LAST);
grilio_channel_cancel_request(slot->io,
slot->imei_req_id, FALSE);
slot->imei_req_id =
grilio_channel_send_request_full(slot->io,
req, RIL_REQUEST_DEVICE_IDENTITY,
ril_plugin_device_identity_cb,
NULL, slot);
grilio_request_unref(req);
}
slot->received_sim_status = TRUE;
}
if (slot->pub.sim_present != present) {
slot->pub.sim_present = present;
ril_plugin_dbus_signal_sim(plugin->dbus, slot->index, present);
@@ -611,7 +736,7 @@ static void ril_plugin_sim_state_watch(enum ofono_sim_state new_state,
struct ril_slot *slot = data;
struct ril_plugin_priv *plugin = slot->plugin;
DBG("%s sim state %d", slot->path + 1, new_state);
DBG("%s sim state %d", ril_slot_debug_prefix(slot), new_state);
slot->sim_state = new_state;
if (new_state == OFONO_SIM_STATE_READY) {
struct ril_slot *voice_slot = plugin->voice_slot;
@@ -667,10 +792,10 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
struct ril_slot *slot = data;
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
DBG("%s sim registered", slot->path + 1);
DBG("%s sim registered", ril_slot_debug_prefix(slot));
ril_plugin_register_sim(slot, __ofono_atom_get_data(atom));
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
DBG("%s sim unregistered", slot->path + 1);
DBG("%s sim unregistered", ril_slot_debug_prefix(slot));
slot->sim = NULL;
}
@@ -678,8 +803,35 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
ril_plugin_update_modem_paths_full(slot->plugin);
}
static void ril_plugin_handle_error(struct ril_slot *slot)
static void ril_plugin_count_error(struct ril_slot *slot, const char *key,
const char *message)
{
GHashTable *errors = slot->pub.errors;
GKeyFile *storage = storage_open(NULL, RIL_ERROR_STORAGE);
/* Update life-time statistics */
if (storage) {
/* slot->path always starts with a slash, skip it */
const char *group = slot->path + 1;
g_key_file_set_integer(storage, group, key,
g_key_file_get_integer(storage, group, key, NULL) + 1);
storage_close(NULL, RIL_ERROR_STORAGE, storage, TRUE);
}
/* Update run-time error counts. The key is the error id which
* is always a static string */
g_hash_table_insert(errors, (void*)key, GINT_TO_POINTER(
GPOINTER_TO_INT(g_hash_table_lookup(errors, key)) + 1));
/* Issue the D-Bus signal */
ril_plugin_dbus_signal_modem_error(slot->plugin->dbus,
slot->index, key, message);
}
static void ril_plugin_handle_error(struct ril_slot *slot, const char *msg)
{
ofono_error("%s %s", ril_slot_debug_prefix(slot), msg);
ril_plugin_count_error(slot, RIL_ERROR_ID_RILD_RESTART, msg);
ril_plugin_shutdown_slot(slot, TRUE);
ril_plugin_update_modem_paths_full(slot->plugin);
ril_plugin_retry_init_io(slot);
@@ -688,12 +840,12 @@ static void ril_plugin_handle_error(struct ril_slot *slot)
static void ril_plugin_slot_error(GRilIoChannel *io, const GError *error,
void *data)
{
ril_plugin_handle_error((struct ril_slot *)data);
ril_plugin_handle_error((struct ril_slot *)data, GERRMSG(error));
}
static void ril_plugin_slot_disconnected(GRilIoChannel *io, void *data)
{
ril_plugin_handle_error((struct ril_slot *)data);
ril_plugin_handle_error((struct ril_slot *)data, "disconnected");
}
static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
@@ -701,7 +853,7 @@ static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
{
struct ril_slot *slot = data;
DBG("%s %d", slot->path + 1, online);
DBG("%s %d", ril_slot_debug_prefix(slot), online);
GASSERT(slot->modem);
GASSERT(slot->modem == modem);
@@ -813,14 +965,15 @@ static void ril_debug_trace_update(struct ril_slot *slot)
static const char *ril_plugin_log_prefix(struct ril_slot *slot)
{
return ril_plugin_multisim(slot->plugin) ? (slot->path + 1) : "";
return ril_plugin_multisim(slot->plugin) ?
ril_slot_debug_prefix(slot) : "";
}
static void ril_plugin_create_modem(struct ril_slot *slot)
{
struct ril_modem *modem;
DBG("%s", slot->path);
DBG("%s", ril_slot_debug_prefix(slot));
GASSERT(slot->io && slot->io->connected);
GASSERT(!slot->modem);
@@ -869,42 +1022,6 @@ static void ril_plugin_check_modem(struct ril_slot *slot)
}
}
static void ril_plugin_imei_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_slot *slot = user_data;
char *imei = NULL;
GASSERT(slot->imei_req_id);
slot->imei_req_id = 0;
if (status == RIL_E_SUCCESS) {
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
imei = grilio_parser_get_utf8(&rilp);
DBG("%s", imei);
/*
* slot->imei should be either NULL (when we get connected
* to rild the very first time) or match the already known
* IMEI (if rild crashed and we have reconnected)
*/
GASSERT(!slot->imei || !g_strcmp0(slot->imei, imei));
} else {
ofono_error("Slot %u IMEI query error: %s", slot->config.slot,
ril_error_to_string(status));
}
g_free(slot->imei);
slot->pub.imei = slot->imei = (imei ? imei : g_strdup("ERROR"));
ril_plugin_check_modem(slot);
ril_plugin_update_ready(slot->plugin);
}
/*
* It seems to be necessary to kick (with RIL_REQUEST_RADIO_POWER) the
* modems with power on after one of the modems has been powered off.
@@ -940,17 +1057,19 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
GASSERT(!slot->io_event_id[IO_EVENT_CONNECTED]);
/*
* Modem will be registered after RIL_REQUEST_GET_IMEI successfully
* completes. By the time ofono starts, rild may not be completely
* functional. Waiting until it responds to RIL_REQUEST_GET_IMEI
* (and retrying the request on failure) gives rild time to finish
* whatever it's doing during initialization.
* Modem will be registered after RIL_REQUEST_DEVICE_IDENTITY
* successfully completes. By the time ofono starts, rild may
* not be completely functional. Waiting until it responds to
* RIL_REQUEST_DEVICE_IDENTITY (and retrying the request on
* failure) gives rild time to finish whatever it's doing during
* initialization.
*/
GASSERT(!slot->imei_req_id);
req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
slot->imei_req_id = grilio_channel_send_request_full(slot->io, req,
RIL_REQUEST_GET_IMEI, ril_plugin_imei_cb, NULL, slot);
slot->imei_req_id = grilio_channel_send_request_full(slot->io,
req, RIL_REQUEST_DEVICE_IDENTITY,
ril_plugin_device_identity_cb, NULL, slot);
grilio_request_unref(req);
GASSERT(!slot->radio);
@@ -967,6 +1086,10 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
slot->sim_flags);
slot->sim_card_state_event_id = ril_sim_card_add_state_changed_handler(
slot->sim_card, ril_plugin_sim_state_changed, slot);
/* ril_sim_card is expected to perform RIL_REQUEST_GET_SIM_STATUS
* asynchronously and report back when request has completed: */
GASSERT(!slot->sim_card->status);
GASSERT(!slot->received_sim_status);
GASSERT(!slot->network);
slot->network = ril_network_new(slot->io, log_prefix, slot->radio,
@@ -1076,6 +1199,7 @@ static struct ril_slot *ril_plugin_slot_new(const char *sockpath,
RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT;
slot->data_opt.data_call_retry_delay_ms =
RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY;
slot->pub.errors = g_hash_table_new(g_str_hash, g_str_equal);
return slot;
}
@@ -1236,6 +1360,27 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
g_free(slot->ecclist_file);
slot->ecclist_file = NULL;
}
slot->config.local_hangup_reasons = ril_config_get_ints(file,
group, RILCONF_LOCAL_HANGUP_REASONS);
strval = ril_config_ints_to_string(
slot->config.local_hangup_reasons, ',');
if (strval) {
DBG("%s: %s %s", group, RILCONF_LOCAL_HANGUP_REASONS,
strval);
g_free(strval);
}
slot->config.remote_hangup_reasons = ril_config_get_ints(file,
group, RILCONF_REMOTE_HANGUP_REASONS);
strval = ril_config_ints_to_string(
slot->config.remote_hangup_reasons, ',');
if (strval) {
DBG("%s: %s %s", group, RILCONF_REMOTE_HANGUP_REASONS,
strval);
g_free(strval);
}
} else {
DBG("no socket path in %s", group);
}
@@ -1248,8 +1393,12 @@ static void ril_plugin_delete_slot(struct ril_slot *slot)
ril_plugin_shutdown_slot(slot, TRUE);
ril_sim_info_unref(slot->sim_info);
ril_sim_settings_unref(slot->sim_settings);
gutil_ints_unref(slot->config.local_hangup_reasons);
gutil_ints_unref(slot->config.remote_hangup_reasons);
g_hash_table_destroy(slot->pub.errors);
g_free(slot->path);
g_free(slot->imei);
g_free(slot->imeisv);
g_free(slot->name);
g_free(slot->sockpath);
g_free(slot->sub);
@@ -1403,7 +1552,7 @@ static void ril_plugin_switch_user()
static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
{
if (slot->pub.enabled) {
DBG("%s enabled", slot->path + 1);
DBG("%s enabled", ril_slot_debug_prefix(slot));
ril_plugin_check_modem(slot);
}
}
@@ -1411,7 +1560,7 @@ static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
static void ril_plugin_update_disabled_slot(struct ril_slot *slot)
{
if (!slot->pub.enabled) {
DBG("%s disabled", slot->path + 1);
DBG("%s disabled", ril_slot_debug_prefix(slot));
ril_plugin_shutdown_slot(slot, FALSE);
ril_plugin_update_modem_paths_full(slot->plugin);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -48,10 +48,12 @@ typedef struct ril_slot_info const *ril_slot_info_ptr;
struct ril_slot_info {
const char *path;
const char *imei;
const char *imeisv;
const char *ecclist_file;
gboolean enabled;
gboolean sim_present;
const struct ril_slot_config *config;
GHashTable *errors;
};
struct ril_plugin {
@@ -68,6 +70,7 @@ struct ril_plugin {
struct ril_modem {
GRilIoChannel *io;
const char *imei;
const char *imeisv;
const char *log_prefix;
const char *ecclist_file;
struct ofono_modem *ofono;
@@ -123,6 +126,8 @@ void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
gboolean present);
void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
int index, const char *id, const char *message);
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
const struct ril_slot_info *slot, struct ril_radio *radio,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -46,7 +46,7 @@ struct ril_plugin_dbus {
#define RIL_DBUS_PATH "/"
#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
#define RIL_DBUS_INTERFACE_VERSION (5)
#define RIL_DBUS_INTERFACE_VERSION (7)
#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
@@ -57,8 +57,11 @@ struct ril_plugin_dbus {
#define RIL_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
#define RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
#define RIL_DBUS_SIGNAL_READY_CHANGED "ReadyChanged"
#define RIL_DBUS_SIGNAL_MODEM_ERROR "ModemError"
#define RIL_DBUS_IMSI_AUTO "auto"
#define RIL_DBUS_ERROR_SIGNATURE "si"
static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
{
return slot->enabled;
@@ -74,6 +77,11 @@ static const char *ril_plugin_dbus_imei(const struct ril_slot_info *slot)
return slot->imei;
}
static const char *ril_plugin_dbus_imeisv(const struct ril_slot_info *slot)
{
return slot->imeisv;
}
static void ril_plugin_dbus_append_path_array(DBusMessageIter *it,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn selector)
{
@@ -167,6 +175,48 @@ static void ril_plugin_dbus_message_append_path_array(DBusMessage *msg,
ril_plugin_dbus_append_path_array(&iter, dbus, fn);
}
static void ril_plugin_dbus_append_modem_error(DBusMessageIter *it,
const char *id, dbus_uint32_t count)
{
DBusMessageIter sub;
dbus_message_iter_open_container(it, DBUS_TYPE_STRUCT, NULL, &sub);
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id);
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &count);
dbus_message_iter_close_container(it, &sub);
}
static void ril_plugin_dbus_append_modem_errors(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
DBusMessageIter slots;
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
"a(" RIL_DBUS_ERROR_SIGNATURE ")", &slots);
while (*ptr) {
const struct ril_slot_info *slot = *ptr++;
DBusMessageIter errors;
dbus_message_iter_open_container(&slots, DBUS_TYPE_ARRAY,
"(" RIL_DBUS_ERROR_SIGNATURE ")", &errors);
if (g_hash_table_size(slot->errors)) {
gpointer key, value;
GHashTableIter iter;
g_hash_table_iter_init(&iter, slot->errors);
while (g_hash_table_iter_next(&iter, &key, &value)) {
ril_plugin_dbus_append_modem_error(&errors,
key, GPOINTER_TO_INT(value));
}
}
dbus_message_iter_close_container(&slots, &errors);
}
dbus_message_iter_close_container(it, &slots);
}
static void ril_plugin_dbus_signal_path_array(struct ril_plugin_dbus *dbus,
const char *name, ril_plugin_dbus_slot_select_fn fn)
{
@@ -257,6 +307,19 @@ void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
DBUS_TYPE_INVALID);
}
void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
int index, const char *id, const char *message)
{
const char *path = dbus->plugin->slots[index]->path;
if (!message) message = "";
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
RIL_DBUS_SIGNAL_MODEM_ERROR,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_STRING, &id,
DBUS_TYPE_STRING, &message,
DBUS_TYPE_INVALID);
}
static DBusMessage *ril_plugin_dbus_reply_with_path_array(DBusMessage *msg,
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
{
@@ -375,6 +438,20 @@ static void ril_plugin_dbus_append_all5(DBusMessageIter *it,
ril_plugin_dbus_append_boolean(it, dbus->plugin->ready);
}
static void ril_plugin_dbus_append_all6(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all5(it, dbus);
ril_plugin_dbus_append_modem_errors(it, dbus);
}
static void ril_plugin_dbus_append_all7(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all6(it, dbus);
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imeisv);
}
static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -410,6 +487,20 @@ static DBusMessage *ril_plugin_dbus_get_all5(DBusConnection *conn,
ril_plugin_dbus_append_all5);
}
static DBusMessage *ril_plugin_dbus_get_all6(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all6);
}
static DBusMessage *ril_plugin_dbus_get_all7(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all7);
}
static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -457,6 +548,19 @@ static DBusMessage *ril_plugin_dbus_get_imei(DBusConnection *conn,
ril_plugin_dbus_append_imei_array);
}
static void ril_plugin_dbus_append_imeisv_array(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imeisv);
}
static DBusMessage *ril_plugin_dbus_get_imeisv(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_imeisv_array);
}
static DBusMessage *ril_plugin_dbus_reply_with_string(DBusMessage *msg,
const char *str)
{
@@ -554,6 +658,13 @@ static DBusMessage *ril_plugin_dbus_get_ready(DBusConnection *conn,
return reply;
}
static DBusMessage *ril_plugin_dbus_get_modem_errors(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_modem_errors);
}
static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -697,28 +808,48 @@ static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
* talking to.
*/
#define RIL_DBUS_VERSION_ARG {"version", "i"}
#define RIL_DBUS_AVAILABLE_MODEMS_ARG {"availableModems", "ao"}
#define RIL_DBUS_ENABLED_MODEMS_ARG {"enabledModems", "ao" }
#define RIL_DBUS_DEFAULT_DATA_SIM_ARG {"defaultDataSim", "s" }
#define RIL_DBUS_DEFAULT_VOICE_SIM_ARG {"defaultVoiceSim", "s" }
#define RIL_DBUS_DEFAULT_DATA_MODEM_ARG {"defaultDataModem", "s" }
#define RIL_DBUS_DEFAULT_VOICE_MODEM_ARG {"defaultVoiceModem" , "s"}
#define RIL_DBUS_PRESENT_SIMS_ARG {"presentSims" , "ab"}
#define RIL_DBUS_IMEI_ARG {"imei" , "as"}
#define RIL_DBUS_MMS_SIM_ARG {"mmsSim", "s"}
#define RIL_DBUS_MMS_MODEM_ARG {"mmsModem" , "s"}
#define RIL_DBUS_READY_ARG {"ready" , "b"}
#define RIL_DBUS_MODEM_ERRORS_ARG {"errors" , \
"aa(" RIL_DBUS_ERROR_SIGNATURE ")"}
#define RIL_DBUS_IMEISV_ARG {"imeisv" , "as"}
#define RIL_DBUS_GET_ALL_ARGS \
{"version", "i" }, \
{"availableModems", "ao" }, \
{"enabledModems", "ao" }, \
{"defaultDataSim", "s" }, \
{"defaultVoiceSim", "s" }, \
{"defaultDataModem", "s" }, \
{"defaultVoiceModem" , "s"}
RIL_DBUS_VERSION_ARG, \
RIL_DBUS_AVAILABLE_MODEMS_ARG, \
RIL_DBUS_ENABLED_MODEMS_ARG, \
RIL_DBUS_DEFAULT_DATA_SIM_ARG, \
RIL_DBUS_DEFAULT_VOICE_SIM_ARG, \
RIL_DBUS_DEFAULT_DATA_MODEM_ARG, \
RIL_DBUS_DEFAULT_VOICE_MODEM_ARG
#define RIL_DBUS_GET_ALL2_ARGS \
RIL_DBUS_GET_ALL_ARGS, \
{"presentSims" , "ab"}
RIL_DBUS_PRESENT_SIMS_ARG
#define RIL_DBUS_GET_ALL3_ARGS \
RIL_DBUS_GET_ALL2_ARGS, \
{"imei" , "as"}
RIL_DBUS_IMEI_ARG
#define RIL_DBUS_GET_ALL4_ARGS \
RIL_DBUS_GET_ALL3_ARGS, \
{"mmsSim", "s" }, \
{"mmsModem" , "s"}
RIL_DBUS_MMS_SIM_ARG, \
RIL_DBUS_MMS_MODEM_ARG
#define RIL_DBUS_GET_ALL5_ARGS \
RIL_DBUS_GET_ALL4_ARGS, \
{"ready" , "b"}
RIL_DBUS_READY_ARG
#define RIL_DBUS_GET_ALL6_ARGS \
RIL_DBUS_GET_ALL5_ARGS, \
RIL_DBUS_MODEM_ERRORS_ARG
#define RIL_DBUS_GET_ALL7_ARGS \
RIL_DBUS_GET_ALL6_ARGS, \
RIL_DBUS_IMEISV_ARG
static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
@@ -735,42 +866,54 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_ASYNC_METHOD("GetAll5",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL5_ARGS),
ril_plugin_dbus_get_all5) },
{ GDBUS_ASYNC_METHOD("GetAll6",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL6_ARGS),
ril_plugin_dbus_get_all6) },
{ GDBUS_ASYNC_METHOD("GetAll7",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL7_ARGS),
ril_plugin_dbus_get_all7) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
NULL, GDBUS_ARGS(RIL_DBUS_VERSION_ARG),
ril_plugin_dbus_get_interface_version) },
{ GDBUS_METHOD("GetAvailableModems",
NULL, GDBUS_ARGS({ "modems", "ao" }),
NULL, GDBUS_ARGS(RIL_DBUS_AVAILABLE_MODEMS_ARG),
ril_plugin_dbus_get_available_modems) },
{ GDBUS_METHOD("GetEnabledModems",
NULL, GDBUS_ARGS({ "modems", "ao" }),
NULL, GDBUS_ARGS(RIL_DBUS_ENABLED_MODEMS_ARG),
ril_plugin_dbus_get_enabled_modems) },
{ GDBUS_METHOD("GetPresentSims",
NULL, GDBUS_ARGS({ "presentSims", "ab" }),
NULL, GDBUS_ARGS(RIL_DBUS_PRESENT_SIMS_ARG),
ril_plugin_dbus_get_present_sims) },
{ GDBUS_ASYNC_METHOD("GetIMEI",
NULL, GDBUS_ARGS({ "imei", "as" }),
NULL, GDBUS_ARGS(RIL_DBUS_IMEI_ARG),
ril_plugin_dbus_get_imei) },
{ GDBUS_ASYNC_METHOD("GetIMEISV",
NULL, GDBUS_ARGS(RIL_DBUS_IMEISV_ARG),
ril_plugin_dbus_get_imeisv) },
{ GDBUS_METHOD("GetDefaultDataSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG),
ril_plugin_dbus_get_default_data_sim) },
{ GDBUS_METHOD("GetDefaultVoiceSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG),
ril_plugin_dbus_get_default_voice_sim) },
{ GDBUS_METHOD("GetMmsSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG),
ril_plugin_dbus_get_mms_sim) },
{ GDBUS_METHOD("GetDefaultDataModem",
NULL, GDBUS_ARGS({ "path", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG),
ril_plugin_dbus_get_default_data_modem) },
{ GDBUS_METHOD("GetDefaultVoiceModem",
NULL, GDBUS_ARGS({ "path", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG),
ril_plugin_dbus_get_default_voice_modem) },
{ GDBUS_METHOD("GetMmsModem",
NULL, GDBUS_ARGS({ "path", "s" }),
NULL, GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG),
ril_plugin_dbus_get_mms_modem) },
{ GDBUS_METHOD("GetReady",
NULL, GDBUS_ARGS({ "ready", "b" }),
NULL, GDBUS_ARGS(RIL_DBUS_READY_ARG),
ril_plugin_dbus_get_ready) },
{ GDBUS_METHOD("GetModemErrors",
NULL, GDBUS_ARGS(RIL_DBUS_MODEM_ERRORS_ARG),
ril_plugin_dbus_get_modem_errors) },
{ GDBUS_METHOD("SetEnabledModems",
GDBUS_ARGS({ "modems", "ao" }), NULL,
ril_plugin_dbus_set_enabled_modems) },
@@ -788,24 +931,28 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
static const GDBusSignalTable ril_plugin_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
GDBUS_ARGS({ "modems", "ao" })) },
GDBUS_ARGS(RIL_DBUS_ENABLED_MODEMS_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
GDBUS_ARGS({"index", "i" },
{"present" , "b"})) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_READY_CHANGED,
GDBUS_ARGS({ "ready", "b" })) },
GDBUS_ARGS(RIL_DBUS_READY_ARG)) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MODEM_ERROR,
GDBUS_ARGS({"path","o"},
{"error_id", "s"},
{"message", "s"})) },
{ }
};

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -85,6 +85,7 @@ struct ril_sim {
ofono_sim_passwd_cb_t query_passwd_state_cb;
void *query_passwd_state_cb_data;
guint query_passwd_state_timeout_id;
gulong query_passwd_state_sim_status_refresh_id;
};
struct ril_sim_io_response {
@@ -691,6 +692,12 @@ static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
sd->query_passwd_state_timeout_id = 0;
}
if (sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
sd->query_passwd_state_sim_status_refresh_id = 0;
}
if (sd->query_passwd_state_cb) {
ofono_sim_passwd_cb_t cb = sd->query_passwd_state_cb;
void *data = sd->query_passwd_state_cb_data;
@@ -884,6 +891,15 @@ static void ril_sim_query_pin_retries(struct ofono_sim *sim,
cb(ril_error_ok(&error), sd->retries, data);
}
static void ril_sim_query_passwd_state_complete_cb(struct ril_sim_card *sc,
void *user_data)
{
struct ril_sim *sd = user_data;
GASSERT(sd->query_passwd_state_sim_status_refresh_id);
ril_sim_finish_passwd_state_query(sd, ril_sim_passwd_state(sd));
}
static gboolean ril_sim_query_passwd_state_timeout_cb(gpointer user_data)
{
struct ril_sim *sd = user_data;
@@ -899,29 +915,41 @@ static void ril_sim_query_passwd_state(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
enum ofono_sim_password_type passwd_state = ril_sim_passwd_state(sd);
struct ofono_error error;
if (sd->query_passwd_state_timeout_id) {
g_source_remove(sd->query_passwd_state_timeout_id);
sd->query_passwd_state_timeout_id = 0;
}
if (passwd_state != OFONO_SIM_PASSWORD_INVALID) {
DBG_(sd, "%d", passwd_state);
sd->query_passwd_state_cb = NULL;
sd->query_passwd_state_cb_data = NULL;
sd->ofono_passwd_state = passwd_state;
cb(ril_error_ok(&error), passwd_state, data);
if (!sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
sd->query_passwd_state_sim_status_refresh_id = 0;
}
/* Always request fresh status, just in case. */
ril_sim_card_request_status(sd->card);
sd->query_passwd_state_cb = cb;
sd->query_passwd_state_cb_data = data;
if (ril_sim_passwd_state(sd) != OFONO_SIM_PASSWORD_INVALID) {
/* Just wait for GET_SIM_STATUS completion */
DBG_(sd, "waiting for SIM status query to complete");
sd->query_passwd_state_sim_status_refresh_id =
ril_sim_card_add_status_received_handler(sd->card,
ril_sim_query_passwd_state_complete_cb, sd);
} else {
/* Wait for the state to change */
DBG_(sd, "waiting for the SIM state to change");
sd->query_passwd_state_cb = cb;
sd->query_passwd_state_cb_data = data;
sd->query_passwd_state_timeout_id =
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
ril_sim_query_passwd_state_timeout_cb, sd);
}
/*
* We still need to complete the request somehow, even if
* GET_STATUS never completes or SIM status never changes.
*/
sd->query_passwd_state_timeout_id =
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
ril_sim_query_passwd_state_timeout_cb, sd);
}
static gboolean ril_sim_pin_change_state_timeout_cb(gpointer user_data)
@@ -1280,6 +1308,11 @@ static void ril_sim_remove(struct ofono_sim *sim)
g_source_remove(sd->query_passwd_state_timeout_id);
}
if (sd->query_passwd_state_sim_status_refresh_id) {
ril_sim_card_remove_handler(sd->card,
sd->query_passwd_state_sim_status_refresh_id);
}
ril_sim_card_remove_handler(sd->card, sd->card_status_id);
ril_sim_card_unref(sd->card);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -64,8 +64,6 @@ G_DEFINE_TYPE(RilSimCard, ril_sim_card, G_TYPE_OBJECT)
#define RIL_SIMCARD_STATE_CHANGED (0x01)
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
static void ril_sim_card_request_status(struct ril_sim_card *self);
static gboolean ril_sim_card_app_equal(const struct ril_sim_card_app *a1,
const struct ril_sim_card_app *a2)
{
@@ -365,7 +363,7 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
}
}
static void ril_sim_card_request_status(struct ril_sim_card *self)
void ril_sim_card_request_status(struct ril_sim_card *self)
{
struct ril_sim_card_priv *priv = self->priv;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -55,6 +55,7 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
void ril_sim_card_unref(struct ril_sim_card *sc);
void ril_sim_card_request_status(struct ril_sim_card *self);
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);

View File

@@ -142,3 +142,12 @@ socket=/dev/socket/rild
# Default is 200 ms
#
#dataCallRetryDelay=200
# Additional local and remote hangup reasons. Remote reasons are checked
# first. Normally, RIL plugin figures it out automatically. You would only
# need to define these if your RIL does something unusual.
#
# No default
#
#remoteHangupReasons=20
#localHangupReasons=23

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -53,6 +53,8 @@ struct ril_slot_config {
guint slot;
gboolean enable_4g;
gboolean empty_pin_query;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
};
#endif /* RIL_TYPES_H */

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2016 Jolla Ltd.
* Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,6 +21,7 @@
#include "common.h"
#include <gutil_ints.h>
#include <gutil_ring.h>
#define FLAG_NEED_CLIP 1
@@ -43,7 +44,9 @@ struct ril_voicecall {
ofono_voicecall_cb_t cb;
void *data;
guint timer_id;
GUtilRing* dtmf_queue;
GUtilRing *dtmf_queue;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
guint send_dtmf_id;
guint clcc_poll_id;
gulong event_id[VOICECALL_EVENT_COUNT];
@@ -60,28 +63,13 @@ struct ril_voicecall_change_state_req {
};
struct lastcause_req {
struct ofono_voicecall *vc;
struct ril_voicecall *vd;
int id;
};
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
/*
* structs ofono_voicecall and voicecall are fully defined
* in src/voicecall.c; we need (read) access to the
* call objects, so partially redefine them here.
*/
struct ofono_voicecall {
GSList *call_list;
/* ... */
};
struct voicecall {
struct ofono_call *call;
/* ... */
};
static inline struct ril_voicecall *ril_voicecall_get_data(
struct ofono_voicecall *vc)
{
@@ -166,38 +154,76 @@ static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
}
/* Valid call statuses have value >= 0 */
static int call_status_with_id(struct ofono_voicecall *vc, int id)
static int ril_voicecall_status_with_id(struct ofono_voicecall *vc,
unsigned int id)
{
GSList *l;
struct voicecall *v;
struct ofono_call *call = ofono_voicecall_find_call(vc, id);
GASSERT(vc);
return call ? call->status : -1;
}
for (l = vc->call_list; l; l = l->next) {
v = l->data;
if (v->call->id == id) {
return v->call->status;
/* Tries to parse the payload as a uint followed by a string */
static int ril_voicecall_parse_lastcause_1(const void *data, guint len)
{
int result = -1;
if (len > 8) {
int code;
char *msg = NULL;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &code) && code >= 0 &&
(msg = grilio_parser_get_utf8(&rilp)) &&
grilio_parser_at_end(&rilp)) {
DBG("%d \"%s\"", code, msg);
result = code;
}
g_free(msg);
}
return -1;
return result;
}
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct lastcause_req *reqdata = user_data;
struct ofono_voicecall *vc = reqdata->vc;
int tmp;
struct ril_voicecall *vd = reqdata->vd;
struct ofono_voicecall *vc = vd->vc;
int id = reqdata->id;
int call_status;
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
grilio_parser_get_int32(&rilp, &last_cause);
int last_cause;
/*
* According to ril.h:
*
* "response" is a "int *"
* ((int *)response)[0] is RIL_LastCallFailCause. GSM failure
* reasons are mapped to cause codes defined in TS 24.008 Annex H
* where possible.
*
* However some RILs feel free to invent their own formats,
* try those first.
*/
last_cause = ril_voicecall_parse_lastcause_1(data, len);
if (last_cause < 0) {
GRilIoParser rilp;
int num, code;
/* Default format described in ril.h */
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &num) && num == 1 &&
grilio_parser_get_int32(&rilp, &code) &&
grilio_parser_at_end(&rilp)) {
last_cause = code;
} else {
ofono_warn("Unable to parse last call fail cause");
last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
}
}
/*
@@ -208,7 +234,14 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
* from a network failure.
*/
switch (last_cause) {
if (gutil_ints_contains(vd->remote_hangup_reasons, last_cause)) {
DBG("hangup cause %d => remote hangup", last_cause);
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
} else if (gutil_ints_contains(vd->local_hangup_reasons, last_cause)) {
DBG("hangup cause %d => local hangup", last_cause);
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
} else {
switch (last_cause) {
case CALL_FAIL_UNOBTAINABLE_NUMBER:
case CALL_FAIL_NORMAL:
case CALL_FAIL_BUSY:
@@ -216,19 +249,19 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
case CALL_FAIL_CHANNEL_UNACCEPTABLE:
case CALL_FAIL_OPERATOR_DETERMINED_BARRING:
case CALL_FAIL_NO_USER_RESPONDING:
case CALL_FAIL_USER_ALERTING_NO_ANSWER:
case CALL_FAIL_NO_ANSWER_FROM_USER:
case CALL_FAIL_CALL_REJECTED:
case CALL_FAIL_NUMBER_CHANGED:
case CALL_FAIL_ANONYMOUS_CALL_REJECTION:
case CALL_FAIL_PRE_EMPTION:
case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
case CALL_FAIL_INCOMPLETE_NUMBER:
case CALL_FAIL_INVALID_NUMBER_FORMAT:
case CALL_FAIL_FACILITY_REJECTED:
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
break;
case CALL_FAIL_NORMAL_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
call_status = ril_voicecall_status_with_id(vc, id);
if (call_status == CALL_STATUS_ACTIVE ||
call_status == CALL_STATUS_HELD ||
call_status == CALL_STATUS_DIALING ||
@@ -240,7 +273,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
break;
case CALL_FAIL_ERROR_UNSPECIFIED:
call_status = call_status_with_id(vc, id);
call_status = ril_voicecall_status_with_id(vc, id);
if (call_status == CALL_STATUS_DIALING ||
call_status == CALL_STATUS_ALERTING) {
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
@@ -250,6 +283,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
default:
reason = OFONO_DISCONNECT_REASON_ERROR;
break;
}
}
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
@@ -295,7 +329,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
struct lastcause_req *reqdata =
g_new0(struct lastcause_req, 1);
reqdata->vc = vd->vc;
reqdata->vd = vd;
reqdata->id = oc->id;
grilio_queue_send_request_full(vd->q, NULL,
RIL_REQUEST_LAST_CALL_FAIL_CAUSE,
@@ -803,6 +837,7 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
void *data)
{
struct ril_modem *modem = data;
const struct ril_slot_config *cfg = &modem->config;
struct ril_voicecall *vd;
DBG("");
@@ -810,6 +845,8 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
vd->io = grilio_channel_ref(ril_modem_io(modem));
vd->q = grilio_queue_new(vd->io);
vd->dtmf_queue = gutil_ring_new();
vd->local_hangup_reasons = gutil_ints_ref(cfg->local_hangup_reasons);
vd->remote_hangup_reasons = gutil_ints_ref(cfg->remote_hangup_reasons);
vd->vc = vc;
vd->timer_id = g_idle_add(ril_delayed_register, vd);
if (modem->ecclist_file) {
@@ -841,6 +878,8 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
grilio_queue_cancel_all(vd->q, FALSE);
grilio_queue_unref(vd->q);
gutil_ring_unref(vd->dtmf_queue);
gutil_ints_unref(vd->local_hangup_reasons);
gutil_ints_unref(vd->remote_hangup_reasons);
g_free(vd);
}

View File

@@ -261,6 +261,7 @@ static void ublox_send_uauthreq(struct ofono_gprs_context *gc,
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = 1;
break;
case OFONO_GPRS_AUTH_METHOD_ANY:
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = 2;
break;

View File

@@ -49,7 +49,9 @@ enum ofono_gprs_context_type {
};
enum ofono_gprs_auth_method {
OFONO_GPRS_AUTH_METHOD_CHAP = 0,
OFONO_GPRS_AUTH_METHOD_ANY = 0,
OFONO_GPRS_AUTH_METHOD_NONE,
OFONO_GPRS_AUTH_METHOD_CHAP,
OFONO_GPRS_AUTH_METHOD_PAP,
};

View File

@@ -172,6 +172,8 @@ void ofono_voicecall_ssn_mt_notify(struct ofono_voicecall *vc, unsigned int id,
int code, int index,
const struct ofono_phone_number *ph);
struct ofono_call *ofono_voicecall_find_call(struct ofono_voicecall *vc,
unsigned int id);
void ofono_voicecall_ringback_tone_notify(struct ofono_voicecall *vc,
const ofono_bool_t playTone);

View File

@@ -53,6 +53,9 @@ const char *mbpi_database = MBPI_DATABASE;
enum ofono_gprs_proto mbpi_default_internet_proto = OFONO_GPRS_PROTO_IPV4V6;
enum ofono_gprs_proto mbpi_default_mms_proto = OFONO_GPRS_PROTO_IP;
enum ofono_gprs_proto mbpi_default_proto = OFONO_GPRS_PROTO_IP;
enum ofono_gprs_auth_method mbpi_default_auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
#define OFONO_GPRS_AUTH_METHOD_UNSPECIFIED ((enum ofono_gprs_auth_method)(-1))
#define _(x) case x: return (#x)
@@ -166,6 +169,10 @@ static void authentication_start(GMarkupParseContext *context,
*auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
else if (strcmp(text, "pap") == 0)
*auth_method = OFONO_GPRS_AUTH_METHOD_PAP;
else if (strcmp(text, "any") == 0)
*auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
else if (strcmp(text, "none") == 0)
*auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
else
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
@@ -344,7 +351,7 @@ static void apn_handler(GMarkupParseContext *context, struct gsm_data *gsm,
ap->apn = g_strdup(apn);
ap->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
ap->proto = mbpi_default_proto;
ap->auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
ap->auth_method = OFONO_GPRS_AUTH_METHOD_UNSPECIFIED;
g_markup_parse_context_push(context, &apn_parser, ap);
}
@@ -414,6 +421,17 @@ static void gsm_end(GMarkupParseContext *context, const gchar *element_name,
if (ap == NULL)
return;
/* Fix the authentication method if none was specified */
if (ap->auth_method == OFONO_GPRS_AUTH_METHOD_UNSPECIFIED) {
if ((!ap->username || !ap->username[0]) &&
(!ap->password || !ap->password[0])) {
/* No username or password => no authentication */
ap->auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
} else {
ap->auth_method = mbpi_default_auth_method;
}
}
if (gsm->allow_duplicates == FALSE) {
GSList *l;

View File

@@ -23,6 +23,7 @@ extern const char *mbpi_database;
extern enum ofono_gprs_proto mbpi_default_internet_proto;
extern enum ofono_gprs_proto mbpi_default_mms_proto;
extern enum ofono_gprs_proto mbpi_default_proto;
extern enum ofono_gprs_auth_method mbpi_default_auth_method;
const char *mbpi_ap_type(enum ofono_gprs_context_type type);

View File

@@ -3,7 +3,6 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,7 +23,6 @@
#include <config.h>
#endif
#define _GNU_SOURCE
#include <errno.h>
#include <string.h>
@@ -37,114 +35,9 @@
#include <ofono/modem.h>
#include <ofono/gprs-provision.h>
#include "provision.h"
#include "mbpi.h"
struct provision_ap_defaults {
enum ofono_gprs_context_type type;
const char *name;
const char *apn;
};
static gboolean provision_match_name(const struct ofono_gprs_provision_data *ap,
const char* spn)
{
return (ap->provider_name && strcasestr(ap->provider_name, spn)) ||
(ap->name && strcasestr(ap->name, spn)) ||
(ap->apn && strcasestr(ap->apn, spn));
}
static void provision_free_ap(gpointer data)
{
mbpi_ap_free(data);
}
static gint provision_compare_ap(gconstpointer a, gconstpointer b, gpointer data)
{
const struct ofono_gprs_provision_data *ap1 = a;
const struct ofono_gprs_provision_data *ap2 = b;
const char* spn = data;
if (spn) {
const gboolean match1 = provision_match_name(ap1, spn);
const gboolean match2 = provision_match_name(ap2, spn);
if (match1 && !match2) {
return -1;
} else if (match2 && !match1) {
return 1;
}
}
if (ap1->provider_primary && !ap2->provider_primary) {
return -1;
} else if (ap2->provider_primary && !ap1->provider_primary) {
return 1;
} else {
return 0;
}
}
/* Picks best ap, deletes the rest. Creates one if necessary */
static GSList *provision_pick_best_ap(GSList *list, const char* spn,
const enum ofono_gprs_proto default_proto,
const struct provision_ap_defaults *defaults)
{
/* Sort the list */
list = g_slist_sort_with_data(list, provision_compare_ap, (void*)spn);
if (list) {
/* Pick the best one, delete the rest */
GSList *best = list;
g_slist_free_full(g_slist_remove_link(list, best),
provision_free_ap);
return best;
} else {
/* or create one from the default data */
struct ofono_gprs_provision_data *ap =
g_new0(struct ofono_gprs_provision_data, 1);
ap->proto = default_proto;
ap->type = defaults->type;
ap->name = g_strdup(defaults->name);
ap->apn = g_strdup(defaults->apn);
return g_slist_append(NULL, ap);
}
}
/* Returns the list containing exactly one INTERNET and one MMS access point */
static GSList *provision_normalize_apn_list(GSList *apns, const char* spn)
{
static const struct provision_ap_defaults internet_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
static const struct provision_ap_defaults mms_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
GSList *internet_apns = NULL;
GSList *mms_apns = NULL;
/* Split internet and mms apns, delete all others */
while (apns) {
GSList *link = apns;
struct ofono_gprs_provision_data *ap = link->data;
apns = g_slist_remove_link(apns, link);
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
internet_apns = g_slist_concat(internet_apns, link);
} else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
mms_apns = g_slist_concat(mms_apns, link);
} else {
g_slist_free_full(link, provision_free_ap);
}
}
/* Pick the best ap of each type and concatenate them */
return g_slist_concat(
provision_pick_best_ap(internet_apns, spn,
mbpi_default_internet_proto, &internet_defaults),
provision_pick_best_ap(mms_apns, spn,
mbpi_default_mms_proto, &mms_defaults));
}
int provision_get_settings(const char *mcc, const char *mnc,
static int provision_get_settings(const char *mcc, const char *mnc,
const char *spn,
struct ofono_gprs_provision_data **settings,
int *count)
@@ -155,26 +48,21 @@ int provision_get_settings(const char *mcc, const char *mnc,
int ap_count;
int i;
ofono_info("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
DBG("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
/*
* Passing FALSE to mbpi_lookup_apn() would return
* an empty list if duplicates are found.
*/
apns = mbpi_lookup_apn(mcc, mnc, TRUE, &error);
if (error != NULL) {
ofono_error("%s", error->message);
g_error_free(error);
}
apns = mbpi_lookup_apn(mcc, mnc, FALSE, &error);
if (apns == NULL) {
if (error != NULL) {
ofono_error("%s", error->message);
g_error_free(error);
}
ofono_info("Found %d APs in MBPI", g_slist_length(apns));
apns = provision_normalize_apn_list(apns, spn);
if (apns == NULL)
return -ENOENT;
}
ap_count = g_slist_length(apns);
ofono_info("Provisioning %d APs", ap_count);
DBG("Found %d APs", ap_count);
*settings = g_try_new0(struct ofono_gprs_provision_data, ap_count);
if (*settings == NULL) {
@@ -193,11 +81,11 @@ int provision_get_settings(const char *mcc, const char *mnc,
for (l = apns, i = 0; l; l = l->next, i++) {
struct ofono_gprs_provision_data *ap = l->data;
ofono_info("Name: '%s'", ap->name);
ofono_info("APN: '%s'", ap->apn);
ofono_info("Type: %s", mbpi_ap_type(ap->type));
ofono_info("Username: '%s'", ap->username);
ofono_info("Password: '%s'", ap->password);
DBG("Name: '%s'", ap->name);
DBG("APN: '%s'", ap->apn);
DBG("Type: %s", mbpi_ap_type(ap->type));
DBG("Username: '%s'", ap->username);
DBG("Password: '%s'", ap->password);
memcpy(*settings + i, ap,
sizeof(struct ofono_gprs_provision_data));

View File

@@ -0,0 +1,251 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <errno.h>
#include <string.h>
#include <glib.h>
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/log.h>
#include <ofono/plugin.h>
#include <ofono/modem.h>
#include <ofono/gprs-provision.h>
#include "provision.h"
#include "mbpi.h"
struct provision_ap_defaults {
enum ofono_gprs_context_type type;
const char *name;
const char *apn;
};
static gint provision_match_strings(const char *s1, const char *s2)
{
gint match = 0;
/* Caller checks s2 for NULL */
if (s1) {
const gssize len1 = strlen(s1);
const gssize len2 = strlen(s2);
if (len1 == len2 && !strcmp(s1, s2)) {
/* Best match ever */
match = 3;
} else if (g_utf8_validate(s1, len1, NULL) &&
g_utf8_validate(s2, len2, NULL)) {
char *d1 = g_utf8_strdown(s1, len1);
char *d2 = g_utf8_strdown(s2, len2);
if (len1 == len2 && !strcmp(d1, d2)) {
/* Case insensitive match */
match = 2;
} else if ((len1 > len2 && strstr(d1, d2)) ||
(len2 > len1 && strstr(d2, d1))) {
/* Partial case insensitive match */
match = 1;
}
g_free(d1);
g_free(d2);
}
}
return match;
}
static gint provision_match_spn(const struct ofono_gprs_provision_data *ap,
const char *spn)
{
return provision_match_strings(ap->provider_name, spn) * 4 +
provision_match_strings(ap->name, spn);
}
static void provision_free_ap(gpointer data)
{
mbpi_ap_free(data);
}
static gint provision_compare_ap(gconstpointer a, gconstpointer b,
gpointer data)
{
const struct ofono_gprs_provision_data *ap1 = a;
const struct ofono_gprs_provision_data *ap2 = b;
const char *spn = data;
if (spn) {
const gint result = provision_match_spn(ap2, spn) -
provision_match_spn(ap1, spn);
if (result) {
return result;
}
}
if (ap1->provider_primary && !ap2->provider_primary) {
return -1;
} else if (ap2->provider_primary && !ap1->provider_primary) {
return 1;
}
return 0;
}
/* Picks best ap, deletes the rest. Creates one if necessary */
static GSList *provision_pick_best_ap(GSList *list, const char *spn,
const enum ofono_gprs_proto default_proto,
const struct provision_ap_defaults *defaults)
{
/* Sort the list */
list = g_slist_sort_with_data(list, provision_compare_ap, (void*)spn);
if (list) {
/* Pick the best one, delete the rest */
GSList *best = list;
g_slist_free_full(g_slist_remove_link(list, best),
provision_free_ap);
return best;
} else {
/* or create one from the default data */
struct ofono_gprs_provision_data *ap =
g_new0(struct ofono_gprs_provision_data, 1);
ap->proto = default_proto;
ap->type = defaults->type;
ap->name = g_strdup(defaults->name);
ap->apn = g_strdup(defaults->apn);
ap->auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
return g_slist_append(NULL, ap);
}
}
/* Returns the list containing exactly one INTERNET and one MMS access point */
static GSList *provision_normalize_apn_list(GSList *apns, const char *spn)
{
static const struct provision_ap_defaults internet_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
static const struct provision_ap_defaults mms_defaults =
{ OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
GSList *internet_apns = NULL;
GSList *mms_apns = NULL;
/* Split internet and mms apns, delete all others */
while (apns) {
GSList *link = apns;
struct ofono_gprs_provision_data *ap = link->data;
apns = g_slist_remove_link(apns, link);
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
internet_apns = g_slist_concat(internet_apns, link);
} else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
mms_apns = g_slist_concat(mms_apns, link);
} else {
g_slist_free_full(link, provision_free_ap);
}
}
/* Pick the best ap of each type and concatenate them */
return g_slist_concat(
provision_pick_best_ap(internet_apns, spn,
mbpi_default_internet_proto, &internet_defaults),
provision_pick_best_ap(mms_apns, spn,
mbpi_default_mms_proto, &mms_defaults));
}
int provision_get_settings(const char *mcc, const char *mnc,
const char *spn,
struct ofono_gprs_provision_data **settings,
int *count)
{
GSList *l;
GSList *apns;
GError *error = NULL;
int ap_count;
int i;
ofono_info("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
/*
* Passing FALSE to mbpi_lookup_apn() would return
* an empty list if duplicates are found.
*/
apns = mbpi_lookup_apn(mcc, mnc, TRUE, &error);
if (error != NULL) {
ofono_error("%s", error->message);
g_error_free(error);
}
DBG("Found %d APs in MBPI", g_slist_length(apns));
apns = provision_normalize_apn_list(apns, spn);
ap_count = g_slist_length(apns);
DBG("Provisioning %d APs", ap_count);
*settings = g_new0(struct ofono_gprs_provision_data, ap_count);
*count = ap_count;
for (l = apns, i = 0; l; l = l->next, i++) {
struct ofono_gprs_provision_data *ap = l->data;
ofono_info("Name: '%s'", ap->name);
ofono_info(" APN: '%s'", ap->apn);
ofono_info(" Type: %s", mbpi_ap_type(ap->type));
ofono_info(" Username: '%s'", ap->username);
ofono_info(" Password: '%s'", ap->password);
memcpy(*settings + i, ap,
sizeof(struct ofono_gprs_provision_data));
g_free(ap);
}
g_slist_free(apns);
return 0;
}
static struct ofono_gprs_provision_driver provision_driver = {
.name = "Provisioning",
.get_settings = provision_get_settings
};
static int provision_init(void)
{
DBG("");
return ofono_gprs_provision_driver_register(&provision_driver);
}
static void provision_exit(void)
{
DBG("");
ofono_gprs_provision_driver_unregister(&provision_driver);
}
OFONO_PLUGIN_DEFINE(provision, "Provisioning Plugin", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT,
provision_init, provision_exit)
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

362
ofono/plugins/sfos_bt.c Normal file
View File

@@ -0,0 +1,362 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <glib.h>
#include <ofono.h>
#include <gdbus.h>
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include <ofono/log.h>
#define SFOS_BT_DBUS_CV_INTERFACE "org.nemomobile.ofono.bluetooth.CallVolume"
#define HFP_CALL_VOLUME_MAX 15
struct sfos_bt {
unsigned int emu_watch;
struct ofono_modem *modem;
struct ofono_emulator *em;
unsigned char speaker_volume;
unsigned char microphone_volume;
};
static GSList *modems;
static guint modemwatch_id;
static void set_hfp_microphone_volume(struct sfos_bt *sfos_bt,
unsigned char gain)
{
char buf[64];
snprintf(buf, sizeof(buf), "+VGM:%d", (int) gain);
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
}
static void set_hfp_speaker_volume(struct sfos_bt *sfos_bt,
unsigned char gain)
{
char buf[64];
snprintf(buf, sizeof(buf), "+VGS:%d", (int) gain);
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
}
static DBusMessage *cv_set_property(DBusConnection *conn, DBusMessage *msg,
void *data)
{
struct sfos_bt *sfos_bt = data;
DBusMessageIter iter;
DBusMessageIter var;
const char *property;
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_str_equal(property, "SpeakerVolume") == TRUE) {
unsigned char gain;
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BYTE)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &gain);
if (gain > HFP_CALL_VOLUME_MAX)
return __ofono_error_invalid_format(msg);
if (gain == sfos_bt->speaker_volume)
return dbus_message_new_method_return(msg);
DBG("SpeakerVolume:%d", gain);
sfos_bt->speaker_volume = gain;
set_hfp_speaker_volume(sfos_bt, gain);
return dbus_message_new_method_return(msg);
} else if (g_str_equal(property, "MicrophoneVolume") == TRUE) {
unsigned char gain;
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BYTE)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &gain);
if (gain > HFP_CALL_VOLUME_MAX)
return __ofono_error_invalid_format(msg);
if (gain == sfos_bt->microphone_volume)
return dbus_message_new_method_return(msg);
DBG("MicrophoneVolume:%d", gain);
sfos_bt->microphone_volume = gain;
set_hfp_microphone_volume(sfos_bt, gain);
return dbus_message_new_method_return(msg);
} else if (g_str_equal(property, "Muted") == TRUE) {
unsigned char gain;
dbus_bool_t muted;
/*Remove when supported*/
return __ofono_error_not_implemented(msg);
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &muted);
if (muted)
gain = 0;
else
gain = 7;/* rather gain = sfos->old_mic_vol */
if (gain == sfos_bt->microphone_volume)
return dbus_message_new_method_return(msg);
sfos_bt->microphone_volume = gain;
set_hfp_microphone_volume(sfos_bt, gain);
return dbus_message_new_method_return(msg);
}
return __ofono_error_invalid_args(msg);
}
static const GDBusMethodTable cv_methods[] = {
{ GDBUS_METHOD("SetProperty",
GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
NULL, cv_set_property) },
{ }
};
static const GDBusSignalTable cv_signals[] = {
{ GDBUS_SIGNAL("PropertyChanged",
GDBUS_ARGS({ "property", "s" }, { "value", "v" })) },
{ }
};
int sfos_bt_call_volume_set(struct ofono_modem *modem, unsigned char volume,
const char *gain)
{
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = ofono_modem_get_path(modem);
return ofono_dbus_signal_property_changed(conn, path,
SFOS_BT_DBUS_CV_INTERFACE,
gain,
DBUS_TYPE_BYTE, &volume);
}
static void set_gain(struct ofono_emulator *em,
struct ofono_emulator_request *req,
void *userdata, const char *gain)
{
struct sfos_bt *sfos_bt = userdata;
struct ofono_modem *modem = sfos_bt->modem;
struct ofono_error result;
unsigned char volume;
int val;
result.error = 0;
switch (ofono_emulator_request_get_type(req)) {
case OFONO_EMULATOR_REQUEST_TYPE_SET:
if (ofono_emulator_request_next_number(req, &val) == FALSE)
goto fail;
if (val < 0 || val > 0xffff || val > HFP_CALL_VOLUME_MAX)
goto fail;
DBG("gain:%d", val);
volume = (unsigned char) val;
if (sfos_bt_call_volume_set(modem, volume, gain)<= 0)
goto fail;
if (!g_strcmp0(gain, "SpeakerVolume"))
sfos_bt->speaker_volume = volume;
else
sfos_bt->microphone_volume = volume;
result.type = OFONO_ERROR_TYPE_NO_ERROR;
ofono_emulator_send_final(em, &result);
break;
default:
fail:
result.type = OFONO_ERROR_TYPE_FAILURE;
ofono_emulator_send_final(em, &result);
break;
}
}
static void sfos_bt_vgm_cb(struct ofono_emulator *em,
struct ofono_emulator_request *req, void *userdata)
{
const char *gain = "MicrophoneVolume";
set_gain(em, req, userdata, gain);
}
static void sfos_bt_vgs_cb(struct ofono_emulator *em,
struct ofono_emulator_request *req, void *userdata)
{
const char *gain = "SpeakerVolume";
set_gain(em, req, userdata, gain);
}
void sfos_bt_cv_dbus_new(struct sfos_bt *sfos_bt)
{
DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = sfos_bt->modem;
const char *path = ofono_modem_get_path(modem);
if (g_dbus_register_interface(conn, path,
SFOS_BT_DBUS_CV_INTERFACE, cv_methods,
cv_signals, NULL, sfos_bt, NULL)){
ofono_modem_add_interface(modem,SFOS_BT_DBUS_CV_INTERFACE);
return;
}
ofono_error("D-Bus register failed");
}
static void sfos_bt_remove_handler(struct ofono_emulator *em)
{
ofono_emulator_remove_handler(em, "+VGS");
ofono_emulator_remove_handler(em, "+VGM");
}
void sfos_bt_cv_dbus_free(struct sfos_bt *sfos_bt)
{
DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = sfos_bt->modem;
const char *path = ofono_modem_get_path(modem);
ofono_modem_remove_interface(modem, SFOS_BT_DBUS_CV_INTERFACE);
g_dbus_unregister_interface(conn, path,
SFOS_BT_DBUS_CV_INTERFACE);
}
static void sfos_bt_emu_watch_cb(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond,
void *data)
{
struct sfos_bt *sfos_bt = data;
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED){
sfos_bt->em = __ofono_atom_get_data(atom);
sfos_bt_cv_dbus_new(sfos_bt);
ofono_emulator_add_handler(sfos_bt->em, "+VGS",
sfos_bt_vgs_cb, sfos_bt, NULL);
ofono_emulator_add_handler(sfos_bt->em, "+VGM",
sfos_bt_vgm_cb, sfos_bt, NULL);
} else {
sfos_bt_cv_dbus_free(sfos_bt);
sfos_bt_remove_handler(sfos_bt->em);
sfos_bt->em = NULL;
}
}
static void sfos_bt_emu_watch_destroy(void *data)
{
struct sfos_bt *sfos_bt = data;
sfos_bt->emu_watch = 0;
}
static void sfos_bt_free(void *data)
{
struct sfos_bt *sfos_bt = data;
if (sfos_bt->emu_watch)
__ofono_modem_remove_atom_watch(sfos_bt->modem,
sfos_bt->emu_watch);
if (sfos_bt->em) {
sfos_bt_cv_dbus_free(sfos_bt);
sfos_bt_remove_handler(sfos_bt->em);
}
g_free(sfos_bt);
}
static gint sfos_bt_find_modem(gconstpointer listdata, gconstpointer modem)
{
const struct sfos_bt *sfos_bt = listdata;
return (sfos_bt->modem != modem);
}
static void modem_watch(struct ofono_modem *modem, gboolean added, void *user)
{
struct sfos_bt *sfos_bt;
DBG("modem: %p, added: %d", modem, added);
if (added) {
sfos_bt = g_new0(struct sfos_bt, 1);
modems = g_slist_append(modems, sfos_bt);
sfos_bt->emu_watch = __ofono_modem_add_atom_watch(modem,
OFONO_ATOM_TYPE_EMULATOR_HFP, sfos_bt_emu_watch_cb,
sfos_bt, sfos_bt_emu_watch_destroy);
sfos_bt->modem = modem;
} else {
GSList *link = g_slist_find_custom(modems, modem,
sfos_bt_find_modem);
if (link) {
sfos_bt_free(link->data);
modems = g_slist_delete_link(modems, link);
}
}
}
static void call_modemwatch(struct ofono_modem *modem, void *user)
{
modem_watch(modem, TRUE, user);
}
static int sfos_bt_init(void)
{
modemwatch_id = __ofono_modemwatch_add(modem_watch, NULL, NULL);
__ofono_modem_foreach(call_modemwatch, NULL);
return 0;
}
static void sfos_bt_exit(void)
{
DBG("");
__ofono_modemwatch_remove(modemwatch_id);
g_slist_free_full(modems, sfos_bt_free);
}
OFONO_PLUGIN_DEFINE(sfos_bt, "Sailfish OS Bluetooth Plugin", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT,
sfos_bt_init, sfos_bt_exit)

View File

@@ -34,6 +34,7 @@
#include <net/route.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <glib.h>
#include <gdbus.h>
@@ -258,6 +259,10 @@ static gboolean gprs_proto_from_string(const char *str,
static const char *gprs_auth_method_to_string(enum ofono_gprs_auth_method auth)
{
switch (auth) {
case OFONO_GPRS_AUTH_METHOD_ANY:
return "any";
case OFONO_GPRS_AUTH_METHOD_NONE:
return "none";
case OFONO_GPRS_AUTH_METHOD_CHAP:
return "chap";
case OFONO_GPRS_AUTH_METHOD_PAP:
@@ -276,6 +281,12 @@ static gboolean gprs_auth_method_from_string(const char *str,
} else if (g_str_equal(str, "pap")) {
*auth = OFONO_GPRS_AUTH_METHOD_PAP;
return TRUE;
} else if (g_str_equal(str, "any")) {
*auth = OFONO_GPRS_AUTH_METHOD_ANY;
return TRUE;
} else if (g_str_equal(str, "none")) {
*auth = OFONO_GPRS_AUTH_METHOD_NONE;
return TRUE;
}
return FALSE;
@@ -641,7 +652,48 @@ static gboolean pri_parse_proxy(struct pri_context *ctx, const char *proxy)
}
g_free(ctx->proxy_host);
ctx->proxy_host = g_strdup(host);
ctx->proxy_host = NULL;
if (host[0] == '0' || strstr(host, ".0")) {
/*
* Some operators provide IP address of the MMS proxy
* prepending zeros to each number shorter then 3 digits,
* e.g. "192.168.094.023" instead of "192.168.94.23".
* That may look nicer but it's actually wrong because
* the numbers starting with zeros are interpreted as
* octal numbers. In the example above 023 actually means
* 16 and 094 is not a valid number at all.
*
* In addition to publishing these broken settings on their
* web sites, some of the operators send them over the air,
* in which case we can't even blame the user for entering
* an invalid IP address. We better be prepared to deal with
* those.
*
* Since nobody in the world seems to be actually using the
* octal notation to write an IP address, let's remove the
* leading zeros if we find them in the host part of the MMS
* proxy URL.
*/
char** parts = g_strsplit(host, ".", -1);
guint count = g_strv_length(parts);
if (count == 4) {
char** ptr = parts;
while (*ptr) {
char* part = *ptr;
while (part[0] == '0' && isdigit(part[1])) {
memmove(part, part+1, strlen(part));
}
*ptr++ = part;
}
ctx->proxy_host = g_strjoinv(".", parts);
DBG("%s => %s", host, ctx->proxy_host);
}
g_strfreev(parts);
}
if (!ctx->proxy_host)
ctx->proxy_host = g_strdup(host);
g_free(scheme);
return TRUE;
@@ -892,6 +944,13 @@ static void pri_reset_context_properties(struct pri_context *ctx,
gprs_proto_to_string(ctx->context.proto));
}
if (ctx->context.auth_method != ap->auth_method) {
ctx->context.auth_method = ap->auth_method;
changed = TRUE;
pri_str_signal_change(ctx, "AuthenticationMethod",
gprs_auth_method_to_string(ctx->context.auth_method));
}
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
if (pri_str_update(ctx->message_proxy, ap->message_proxy,
sizeof(ctx->message_proxy))) {
@@ -2274,6 +2333,11 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
const char *path;
enum ofono_gprs_context_type type;
#ifdef DISABLE_ADD_REMOVE_CONTEXT
ofono_error("AddContext not allowed");
return __ofono_error_not_supported(msg);
#endif
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &typestr,
DBUS_TYPE_INVALID))
return __ofono_error_invalid_args(msg);
@@ -2355,6 +2419,11 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
const char *path;
const char *atompath;
#ifdef DISABLE_ADD_REMOVE_CONTEXT
ofono_error("RemoveContext not allowed");
return __ofono_error_not_supported(msg);
#endif
if (gprs->pending)
return __ofono_error_busy(msg);

View File

@@ -226,6 +226,9 @@ void sim_fs_notify_file_watches(struct sim_fs *fs, int id)
struct ofono_sim_context *context = l->data;
GSList *k;
if (context->file_watches == NULL)
continue;
for (k = context->file_watches->items; k; k = k->next) {
struct file_watch *w = k->data;
ofono_sim_file_changed_cb_t notify = w->item.notify;

View File

@@ -514,6 +514,20 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs,
DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
ussd_change_state(ussd, new_state);
goto free;
} else if (ussd->state == USSD_STATE_USER_ACTION &&
status != OFONO_USSD_STATUS_ACTION_REQUIRED) {
ussd_change_state(ussd, USSD_STATE_IDLE);
if (status == OFONO_USSD_STATUS_NOTIFY && str && str[0]) {
const char *path = __ofono_atom_get_path(ussd->atom);
g_dbus_emit_signal(conn, path,
OFONO_SUPPLEMENTARY_SERVICES_INTERFACE,
"NotificationReceived", DBUS_TYPE_STRING,
&str, DBUS_TYPE_INVALID);
}
goto free;
} else {
ofono_error("Received an unsolicited USSD but can't handle.");

View File

@@ -3748,6 +3748,15 @@ int ofono_voicecall_get_next_callid(struct ofono_voicecall *vc)
return __ofono_modem_callid_next(modem);
}
struct ofono_call *ofono_voicecall_find_call(struct ofono_voicecall *vc,
unsigned int id)
{
GSList *l = g_slist_find_custom(vc->call_list, GUINT_TO_POINTER(id),
call_compare_by_id);
return l ? ((struct voicecall *)l->data)->call : NULL;
}
ofono_bool_t __ofono_voicecall_is_busy(struct ofono_voicecall *vc,
enum ofono_voicecall_interaction type)
{

View File

@@ -11,7 +11,7 @@ Requires: dbus
Requires: systemd
Requires: ofono-configs
Requires: libgrilio >= 1.0.10
Requires: libglibutil >= 1.0.10
Requires: libglibutil >= 1.0.22
Requires(preun): systemd
Requires(post): systemd
Requires(postun): systemd
@@ -21,7 +21,7 @@ BuildRequires: pkgconfig(libudev) >= 145
BuildRequires: pkgconfig(mobile-broadband-provider-info)
BuildRequires: pkgconfig(libwspcodec) >= 2.0
BuildRequires: pkgconfig(libgrilio) >= 1.0.10
BuildRequires: pkgconfig(libglibutil) >= 1.0.10
BuildRequires: pkgconfig(libglibutil) >= 1.0.22
BuildRequires: pkgconfig(libdbuslogserver-dbus)
BuildRequires: pkgconfig(libmce-glib)
BuildRequires: libtool
@@ -71,6 +71,11 @@ autoreconf --force --install
--enable-test \
--enable-debuglog \
--enable-jolla-rilmodem \
--enable-sailfishos \
--enable-sailfish-provision \
--disable-add-remove-context \
--disable-isimodem \
--disable-qmimodem \
--with-systemdunitdir="/%{_lib}/systemd/system"
make %{?jobs:-j%jobs}