forked from sailfishos/ofono
Compare commits
45 Commits
mer/1.22+g
...
mer/1.23+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc696fc9fa | ||
|
|
aa4309e8cb | ||
|
|
cb6b24d950 | ||
|
|
6d1ab13c74 | ||
|
|
45424a3f96 | ||
|
|
4f7398e39d | ||
|
|
cd118ce70b | ||
|
|
99d4ce538e | ||
|
|
9b2c4bcf76 | ||
|
|
0122db04a3 | ||
|
|
021db194cb | ||
|
|
e0a0896205 | ||
|
|
49d0bbbb28 | ||
|
|
9193d06b77 | ||
|
|
b0cd3e4544 | ||
|
|
29cce6969b | ||
|
|
b87f666e4b | ||
|
|
1c1e4fa28b | ||
|
|
f597119845 | ||
|
|
633888932d | ||
|
|
a37f325d4a | ||
|
|
0afceac554 | ||
|
|
109751bcc0 | ||
|
|
30dfbf8fd7 | ||
|
|
c7aab2e790 | ||
|
|
412a2a0e7f | ||
|
|
f1aeedd113 | ||
|
|
639fce8eca | ||
|
|
9cfd0a195e | ||
|
|
cf2d8488cc | ||
|
|
ab0ac10abd | ||
|
|
b2df7de223 | ||
|
|
b56930a87f | ||
|
|
f65e8dd5af | ||
|
|
f2439243b2 | ||
|
|
93ff644856 | ||
|
|
08f8555d51 | ||
|
|
04b2a9b0f9 | ||
|
|
4d513b68d2 | ||
|
|
36f971dc78 | ||
|
|
8ba2d96cff | ||
|
|
a76f50be67 | ||
|
|
43227086c0 | ||
|
|
e40811fbc6 | ||
|
|
8c543b054a |
2
ofono/.gitignore
vendored
2
ofono/.gitignore
vendored
@@ -48,6 +48,7 @@ unit/test-dbus-access
|
||||
unit/test-dbus-queue
|
||||
unit/test-gprs-filter
|
||||
unit/test-ril_config
|
||||
unit/test-ril_ecclist
|
||||
unit/test-ril_util
|
||||
unit/test-ril_vendor
|
||||
unit/test-ril-transport
|
||||
@@ -61,6 +62,7 @@ unit/test-sailfish_cell_info_dbus
|
||||
unit/test-sailfish_manager
|
||||
unit/test-sailfish_sim_info
|
||||
unit/test-sailfish_sim_info_dbus
|
||||
unit/test-config
|
||||
unit/test-watch
|
||||
unit/test-sms-filter
|
||||
unit/test-voicecall-filter
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
ver 1.23:
|
||||
Fix issue with handling SIM AID sessions.
|
||||
Add support for QMI LTE bearer handling.
|
||||
Add support for memory location dialing.
|
||||
|
||||
ver 1.22:
|
||||
Fix issue with GPIO handling and Nokia modems.
|
||||
Fix issue with SIM state callback and AT modems.
|
||||
|
||||
@@ -32,11 +32,6 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
|
||||
nodist_pkginclude_HEADERS = include/version.h
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
|
||||
include/sailfish_manager.h
|
||||
endif
|
||||
|
||||
local_headers = $(foreach file,$(pkginclude_HEADERS) \
|
||||
$(nodist_pkginclude_HEADERS), \
|
||||
include/ofono/$(notdir $(file)))
|
||||
@@ -310,6 +305,7 @@ builtin_sources += $(qmi_sources) \
|
||||
drivers/qmimodem/ussd.c \
|
||||
drivers/qmimodem/gprs.c \
|
||||
drivers/qmimodem/gprs-context.c \
|
||||
drivers/qmimodem/lte.c \
|
||||
drivers/qmimodem/radio-settings.c \
|
||||
drivers/qmimodem/location-reporting.c \
|
||||
drivers/qmimodem/netmon.c
|
||||
@@ -777,7 +773,7 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
||||
src/handsfree-audio.c src/bluetooth.h \
|
||||
src/sim-mnclength.c src/voicecallagent.c \
|
||||
src/sms-filter.c src/gprs-filter.c \
|
||||
src/dbus-queue.c src/dbus-access.c \
|
||||
src/dbus-queue.c src/dbus-access.c src/config.c \
|
||||
src/voicecall-filter.c src/ril-transport.c \
|
||||
src/hfp.h src/siri.c src/watchlist.c \
|
||||
src/netmon.c src/lte.c src/ims.c \
|
||||
@@ -808,7 +804,8 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ $(builtin_cflags) \
|
||||
|
||||
AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/src \
|
||||
-I$(srcdir)/gdbus -I$(srcdir)/gisi -I$(srcdir)/gatchat \
|
||||
-I$(srcdir)/btio -I$(srcdir)/gril
|
||||
-I$(srcdir)/btio -I$(srcdir)/gril \
|
||||
-I$(srcdir)/plugins/sailfish_manager
|
||||
|
||||
doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/manager-api.txt doc/modem-api.txt doc/network-api.txt \
|
||||
@@ -972,8 +969,7 @@ if SAILFISH_MANAGER
|
||||
|
||||
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-Iplugins/sailfish_manager
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
|
||||
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info
|
||||
@@ -986,7 +982,7 @@ unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
|
||||
gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
@DBUS_GLIB_CFLAGS@ -Iplugins/sailfish_manager
|
||||
@DBUS_GLIB_CFLAGS@
|
||||
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info_dbus
|
||||
@@ -996,7 +992,7 @@ unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info
|
||||
@@ -1008,8 +1004,7 @@ unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
|
||||
gdbus/object.c \
|
||||
src/dbus.c src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"' \
|
||||
-Iplugins/sailfish_manager
|
||||
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info_dbus
|
||||
@@ -1021,7 +1016,7 @@ unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/log.c
|
||||
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_manager
|
||||
@@ -1029,13 +1024,20 @@ unit_tests += unit/test-sailfish_manager
|
||||
unit_test_watch_SOURCES = unit/test-watch.c src/watch.c \
|
||||
src/log.c src/watchlist.c
|
||||
unit_test_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_watch_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_watch_OBJECTS)
|
||||
unit_tests += unit/test-watch
|
||||
|
||||
endif
|
||||
|
||||
unit_test_config_SOURCES = unit/test-config.c drivers/ril/ril_util.c \
|
||||
src/config.c src/log.c
|
||||
unit_test_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_config_OBJECTS)
|
||||
unit_tests += unit/test-config
|
||||
|
||||
if SAILFISH_ACCESS
|
||||
unit_test_sailfish_access_SOURCES = unit/test-sailfish_access.c \
|
||||
plugins/sailfish_access.c src/dbus-access.c src/log.c
|
||||
@@ -1062,6 +1064,13 @@ unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_config_OBJECTS)
|
||||
unit_tests += unit/test-ril_config
|
||||
|
||||
unit_test_ril_ecclist_SOURCES = unit/test-ril_ecclist.c \
|
||||
drivers/ril/ril_ecclist.c src/log.c
|
||||
unit_test_ril_ecclist_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_ecclist_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_ecclist_OBJECTS)
|
||||
unit_tests += unit/test-ril_ecclist
|
||||
|
||||
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
|
||||
src/log.c
|
||||
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.22)
|
||||
AC_INIT(ofono, 1.23)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
||||
@@ -95,6 +95,13 @@ Properties boolean Powered [readwrite]
|
||||
String representing the software version number of the
|
||||
modem device.
|
||||
|
||||
string SystemPath [readonly, optional]
|
||||
|
||||
String representing the system path for the modem
|
||||
device.
|
||||
For modems detected by udev events, this corresponds to
|
||||
the modem sysfs path.
|
||||
|
||||
array{string} Features [readonly]
|
||||
|
||||
List of currently enabled features. It uses simple
|
||||
|
||||
@@ -69,6 +69,17 @@ Methods dict GetProperties()
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
object DialMemory(string memory position, string hide_callerid)
|
||||
|
||||
Initiates a new outgoing call to the number in the given memory
|
||||
position/favourite. For callerid see the Dial method.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.InvalidFormat
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
void Transfer()
|
||||
|
||||
Joins the currently Active (or Outgoing, depending
|
||||
|
||||
@@ -422,6 +422,28 @@ static void hfp_dial_last(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
|
||||
}
|
||||
|
||||
static void hfp_dial_memory(struct ofono_voicecall *vc,
|
||||
unsigned int memory_location,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[256];
|
||||
|
||||
cbd->user = vc;
|
||||
DBG("Calling memory location %d\n", memory_location);
|
||||
snprintf(buf, sizeof(buf), "ATD>%d;", memory_location);
|
||||
|
||||
if (g_at_chat_send(vd->chat, buf, none_prefix,
|
||||
atd_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
DBG("at_chat_failed");
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void hfp_template(const char *cmd, struct ofono_voicecall *vc,
|
||||
GAtResultFunc result_cb, unsigned int affected_types,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
@@ -1287,6 +1309,7 @@ static struct ofono_voicecall_driver driver = {
|
||||
.remove = hfp_voicecall_remove,
|
||||
.dial = hfp_dial,
|
||||
.dial_last = hfp_dial_last,
|
||||
.dial_memory = hfp_dial_memory,
|
||||
.answer = hfp_answer,
|
||||
.hangup_active = hfp_hangup,
|
||||
.hold_all_active = hfp_hold_all_active,
|
||||
|
||||
@@ -29,12 +29,16 @@
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "src/common.h"
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct gprs_data {
|
||||
struct qmi_device *dev;
|
||||
struct qmi_service *nas;
|
||||
struct qmi_service *wds;
|
||||
unsigned int last_auto_context_id;
|
||||
};
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
|
||||
@@ -64,8 +68,124 @@ static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void get_lte_attach_param_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
char *apn = NULL;
|
||||
uint16_t error;
|
||||
uint8_t iptype;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Failed to query LTE attach params: %hd", error);
|
||||
goto noapn;
|
||||
}
|
||||
|
||||
/* APN */
|
||||
apn = qmi_result_get_string(result, 0x10);
|
||||
if (!apn) {
|
||||
DBG("Default profile has no APN setting");
|
||||
goto noapn;
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint8(result, 0x11, &iptype))
|
||||
ofono_info("LTE attach IP type: %hhd", iptype);
|
||||
|
||||
ofono_gprs_cid_activated(gprs, data->last_auto_context_id, apn);
|
||||
g_free(apn);
|
||||
|
||||
return;
|
||||
|
||||
noapn:
|
||||
data->last_auto_context_id = 0;
|
||||
ofono_error("LTE bearer established but APN not set");
|
||||
}
|
||||
|
||||
static void get_default_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs* gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
uint16_t error;
|
||||
uint8_t index;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Get default profile error: %hd", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Profile index */
|
||||
if (!qmi_result_get_uint8(result, 0x01, &index)) {
|
||||
ofono_error("Failed query default profile");
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBG("Default profile index: %hhd", index);
|
||||
|
||||
data->last_auto_context_id = index;
|
||||
|
||||
/* Get LTE Attach Parameters */
|
||||
if (qmi_service_send(data->wds, 0x85, NULL,
|
||||
get_lte_attach_param_cb, gprs, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
data->last_auto_context_id = 0;
|
||||
ofono_error("LTE bearer established but APN not set");
|
||||
}
|
||||
|
||||
/*
|
||||
* Query the settings in effect on the default bearer. These may be
|
||||
* implicit or may even be something other than requested as the gateway
|
||||
* is allowed to override whatever was requested by the user.
|
||||
*/
|
||||
static void get_lte_attach_params(struct ofono_gprs* gprs)
|
||||
{
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t family;
|
||||
} __attribute((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
.family = 0, /* embedded */
|
||||
};
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (data->last_auto_context_id != 0)
|
||||
return; /* Established or in progress */
|
||||
|
||||
/* Set query in progress */
|
||||
data->last_auto_context_id = -1;
|
||||
|
||||
/* First we query the default profile in order to find out which
|
||||
* context the modem has activated.
|
||||
*/
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile type */
|
||||
qmi_param_append(param, 0x1, sizeof(p), &p);
|
||||
|
||||
/* Get default profile */
|
||||
if (qmi_service_send(data->wds, 0x49, param,
|
||||
get_default_profile_cb, gprs, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_warn("Unable to query LTE APN... will not activate context");
|
||||
}
|
||||
|
||||
static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
|
||||
{
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
int status;
|
||||
int tech;
|
||||
|
||||
@@ -74,17 +194,20 @@ static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
|
||||
if (!extract_ss_info(result, &status, &tech))
|
||||
return -1;
|
||||
|
||||
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED)
|
||||
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED) {
|
||||
if (tech == ACCESS_TECHNOLOGY_EUTRAN) {
|
||||
/* On LTE we are effectively always attached; and
|
||||
* the default bearer is established as soon as the
|
||||
* network is joined.
|
||||
* network is joined. We just need to query the
|
||||
* parameters in effect on the default bearer and
|
||||
* let the ofono core know about the activated
|
||||
* context.
|
||||
*/
|
||||
/* FIXME: query default profile number and APN
|
||||
* instead of assuming profile 1 and ""
|
||||
*/
|
||||
ofono_gprs_cid_activated(gprs, 1 , "automatic");
|
||||
get_lte_attach_params(gprs);
|
||||
}
|
||||
} else {
|
||||
data->last_auto_context_id = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -198,7 +321,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
@@ -206,12 +329,12 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request NAS service");
|
||||
ofono_error("Failed to request WDS service");
|
||||
ofono_gprs_remove(gprs);
|
||||
return;
|
||||
}
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
data->wds = qmi_service_ref(service);
|
||||
|
||||
/*
|
||||
* First get the SS info - the modem may already be connected,
|
||||
@@ -228,6 +351,25 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
ofono_gprs_register(gprs);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request NAS service");
|
||||
ofono_gprs_remove(gprs);
|
||||
return;
|
||||
}
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS,
|
||||
create_wds_cb, gprs, NULL);
|
||||
}
|
||||
|
||||
static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
@@ -240,6 +382,8 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
|
||||
ofono_gprs_set_data(gprs, data);
|
||||
|
||||
data->dev = device;
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, gprs, NULL);
|
||||
|
||||
@@ -254,6 +398,9 @@ static void qmi_gprs_remove(struct ofono_gprs *gprs)
|
||||
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->wds);
|
||||
qmi_service_unref(data->wds);
|
||||
|
||||
qmi_service_unregister_all(data->nas);
|
||||
|
||||
qmi_service_unref(data->nas);
|
||||
|
||||
264
ofono/drivers/qmimodem/lte.c
Normal file
264
ofono/drivers/qmimodem/lte.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 Jonas Bonn. All rights reserved.
|
||||
* Copyright (C) 2018 Norrbonn AB. All rights reserved.
|
||||
* Copyright (C) 2018 Data Respons ASA. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/lte.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct lte_data {
|
||||
struct qmi_service *wds;
|
||||
uint8_t default_profile;
|
||||
};
|
||||
|
||||
static void modify_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_lte_cb_t cb = cbd->cb;
|
||||
uint16_t error;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
DBG("Failed to modify profile: %d", error);
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmimodem_lte_set_default_attach_info(const struct ofono_lte *lte,
|
||||
const struct ofono_lte_default_attach_info *info,
|
||||
ofono_lte_cb_t cb, void *data)
|
||||
{
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct qmi_param* param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
} __attribute__((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
p.index = ldd->default_profile;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile selector */
|
||||
qmi_param_append(param, 0x01, sizeof(p), &p);
|
||||
|
||||
/* WDS APN Name */
|
||||
qmi_param_append(param, QMI_WDS_PARAM_APN,
|
||||
strlen(info->apn), info->apn);
|
||||
|
||||
/* Modify profile */
|
||||
if (qmi_service_send(ldd->wds, 0x28, param,
|
||||
modify_profile_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void reset_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
uint16_t error;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error))
|
||||
ofono_error("Reset profile error: %hd", error);
|
||||
|
||||
ofono_lte_register(lte);
|
||||
}
|
||||
|
||||
static void get_default_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
uint16_t error;
|
||||
uint8_t index;
|
||||
struct qmi_param *param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
} __attribute__((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Get default profile error: %hd", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Profile index */
|
||||
if (!qmi_result_get_uint8(result, 0x01, &index)) {
|
||||
ofono_error("Failed query default profile");
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBG("Default profile index: %hhd", index);
|
||||
|
||||
ldd->default_profile = index;
|
||||
|
||||
p.index = index;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile selector */
|
||||
qmi_param_append(param, 0x01, sizeof(p), &p);
|
||||
|
||||
/* Reset profile */
|
||||
if (qmi_service_send(ldd->wds, 0x4b, param,
|
||||
reset_profile_cb, lte, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_error("Failed to reset profile %hhd", index);
|
||||
ofono_lte_remove(lte);
|
||||
}
|
||||
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
struct qmi_param *param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t family;
|
||||
} __attribute((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
.family = 0, /* embedded */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request WDS service");
|
||||
ofono_lte_remove(lte);
|
||||
return;
|
||||
}
|
||||
|
||||
ldd->wds = qmi_service_ref(service);
|
||||
|
||||
/* Query the default profile */
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile type */
|
||||
qmi_param_append(param, 0x1, sizeof(p), &p);
|
||||
|
||||
/* Get default profile */
|
||||
if (qmi_service_send(ldd->wds, 0x49, param,
|
||||
get_default_profile_cb, lte, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_error("Failed to query default profile");
|
||||
ofono_lte_register(lte);
|
||||
}
|
||||
|
||||
static int qmimodem_lte_probe(struct ofono_lte *lte, void *data)
|
||||
{
|
||||
struct qmi_device *device = data;
|
||||
struct lte_data *ldd;
|
||||
|
||||
DBG("qmimodem lte probe");
|
||||
|
||||
ldd = g_try_new0(struct lte_data, 1);
|
||||
if (!ldd)
|
||||
return -ENOMEM;
|
||||
|
||||
ofono_lte_set_data(lte, ldd);
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_WDS,
|
||||
create_wds_cb, lte, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmimodem_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
qmi_service_unregister_all(ldd->wds);
|
||||
|
||||
qmi_service_unref(ldd->wds);
|
||||
|
||||
g_free(ldd);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmimodem_lte_probe,
|
||||
.remove = qmimodem_lte_remove,
|
||||
.set_default_attach_info = qmimodem_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void qmi_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void qmi_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
@@ -39,6 +39,7 @@ static int qmimodem_init(void)
|
||||
qmi_ussd_init();
|
||||
qmi_gprs_init();
|
||||
qmi_gprs_context_init();
|
||||
qmi_lte_init();
|
||||
qmi_radio_settings_init();
|
||||
qmi_location_reporting_init();
|
||||
qmi_netmon_init();
|
||||
@@ -51,6 +52,7 @@ static void qmimodem_exit(void)
|
||||
qmi_netmon_exit();
|
||||
qmi_location_reporting_exit();
|
||||
qmi_radio_settings_exit();
|
||||
qmi_lte_exit();
|
||||
qmi_gprs_context_exit();
|
||||
qmi_gprs_exit();
|
||||
qmi_ussd_exit();
|
||||
|
||||
@@ -48,6 +48,9 @@ extern void qmi_gprs_exit(void);
|
||||
extern void qmi_gprs_context_init(void);
|
||||
extern void qmi_gprs_context_exit(void);
|
||||
|
||||
extern void qmi_lte_init(void);
|
||||
extern void qmi_lte_exit(void);
|
||||
|
||||
extern void qmi_radio_settings_init(void);
|
||||
extern void qmi_radio_settings_exit(void);
|
||||
|
||||
|
||||
@@ -277,6 +277,9 @@ static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->dms);
|
||||
qmi_service_unref(data->dms);
|
||||
|
||||
qmi_service_unregister_all(data->nas);
|
||||
|
||||
qmi_service_unref(data->nas);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -237,337 +238,6 @@ char *ril_config_ints_to_string(GUtilInts *ints, char separator)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ril_config_merge_files() function does the following:
|
||||
*
|
||||
* 1. Loads the specified key file (say, "/etc/foo.conf")
|
||||
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
|
||||
* for the files with the same suffix as the main file (e.g. "*.conf")
|
||||
* 3. Sorts the files from the subdirectory (alphabetically)
|
||||
* 4. Merges the contents of the additional files with the main file
|
||||
* according to their sort order.
|
||||
*
|
||||
* When the entries are merged, keys and groups overwrite the exising
|
||||
* ones by default. Keys can be suffixed with special characters to
|
||||
* remove or modify the existing entries instead:
|
||||
*
|
||||
* ':' Sets the (default) value if the key is missing
|
||||
* '+' Appends values to the string list
|
||||
* '?' Appends only new (non-existent) values to the string list
|
||||
* '-' Removes the values from the string list
|
||||
*
|
||||
* Both keys and groups can be prefixed with '!' to remove the entire key
|
||||
* or group.
|
||||
*
|
||||
* For example if we merge these two files:
|
||||
*
|
||||
* /etc/foo.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=4
|
||||
* d=5
|
||||
* [bar]
|
||||
* e=5
|
||||
*
|
||||
* /etc/foo.d/bar.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a+=2
|
||||
* b-=2
|
||||
* c=5
|
||||
* !d
|
||||
* [!bar]
|
||||
*
|
||||
* we end up with this:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=5
|
||||
*
|
||||
* Not that the list separator is assumed to be ',' (rather than default ';').
|
||||
* The keyfile passed to ril_config_merge_files() should use the same list
|
||||
* separator, because the default values are copied from the config files
|
||||
* as is.
|
||||
*/
|
||||
|
||||
static gint ril_config_sort_files(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
/* The comparison function for g_ptr_array_sort() doesn't take
|
||||
* the pointers from the array as arguments, it takes pointers
|
||||
* to the pointers in the array. */
|
||||
return strcmp(*(char**)a, *(char**)b);
|
||||
}
|
||||
|
||||
static char **ril_config_collect_files(const char *path, const char *suffix)
|
||||
{
|
||||
/* Returns sorted list of regular files in the directory,
|
||||
* optionally having the specified suffix (e.g. ".conf").
|
||||
* Returns NULL if nothing appropriate has been found. */
|
||||
char **files = NULL;
|
||||
DIR *d = opendir(path);
|
||||
|
||||
if (d) {
|
||||
GPtrArray *list = g_ptr_array_new();
|
||||
const struct dirent *p;
|
||||
|
||||
while ((p = readdir(d)) != NULL) {
|
||||
/* No need to even stat . and .. */
|
||||
if (strcmp(p->d_name, ".") &&
|
||||
strcmp(p->d_name, "..") && (!suffix ||
|
||||
g_str_has_suffix(p->d_name, suffix))) {
|
||||
struct stat st;
|
||||
char *buf = g_strconcat(path, "/", p->d_name,
|
||||
NULL);
|
||||
|
||||
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
|
||||
g_ptr_array_add(list, buf);
|
||||
} else {
|
||||
g_free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (list->len > 0) {
|
||||
g_ptr_array_sort(list, ril_config_sort_files);
|
||||
g_ptr_array_add(list, NULL);
|
||||
files = (char**)g_ptr_array_free(list, FALSE);
|
||||
} else {
|
||||
g_ptr_array_free(list, TRUE);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
static int ril_config_list_find(char **list, gsize len, const char *value)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!strcmp(list[i], value)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ril_config_list_append(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key,
|
||||
char **values, gsize n, gboolean unique)
|
||||
{
|
||||
/* Note: will steal strings from values */
|
||||
if (n > 0) {
|
||||
int i;
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
|
||||
|
||||
for (i = 0; i < (int)len; i++) {
|
||||
g_ptr_array_add(newlist, list[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)n; i++) {
|
||||
char *val = values[i];
|
||||
|
||||
if (!unique || ril_config_list_find((char**)
|
||||
newlist->pdata, newlist->len, val) < 0) {
|
||||
/* Move the string to the new list */
|
||||
g_ptr_array_add(newlist, val);
|
||||
memmove(values + i, values + i + 1,
|
||||
sizeof(char*) * (n - i));
|
||||
i--;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
if (newlist->len > len) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) newlist->pdata,
|
||||
newlist->len);
|
||||
}
|
||||
|
||||
/* Strings are deallocated by GPtrArray */
|
||||
g_ptr_array_free(newlist, TRUE);
|
||||
g_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_config_list_remove(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key, char **values, gsize n)
|
||||
{
|
||||
if (n > 0) {
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
|
||||
if (len > 0) {
|
||||
gsize i;
|
||||
const gsize oldlen = len;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
int pos;
|
||||
|
||||
/* Remove all matching values */
|
||||
while ((pos = ril_config_list_find(list, len,
|
||||
values[i])) >= 0) {
|
||||
g_free(list[pos]);
|
||||
memmove(list + pos, list + pos + 1,
|
||||
sizeof(char*) * (len - pos));
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (len < oldlen) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) list, len);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_config_merge_group(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **keys = g_key_file_get_keys(k, group, &n, NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
char *key = keys[i];
|
||||
|
||||
if (key[0] == '!') {
|
||||
if (key[1]) {
|
||||
g_key_file_remove_key(conf, group, key+1, NULL);
|
||||
}
|
||||
} else {
|
||||
const gsize len = strlen(key);
|
||||
const char last = (len > 0) ? key[len-1] : 0;
|
||||
|
||||
if (last == '+' || last == '?') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
ril_config_list_append(conf, k, group, key,
|
||||
values, count, last == '?');
|
||||
g_strfreev(values);
|
||||
} else if (last == '-') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
ril_config_list_remove(conf, k, group, key,
|
||||
values, count);
|
||||
g_strfreev(values);
|
||||
} else {
|
||||
/* Overwrite the value (it must exist in k) */
|
||||
gchar *value = g_key_file_get_value(k, group,
|
||||
key, NULL);
|
||||
|
||||
if (last == ':') {
|
||||
/* Default value */
|
||||
key[len-1] = 0;
|
||||
if (!g_key_file_has_key(conf,
|
||||
group, key, NULL)) {
|
||||
g_key_file_set_value(conf,
|
||||
group, key, value);
|
||||
}
|
||||
} else {
|
||||
g_key_file_set_value(conf, group, key,
|
||||
value);
|
||||
}
|
||||
g_free(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(keys);
|
||||
}
|
||||
|
||||
static void ril_config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **groups = g_key_file_get_groups(k, &n);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
const char *group = groups[i];
|
||||
|
||||
if (group[0] == '!') {
|
||||
g_key_file_remove_group(conf, group + 1, NULL);
|
||||
} else {
|
||||
ril_config_merge_group(conf, k, group);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(groups);
|
||||
}
|
||||
|
||||
static void ril_config_merge_file(GKeyFile *conf, const char *file)
|
||||
{
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_key_file_set_list_separator(k, ',');
|
||||
|
||||
if (g_key_file_load_from_file(k, file, 0, NULL)) {
|
||||
ril_config_merge_keyfile(conf, k);
|
||||
}
|
||||
|
||||
g_key_file_unref(k);
|
||||
}
|
||||
|
||||
void ril_config_merge_files(GKeyFile *conf, const char *file)
|
||||
{
|
||||
if (conf && file && file[0]) {
|
||||
char *dot = strrchr(file, '.');
|
||||
const char *suffix;
|
||||
char *dir;
|
||||
char **files;
|
||||
|
||||
if (!dot) {
|
||||
dir = g_strconcat(file, ".d", NULL);
|
||||
suffix = NULL;
|
||||
} else if (!dot[1]) {
|
||||
dir = g_strconcat(file, "d", NULL);
|
||||
suffix = NULL;
|
||||
} else {
|
||||
/* 2 bytes for ".d" and 1 for NULL terminator */
|
||||
dir = g_malloc(dot - file + 3);
|
||||
strncpy(dir, file, dot - file);
|
||||
strcpy(dir + (dot - file), ".d");
|
||||
suffix = dot + 1;
|
||||
}
|
||||
|
||||
files = ril_config_collect_files(dir, suffix);
|
||||
g_free(dir);
|
||||
|
||||
/* Load the main config */
|
||||
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
|
||||
DBG("Loading %s", file);
|
||||
ril_config_merge_file(conf, file);
|
||||
}
|
||||
|
||||
if (files) {
|
||||
char **ptr;
|
||||
|
||||
for (ptr = files; *ptr; ptr++) {
|
||||
DBG("Merging %s", *ptr);
|
||||
ril_config_merge_file(conf, *ptr);
|
||||
}
|
||||
|
||||
g_strfreev(files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -22,8 +23,6 @@
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||
|
||||
void ril_config_merge_files(GKeyFile *conf, const char *file);
|
||||
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2019 Jolla Ltd.
|
||||
* Copyright (C) 2013-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -205,10 +205,44 @@ enum ril_data_call_fail_cause {
|
||||
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
|
||||
PDP_FAIL_NSAPI_IN_USE = 0x23,
|
||||
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
|
||||
PDP_FAIL_QOS_NOT_ACCEPTED = 0x25,
|
||||
PDP_FAIL_NETWORK_FAILURE = 0x26,
|
||||
PDP_FAIL_UMTS_REACTIVATION_REQ = 0x27,
|
||||
PDP_FAIL_FEATURE_NOT_SUPP = 0x28,
|
||||
PDP_FAIL_TFT_SEMANTIC_ERROR = 0x29,
|
||||
PDP_FAIL_TFT_SYTAX_ERROR = 0x2A,
|
||||
PDP_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
|
||||
PDP_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
|
||||
PDP_FAIL_FILTER_SYTAX_ERROR = 0x2D,
|
||||
PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
|
||||
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
|
||||
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
|
||||
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
|
||||
PDP_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
|
||||
PDP_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
|
||||
PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
|
||||
PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
|
||||
PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
|
||||
PDP_FAIL_INVALID_TRANSACTION_ID = 0x51,
|
||||
PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
|
||||
PDP_FAIL_INVALID_MANDATORY_INFO = 0x60,
|
||||
PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
|
||||
PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
|
||||
PDP_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
|
||||
PDP_FAIL_CONDITIONAL_IE_ERROR = 0x64,
|
||||
PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
|
||||
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
|
||||
PDP_FAIL_APN_TYPE_CONFLICT = 0x70,
|
||||
PDP_FAIL_INVALID_PCSCF_ADDR = 0x71,
|
||||
PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
|
||||
PDP_FAIL_EMM_ACCESS_BARRED = 0x73,
|
||||
PDP_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
|
||||
PDP_FAIL_IFACE_MISMATCH = 0x75,
|
||||
PDP_FAIL_COMPANION_IFACE_IN_USE = 0x76,
|
||||
PDP_FAIL_IP_ADDRESS_MISMATCH = 0x77,
|
||||
PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
|
||||
PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
|
||||
PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
|
||||
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
|
||||
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
|
||||
PDP_FAIL_SIGNAL_LOST = -3,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -14,6 +14,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_data.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_network.h"
|
||||
@@ -29,6 +31,8 @@
|
||||
#include <grilio_parser.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include "common.h" /* ACCESS_TECHNOLOGY_EUTRAN */
|
||||
|
||||
/* Yes, it does sometimes take minutes in roaming */
|
||||
#define SETUP_DATA_CALL_TIMEOUT (300*1000) /* ms */
|
||||
|
||||
@@ -115,6 +119,7 @@ struct ril_data_priv {
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
gulong settings_event_id[SETTINGS_EVENT_COUNT];
|
||||
GHashTable* grab;
|
||||
gboolean downgraded_tech; /* Status 55 workaround */
|
||||
};
|
||||
|
||||
enum ril_data_signal {
|
||||
@@ -185,7 +190,6 @@ struct ril_data_request_allow_data {
|
||||
gboolean allow;
|
||||
};
|
||||
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
|
||||
static void ril_data_call_deact_cid(struct ril_data *data, int cid);
|
||||
static void ril_data_power_update(struct ril_data *self);
|
||||
@@ -435,7 +439,7 @@ static gboolean ril_data_call_list_equal(const struct ril_data_call_list *l1,
|
||||
if (!l1 && !l2) {
|
||||
return TRUE;
|
||||
} else if (l1 && l2) {
|
||||
if (l1->version == l1->version && l1->num == l2->num) {
|
||||
if (l1->version == l2->version && l1->num == l2->num) {
|
||||
GSList *p1 = l1->calls;
|
||||
GSList *p2 = l2->calls;
|
||||
|
||||
@@ -816,6 +820,31 @@ static gboolean ril_data_call_setup_retry(void *user_data)
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean ril_data_call_retry(struct ril_data_request_setup *setup)
|
||||
{
|
||||
struct ril_data_request *req = &setup->req;
|
||||
const struct ril_data_options *options = &req->data->priv->options;
|
||||
|
||||
if (setup->retry_count < options->data_call_retry_limit) {
|
||||
req->pending_id = 0;
|
||||
GASSERT(!setup->retry_delay_id);
|
||||
if (!setup->retry_count) {
|
||||
/* No delay first time */
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
options->data_call_retry_limit);
|
||||
req->submit(req);
|
||||
} else {
|
||||
const guint ms = options->data_call_retry_delay_ms;
|
||||
DBG("silent retry scheduled in %u ms", ms);
|
||||
setup->retry_delay_id = g_timeout_add(ms,
|
||||
ril_data_call_setup_retry, setup);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
@@ -840,33 +869,49 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
}
|
||||
}
|
||||
|
||||
if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED &&
|
||||
setup->retry_count < priv->options.data_call_retry_limit) {
|
||||
if (call) {
|
||||
switch (call->status) {
|
||||
/*
|
||||
* According to the comment from ril.h we should silently
|
||||
* retry. First time we retry immediately and if that doedsn't
|
||||
* retry. First time we retry immediately and if that doesn't
|
||||
* work, then after certain delay.
|
||||
*/
|
||||
req->pending_id = 0;
|
||||
GASSERT(!setup->retry_delay_id);
|
||||
if (!setup->retry_count) {
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
priv->options.data_call_retry_limit);
|
||||
req->submit(req);
|
||||
} else {
|
||||
guint ms = priv->options.data_call_retry_delay_ms;
|
||||
DBG("silent retry scheduled in %u ms", ms);
|
||||
setup->retry_delay_id = g_timeout_add(ms,
|
||||
ril_data_call_setup_retry, setup);
|
||||
case PDP_FAIL_ERROR_UNSPECIFIED:
|
||||
if (ril_data_call_retry(setup)) {
|
||||
ril_data_call_list_free(list);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* With some networks we sometimes start getting error 55
|
||||
* (Multiple PDN connections for a given APN not allowed)
|
||||
* when trying to setup an LTE data call and this error
|
||||
* doesn't go away until we successfully establish a data
|
||||
* call over 3G. Then we can switch back to LTE.
|
||||
*/
|
||||
case PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED:
|
||||
if (priv->network->data.access_tech ==
|
||||
ACCESS_TECHNOLOGY_EUTRAN &&
|
||||
!priv->downgraded_tech) {
|
||||
DBG("downgrading preferred technology");
|
||||
priv->downgraded_tech = TRUE;
|
||||
ril_data_manager_check_network_mode(priv->dm);
|
||||
/* And let this call fail */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ril_data_call_list_free(list);
|
||||
return;
|
||||
}
|
||||
|
||||
ril_data_request_completed(req);
|
||||
|
||||
if (call && call->status == PDP_FAIL_NONE) {
|
||||
if (priv->downgraded_tech) {
|
||||
DBG("done with status 55 workaround");
|
||||
priv->downgraded_tech = FALSE;
|
||||
ril_data_manager_check_network_mode(priv->dm);
|
||||
}
|
||||
if (ril_data_call_list_move_calls(self->data_calls, list) > 0) {
|
||||
DBG("data call(s) added");
|
||||
ril_data_signal_emit(self, SIGNAL_CALLS_CHANGED);
|
||||
@@ -1152,6 +1197,11 @@ static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
|
||||
/*==========================================================================*
|
||||
* ril_data
|
||||
*==========================================================================*/
|
||||
static enum ofono_radio_access_mode ril_data_max_mode(struct ril_data *self)
|
||||
{
|
||||
return self->priv->downgraded_tech ? OFONO_RADIO_ACCESS_MODE_UMTS :
|
||||
OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
}
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *self,
|
||||
ril_data_cb_t cb, void *arg)
|
||||
@@ -1685,7 +1735,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
|
||||
ril_network_set_max_pref_mode(network,
|
||||
(network == lte_network) ?
|
||||
OFONO_RADIO_ACCESS_MODE_ANY :
|
||||
ril_data_max_mode(data) :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM,
|
||||
FALSE);
|
||||
}
|
||||
@@ -1695,7 +1745,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
ril_network_set_max_pref_mode(data->priv->network,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
|
||||
ril_data_max_mode(data), FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1724,7 +1774,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
|
||||
if (ril_data_manager_handover(self)) {
|
||||
ril_network_set_max_pref_mode(priv->network,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
|
||||
ril_data_max_mode(data), TRUE);
|
||||
}
|
||||
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
|
||||
@@ -1737,7 +1787,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *self)
|
||||
void ril_data_manager_check_data(struct ril_data_manager *self)
|
||||
{
|
||||
/*
|
||||
* Don't do anything if there any requests pending.
|
||||
|
||||
@@ -89,6 +89,7 @@ struct ril_data_manager;
|
||||
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
|
||||
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_unref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
|
||||
|
||||
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +14,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -47,6 +50,53 @@ G_DEFINE_TYPE(RilEccList, ril_ecclist, G_TYPE_OBJECT)
|
||||
#define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_ECCLIST_TYPE, RilEccList))
|
||||
|
||||
static char **ril_ecclist_parse(const char *content)
|
||||
{
|
||||
char **ptr;
|
||||
char **list = NULL;
|
||||
guint i;
|
||||
|
||||
/*
|
||||
* Some MediaTek devices use ECC,CAT;ECC,CAT kind of syntax
|
||||
*/
|
||||
if (strchr(content, ';')) {
|
||||
list = g_strsplit(content, ";", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
char* comma;
|
||||
|
||||
*ptr = g_strstrip(*ptr);
|
||||
|
||||
/* Strip service category */
|
||||
comma = strchr(*ptr, ',');
|
||||
if (comma) {
|
||||
*comma = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* The right ECC,ECC syntax is handled here */
|
||||
list = g_strsplit(content, ",", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
*ptr = g_strstrip(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort the list */
|
||||
gutil_strv_sort(list, TRUE);
|
||||
|
||||
/* Remove empty strings (those are at the beginning after sorting) */
|
||||
while (list[0] && !list[0][0]) {
|
||||
list = gutil_strv_remove_at(list, 0, TRUE);
|
||||
}
|
||||
|
||||
/* Remove duplicates */
|
||||
for (i = 0; list[i] && list[i+1]; i++) {
|
||||
while (list[i+1] && !strcmp(list[i], list[i+1])) {
|
||||
list = gutil_strv_remove_at(list, i+1, TRUE);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||
{
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
@@ -58,16 +108,9 @@ static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||
GError *error = NULL;
|
||||
|
||||
if (g_file_get_contents(priv->path, &content, &len, &error)) {
|
||||
char **ptr;
|
||||
|
||||
DBG("%s = %s", priv->name, content);
|
||||
list = g_strsplit(content, ",", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
*ptr = g_strstrip(*ptr);
|
||||
}
|
||||
|
||||
gutil_strv_sort(list, TRUE);
|
||||
} else if (error) {
|
||||
list = ril_ecclist_parse(content);
|
||||
} else {
|
||||
DBG("%s: %s", priv->path, GERRMSG(error));
|
||||
g_error_free(error);
|
||||
}
|
||||
@@ -89,7 +132,8 @@ static void ril_ecclist_update(struct ril_ecclist *self)
|
||||
DBG("%s changed", priv->name);
|
||||
g_strfreev(self->list);
|
||||
self->list = list;
|
||||
g_signal_emit(self, ril_ecclist_signals[SIGNAL_LIST_CHANGED], 0);
|
||||
g_signal_emit(self, ril_ecclist_signals
|
||||
[SIGNAL_LIST_CHANGED], 0);
|
||||
} else {
|
||||
g_strfreev(list);
|
||||
}
|
||||
@@ -121,10 +165,9 @@ static void ril_ecclist_dir_changed(GUtilInotifyWatch *watch, guint mask,
|
||||
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
|
||||
IN_MODIFY | IN_CLOSE_WRITE,
|
||||
ril_ecclist_changed, self);
|
||||
if (priv->file_watch) {
|
||||
DBG("watching %s", priv->path);
|
||||
ril_ecclist_update(self);
|
||||
}
|
||||
DBG("%swatching %s", priv->file_watch ? "" : "not ",
|
||||
priv->path);
|
||||
ril_ecclist_update(self);
|
||||
}
|
||||
|
||||
if (mask & IN_IGNORED) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
@@ -435,6 +436,7 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
g_source_remove(md->set_offline.timeout_id);
|
||||
}
|
||||
|
||||
ril_vendor_unref(modem->vendor);
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_data_unref(modem->data);
|
||||
@@ -456,7 +458,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct ril_sim_settings *settings, struct ril_vendor *vendor,
|
||||
struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||
@@ -483,6 +485,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
modem->ofono = ofono;
|
||||
modem->vendor = ril_vendor_ref(vendor);
|
||||
modem->radio = ril_radio_ref(radio);
|
||||
modem->network = ril_network_ref(network);
|
||||
modem->sim_card = ril_sim_card_ref(card);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -16,6 +17,7 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
@@ -40,8 +42,11 @@ struct ril_netreg {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gboolean network_selection_manual_0;
|
||||
int signal_strength_dbm_weak;
|
||||
int signal_strength_dbm_strong;
|
||||
struct ofono_netreg *netreg;
|
||||
struct ril_network *network;
|
||||
struct ril_vendor *vendor;
|
||||
char *log_prefix;
|
||||
guint timer_id;
|
||||
guint notify_id;
|
||||
@@ -331,100 +336,92 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_netreg_dbm_to_percentage(int dbm)
|
||||
static int ril_netreg_qdbm_to_percentage(struct ril_netreg *nd, int qdbm)
|
||||
{
|
||||
const int min_dbm = -100; /* very weak signal, 0.0000000001 mW */
|
||||
const int max_dbm = -60; /* strong signal, 0.000001 mW */
|
||||
const int min_qdbm = 4 * nd->signal_strength_dbm_weak; /* 4*dBm */
|
||||
const int max_qdbm = 4 * nd->signal_strength_dbm_strong; /* 4*dBm */
|
||||
|
||||
return (dbm <= min_dbm) ? 1 :
|
||||
(dbm >= max_dbm) ? 100 :
|
||||
(100 * (dbm - min_dbm) / (max_dbm - min_dbm));
|
||||
return (qdbm <= min_qdbm) ? 1 :
|
||||
(qdbm >= max_qdbm) ? 100 :
|
||||
(100 * (qdbm - min_qdbm) / (max_qdbm - min_qdbm));
|
||||
}
|
||||
|
||||
static int ril_netreg_get_signal_strength(const void *data, guint len)
|
||||
static int ril_netreg_get_signal_strength(struct ril_netreg *nd,
|
||||
const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
||||
int rsrp = 0, tdscdma_dbm = 0;
|
||||
struct ril_vendor_signal_strength signal;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
signal.gsm = INT_MAX;
|
||||
signal.lte = INT_MAX;
|
||||
signal.qdbm = 0;
|
||||
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &gw_signal);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
if (!ril_vendor_signal_strength_parse(nd->vendor, &signal, &rilp)) {
|
||||
gint32 rsrp = 0, tdscdma_dbm = 0;
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &cdma_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
/* Apply default parsing algorithm */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
signal.gsm = INT_MAX;
|
||||
signal.lte = INT_MAX;
|
||||
signal.qdbm = 0;
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &evdo_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &signal.gsm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, <e_signal);
|
||||
grilio_parser_get_int32(&rilp, &rsrp);
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
|
||||
/* Skip the rest of LTE_SignalStrength_v8 */
|
||||
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* cqi */
|
||||
grilio_parser_get_int32(&rilp, NULL)) { /* timingAdvance */
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* TD_SCDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &tdscdma_dbm); /* rscp */
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &signal.lte);
|
||||
grilio_parser_get_int32(&rilp, &rsrp);
|
||||
|
||||
/* The rest is considered optional */
|
||||
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* cqi */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* timingAdv */
|
||||
/* TD_SCDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &tdscdma_dbm) &&
|
||||
/* RSCP range: 25 to 120 dBm per 3GPP TS 25.123 */
|
||||
tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
|
||||
signal.qdbm = -4 * tdscdma_dbm;
|
||||
} else if (signal.lte == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||
/* RSRP range: 44 to 140 dBm per 3GPP TS 36.133 */
|
||||
signal.qdbm = -rsrp;
|
||||
}
|
||||
}
|
||||
|
||||
if (rsrp == INT_MAX) {
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d, tdscdma: %d",
|
||||
gw_signal, cdma_dbm, evdo_dbm,
|
||||
lte_signal, tdscdma_dbm);
|
||||
} else {
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d, tdscdma: %d",
|
||||
gw_signal, cdma_dbm, evdo_dbm,
|
||||
lte_signal, rsrp, tdscdma_dbm);
|
||||
}
|
||||
DBG("gw: %d, lte: %d, qdbm: %d", signal.gsm, signal.lte, signal.qdbm);
|
||||
|
||||
/* Return the first valid one */
|
||||
|
||||
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
|
||||
* RSRP value. If we've got zero, don't report it just yet. */
|
||||
if (gw_signal >= 1 && gw_signal <= 31) {
|
||||
if (signal.gsm >= 1 && signal.gsm <= 31) {
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
return (gw_signal * 100) / 31;
|
||||
return (signal.gsm * 100) / 31;
|
||||
}
|
||||
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
if (lte_signal >= 0 && lte_signal <= 31) {
|
||||
return (lte_signal * 100) / 31;
|
||||
if (signal.lte >= 0 && signal.lte <= 31) {
|
||||
return (signal.lte * 100) / 31;
|
||||
}
|
||||
|
||||
/* RSCP range: 25 to 120 dBm as defined in 3GPP TS 25.123 */
|
||||
if (tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
|
||||
return ril_netreg_dbm_to_percentage(-tdscdma_dbm);
|
||||
}
|
||||
|
||||
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
|
||||
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||
return ril_netreg_dbm_to_percentage(-rsrp);
|
||||
}
|
||||
|
||||
/* If we've got zero strength and no valid RSRP, then so be it */
|
||||
if (gw_signal == 0) {
|
||||
if (signal.qdbm < 0) {
|
||||
return ril_netreg_qdbm_to_percentage(nd, signal.qdbm);
|
||||
} else if (signal.gsm == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* In case of dbm, return the value directly */
|
||||
if (cdma_dbm != -1) {
|
||||
return MIN(cdma_dbm, 100);
|
||||
}
|
||||
|
||||
if (evdo_dbm != -1) {
|
||||
return MIN(evdo_dbm, 100);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
@@ -434,9 +431,11 @@ static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
int strength;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
|
||||
strength = ril_netreg_get_signal_strength(data, len);
|
||||
strength = ril_netreg_get_signal_strength(nd, data, len);
|
||||
DBG_(nd, "%d", strength);
|
||||
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||
if (strength >= 0) {
|
||||
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||
@@ -447,8 +446,8 @@ static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int strength = ril_netreg_get_signal_strength(data, len);
|
||||
cb(ril_error_ok(&error), strength, cbd->data);
|
||||
cb(ril_error_ok(&error), ril_netreg_get_signal_strength
|
||||
(cbd->nd, data, len), cbd->data);
|
||||
} else {
|
||||
ofono_error("Failed to retrive the signal strength: %s",
|
||||
ril_error_to_string(status));
|
||||
@@ -558,9 +557,12 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
DBG_(nd, "%p", netreg);
|
||||
nd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
nd->q = grilio_queue_new(nd->io);
|
||||
nd->vendor = ril_vendor_ref(modem->vendor);
|
||||
nd->network = ril_network_ref(modem->network);
|
||||
nd->netreg = netreg;
|
||||
nd->network_selection_manual_0 = config->network_selection_manual_0;
|
||||
nd->signal_strength_dbm_weak = config->signal_strength_dbm_weak;
|
||||
nd->signal_strength_dbm_strong = config->signal_strength_dbm_strong;
|
||||
|
||||
ofono_netreg_set_data(netreg, nd);
|
||||
nd->timer_id = g_idle_add(ril_netreg_register, nd);
|
||||
@@ -589,6 +591,7 @@ static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
|
||||
ril_network_remove_all_handlers(nd->network, nd->network_event_id);
|
||||
ril_network_unref(nd->network);
|
||||
ril_vendor_unref(nd->vendor);
|
||||
|
||||
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
|
||||
grilio_channel_unref(nd->io);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +14,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_sim_card.h"
|
||||
@@ -110,6 +113,7 @@ struct ril_network_priv {
|
||||
gboolean set_initial_attach_apn;
|
||||
struct ofono_network_operator operator;
|
||||
gboolean assert_rat;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
gboolean use_data_profiles;
|
||||
int mms_data_profile_id;
|
||||
GSList *data_profiles;
|
||||
@@ -515,13 +519,12 @@ static enum ofono_radio_access_mode ril_network_actual_pref_mode
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* On dual-SIM phones such as Jolla C only one slot at a time
|
||||
* is allowed to use LTE. Even if the slot which has been using
|
||||
* LTE gets powered off, we still need to explicitely set its
|
||||
* preferred mode to GSM, to make LTE machinery available to
|
||||
* the other slot. This sort of behaviour might not be necessary
|
||||
* on some hardware and can (should) be made configurable when
|
||||
* it becomes necessary.
|
||||
* On most dual-SIM phones only one slot at a time is allowed
|
||||
* to use LTE. On some phones (such as Jolla C), even if the
|
||||
* slot which has been using LTE gets powered off, we still
|
||||
* need to explicitly set its preferred mode to GSM, to make
|
||||
* LTE machinery available to the other slot. This behavior is
|
||||
* configurable.
|
||||
*/
|
||||
const enum ofono_radio_access_mode max_pref_mode =
|
||||
(priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
|
||||
@@ -902,39 +905,52 @@ static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean immediate)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode expected_mode =
|
||||
ril_network_actual_pref_mode(self);
|
||||
const enum ofono_radio_access_mode current_mode =
|
||||
ril_network_rat_to_mode(priv->rat);
|
||||
struct ril_radio *radio = priv->radio;
|
||||
|
||||
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
ril_network_stop_timer(self, TIMER_FORCE_CHECK_PREF_MODE);
|
||||
/*
|
||||
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
immediate = TRUE;
|
||||
}
|
||||
/*
|
||||
* On most dual-SIM phones only one slot at a time is allowed
|
||||
* to use LTE. On some phones (such as Jolla C), even if the
|
||||
* slot which has been using LTE gets powered off, we still
|
||||
* need to explicitly set its preferred mode to GSM, to make
|
||||
* LTE machinery available to the other slot. This behavior is
|
||||
* configurable.
|
||||
*/
|
||||
if (radio->state == RADIO_STATE_ON || priv->force_gsm_when_radio_off) {
|
||||
const enum ofono_radio_access_mode expected =
|
||||
ril_network_actual_pref_mode(self);
|
||||
const enum ofono_radio_access_mode actual =
|
||||
ril_network_rat_to_mode(priv->rat);
|
||||
|
||||
if (priv->rat >= 0 && current_mode != expected_mode) {
|
||||
DBG_(self, "rat %d (%s), expected %s", priv->rat,
|
||||
ofono_radio_access_mode_to_string(current_mode),
|
||||
ofono_radio_access_mode_to_string(expected_mode));
|
||||
}
|
||||
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
ril_network_stop_timer(self,
|
||||
TIMER_FORCE_CHECK_PREF_MODE);
|
||||
/*
|
||||
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
immediate = TRUE;
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
if (priv->rat >= 0 && actual != expected) {
|
||||
DBG_(self, "rat %d (%s), expected %s", priv->rat,
|
||||
ofono_radio_access_mode_to_string(actual),
|
||||
ofono_radio_access_mode_to_string(expected));
|
||||
}
|
||||
|
||||
if (current_mode != expected_mode || priv->assert_rat) {
|
||||
const int rat = ril_network_mode_to_rat(self, expected_mode);
|
||||
if (immediate) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
/* OK, later */
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
if (actual != expected || priv->assert_rat) {
|
||||
const int rat = ril_network_mode_to_rat(self, expected);
|
||||
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
/* OK, later */
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1228,6 +1244,7 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
priv->lte_network_mode = config->lte_network_mode;
|
||||
priv->umts_network_mode = config->umts_network_mode;
|
||||
priv->network_mode_timeout = config->network_mode_timeout;
|
||||
priv->force_gsm_when_radio_off = config->force_gsm_when_radio_off;
|
||||
priv->use_data_profiles = config->use_data_profiles;
|
||||
priv->mms_data_profile_id = config->mms_data_profile_id;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -28,7 +28,10 @@
|
||||
#include "ril_devmon.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/sailfish_manager.h>
|
||||
#include "ofono.h"
|
||||
#include "sailfish_manager.h"
|
||||
|
||||
#include <ofono/storage.h>
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#include <grilio_transport.h>
|
||||
@@ -61,7 +64,7 @@
|
||||
|
||||
#define RIL_SUB_SIZE 4
|
||||
|
||||
#define RILMODEM_CONF_FILE CONFIGDIR "/ril_subscription.conf"
|
||||
#define RILMODEM_CONF_FILE "ril_subscription.conf"
|
||||
#define RILMODEM_DEFAULT_IDENTITY "radio:radio"
|
||||
#define RILMODEM_DEFAULT_SOCK "/dev/socket/rild"
|
||||
#define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2"
|
||||
@@ -70,6 +73,8 @@
|
||||
#define RILMODEM_DEFAULT_LTE_MODE PREF_NET_TYPE_LTE_GSM_WCDMA
|
||||
#define RILMODEM_DEFAULT_UMTS_MODE PREF_NET_TYPE_GSM_WCDMA_AUTO
|
||||
#define RILMODEM_DEFAULT_NETWORK_MODE_TIMEOUT (20*1000) /* ms */
|
||||
#define RILMODEM_DEFAULT_DBM_WEAK (-100) /* very weak, 0.0000000001 mW */
|
||||
#define RILMODEM_DEFAULT_DBM_STRONG (-60) /* strong signal, 0.000001 mW */
|
||||
#define RILMODEM_DEFAULT_ENABLE_VOICECALL TRUE
|
||||
#define RILMODEM_DEFAULT_ENABLE_CBS TRUE
|
||||
#define RILMODEM_DEFAULT_ENABLE_STK TRUE
|
||||
@@ -89,6 +94,7 @@
|
||||
#define RILMODEM_DEFAULT_RADIO_POWER_CYCLE TRUE
|
||||
#define RILMODEM_DEFAULT_CONFIRM_RADIO_POWER_ON TRUE
|
||||
#define RILMODEM_DEFAULT_NETWORK_SELECTION_MANUAL_0 TRUE
|
||||
#define RILMODEM_DEFAULT_FORCE_GSM_WHEN_RADIO_OFF TRUE
|
||||
#define RILMODEM_DEFAULT_USE_DATA_PROFILES FALSE
|
||||
#define RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID RIL_DATA_PROFILE_IMS
|
||||
#define RILMODEM_DEFAULT_SLOT_FLAGS SAILFISH_SLOT_NO_FLAGS
|
||||
@@ -128,6 +134,7 @@
|
||||
#define RILCONF_LTE_MODE "lteNetworkMode"
|
||||
#define RILCONF_UMTS_MODE "umtsNetworkMode"
|
||||
#define RILCONF_NETWORK_MODE_TIMEOUT "networkModeTimeout"
|
||||
#define RILCONF_SIGNAL_STRENGTH_RANGE "signalStrengthRange"
|
||||
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
|
||||
#define RILCONF_ECCLIST_FILE "ecclistFile"
|
||||
#define RILCONF_ALLOW_DATA_REQ "allowDataReq"
|
||||
@@ -143,6 +150,7 @@
|
||||
#define RILCONF_CONFIRM_RADIO_POWER_ON "confirmRadioPowerOn"
|
||||
#define RILCONF_SINGLE_DATA_CONTEXT "singleDataContext"
|
||||
#define RILCONF_NETWORK_SELECTION_MANUAL_0 "networkSelectionManual0"
|
||||
#define RILCONF_FORCE_GSM_WHEN_RADIO_OFF "forceGsmWhenRadioOff"
|
||||
#define RILCONF_USE_DATA_PROFILES "useDataProfiles"
|
||||
#define RILCONF_MMS_DATA_PROFILE_ID "mmsDataProfileId"
|
||||
#define RILCONF_DEVMON "deviceStateTracking"
|
||||
@@ -836,7 +844,7 @@ static void ril_plugin_create_modem(ril_slot *slot)
|
||||
modem = ril_modem_create(slot->io, log_prefix, slot->path, slot->imei,
|
||||
slot->imeisv, slot->ecclist_file, &slot->config, slot->radio,
|
||||
slot->network, slot->sim_card, slot->data, slot->sim_settings,
|
||||
slot->cell_info);
|
||||
slot->vendor, slot->cell_info);
|
||||
|
||||
if (modem) {
|
||||
slot->modem = modem;
|
||||
@@ -910,6 +918,7 @@ static void ril_plugin_radio_caps_cb(const struct ril_radio_capability *cap,
|
||||
static void ril_plugin_manager_started(ril_plugin *plugin)
|
||||
{
|
||||
ril_plugin_drop_orphan_slots(plugin);
|
||||
ril_data_manager_check_data(plugin->data_manager);
|
||||
sailfish_slot_manager_started(plugin->handle);
|
||||
}
|
||||
|
||||
@@ -1184,6 +1193,9 @@ static ril_slot *ril_plugin_slot_new_take(char *transport,
|
||||
config->techs = RILMODEM_DEFAULT_TECHS;
|
||||
config->lte_network_mode = RILMODEM_DEFAULT_LTE_MODE;
|
||||
config->umts_network_mode = RILMODEM_DEFAULT_UMTS_MODE;
|
||||
config->network_mode_timeout = RILMODEM_DEFAULT_NETWORK_MODE_TIMEOUT;
|
||||
config->signal_strength_dbm_weak = RILMODEM_DEFAULT_DBM_WEAK;
|
||||
config->signal_strength_dbm_strong = RILMODEM_DEFAULT_DBM_STRONG;
|
||||
config->empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
|
||||
config->radio_power_cycle = RILMODEM_DEFAULT_RADIO_POWER_CYCLE;
|
||||
config->confirm_radio_power_on =
|
||||
@@ -1195,6 +1207,8 @@ static ril_slot *ril_plugin_slot_new_take(char *transport,
|
||||
RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE;
|
||||
config->network_selection_manual_0 =
|
||||
RILMODEM_DEFAULT_NETWORK_SELECTION_MANUAL_0;
|
||||
config->force_gsm_when_radio_off =
|
||||
RILMODEM_DEFAULT_FORCE_GSM_WHEN_RADIO_OFF;
|
||||
config->use_data_profiles = RILMODEM_DEFAULT_USE_DATA_PROFILES;
|
||||
config->mms_data_profile_id = RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID;
|
||||
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
|
||||
@@ -1231,6 +1245,8 @@ static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
|
||||
defaults.empty_pin_query = config->empty_pin_query;
|
||||
defaults.mms_data_profile_id = config->mms_data_profile_id;
|
||||
defaults.use_data_profiles = config->use_data_profiles;
|
||||
defaults.force_gsm_when_radio_off =
|
||||
config->force_gsm_when_radio_off;
|
||||
defaults.query_available_band_mode =
|
||||
config->query_available_band_mode;
|
||||
|
||||
@@ -1241,6 +1257,8 @@ static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
|
||||
config->empty_pin_query = defaults.empty_pin_query;
|
||||
config->use_data_profiles = defaults.use_data_profiles;
|
||||
config->mms_data_profile_id = defaults.mms_data_profile_id;
|
||||
config->force_gsm_when_radio_off =
|
||||
defaults.force_gsm_when_radio_off;
|
||||
config->query_available_band_mode =
|
||||
defaults.query_available_band_mode;
|
||||
}
|
||||
@@ -1350,6 +1368,7 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
char *sval;
|
||||
char **strv;
|
||||
char *modem;
|
||||
GUtilInts *ints;
|
||||
GHashTable *transport_params = g_hash_table_new_full(g_str_hash,
|
||||
g_str_equal, g_free, g_free);
|
||||
char *transport = NULL;
|
||||
@@ -1469,6 +1488,14 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
config->network_selection_manual_0 ? "yes" : "no");
|
||||
}
|
||||
|
||||
/* forceGsmWhenRadioOff */
|
||||
if (ril_config_get_boolean(file, group,
|
||||
RILCONF_FORCE_GSM_WHEN_RADIO_OFF,
|
||||
&config->force_gsm_when_radio_off)) {
|
||||
DBG("%s: " RILCONF_FORCE_GSM_WHEN_RADIO_OFF " %s", group,
|
||||
config->force_gsm_when_radio_off ? "yes" : "no");
|
||||
}
|
||||
|
||||
/* useDataProfiles */
|
||||
if (ril_config_get_boolean(file, group, RILCONF_USE_DATA_PROFILES,
|
||||
&config->use_data_profiles)) {
|
||||
@@ -1539,6 +1566,21 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
config->network_mode_timeout);
|
||||
}
|
||||
|
||||
/* signalStrengthRange */
|
||||
ints = ril_config_get_ints(file, group, RILCONF_SIGNAL_STRENGTH_RANGE);
|
||||
if (gutil_ints_get_count(ints) == 2) {
|
||||
const int* dbms = gutil_ints_get_data(ints, NULL);
|
||||
|
||||
/* MIN,MAX */
|
||||
if (dbms[0] < dbms[1]) {
|
||||
DBG("%s: " RILCONF_SIGNAL_STRENGTH_RANGE " [%d,%d]",
|
||||
group, dbms[0], dbms[1]);
|
||||
config->signal_strength_dbm_weak = dbms[0];
|
||||
config->signal_strength_dbm_strong = dbms[1];
|
||||
}
|
||||
}
|
||||
gutil_ints_unref(ints);
|
||||
|
||||
/* enable4G (deprecated but still supported) */
|
||||
ival = config->techs;
|
||||
if (ril_config_get_flag(file, group, RILCONF_4G,
|
||||
@@ -1865,7 +1907,7 @@ static GSList *ril_plugin_load_config(const char *path,
|
||||
GKeyFile *file = g_key_file_new();
|
||||
gboolean empty = FALSE;
|
||||
|
||||
ril_config_merge_files(file, path);
|
||||
config_merge_files(file, path);
|
||||
if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP,
|
||||
RILCONF_SETTINGS_EMPTY, &empty) && empty) {
|
||||
DBG("Empty config");
|
||||
@@ -2051,12 +2093,15 @@ static guint ril_plugin_manager_start(ril_plugin *plugin)
|
||||
{
|
||||
struct ril_plugin_settings *ps = &plugin->settings;
|
||||
guint start_timeout = 0;
|
||||
char* config_file = g_build_filename(ofono_config_dir(),
|
||||
RILMODEM_CONF_FILE, NULL);
|
||||
|
||||
DBG("");
|
||||
GASSERT(!plugin->start_timeout_id);
|
||||
plugin->slots = ril_plugin_load_config(RILMODEM_CONF_FILE, ps);
|
||||
plugin->slots = ril_plugin_load_config(config_file, ps);
|
||||
plugin->data_manager = ril_data_manager_new(ps->dm_flags);
|
||||
ril_plugin_init_slots(plugin);
|
||||
g_free(config_file);
|
||||
|
||||
ofono_modem_driver_register(&ril_modem_driver);
|
||||
ofono_sim_driver_register(&ril_sim_driver);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -52,6 +53,7 @@ struct ril_modem {
|
||||
const char *ecclist_file;
|
||||
struct ofono_modem *ofono;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
struct ril_vendor *vendor;
|
||||
struct ril_radio *radio;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
@@ -70,7 +72,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct ril_sim_settings *settings, struct ril_vendor *vendor,
|
||||
struct sailfish_cell_info *cell_info);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
|
||||
@@ -237,6 +237,17 @@ socket=/dev/socket/rild
|
||||
#
|
||||
#networkModeTimeout=20000
|
||||
|
||||
# Comma-separated signal strength range, in dBm.
|
||||
#
|
||||
# These values are used for translating dBm values returned by the modem in
|
||||
# LTE mode into signal strength percentage. If you are getting significantly
|
||||
# different signal strength readings in GSM and LTE modes, you may need to
|
||||
# tweak those.
|
||||
#
|
||||
# Default -100,-60
|
||||
#
|
||||
#signalStrengthRange=-100,-60
|
||||
|
||||
# Cycle radio power at startup.
|
||||
#
|
||||
# Default true (cycle the power)
|
||||
@@ -297,3 +308,11 @@ socket=/dev/socket/rild
|
||||
# Default auto
|
||||
#
|
||||
#deviceStateTracking=auto
|
||||
|
||||
# On some phones (such as Jolla C), even if the slot which has been
|
||||
# using LTE gets powered off, we still need to explicitely set its
|
||||
# preferred mode to GSM, to make LTE machinery available to the other slot.
|
||||
#
|
||||
# Default true (false for MTK RILs)
|
||||
#
|
||||
#forceGsmWhenRadioOff=true
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -54,6 +55,8 @@ struct ril_slot_config {
|
||||
enum ril_pref_net_type lte_network_mode;
|
||||
enum ril_pref_net_type umts_network_mode;
|
||||
int network_mode_timeout;
|
||||
int signal_strength_dbm_weak;
|
||||
int signal_strength_dbm_strong;
|
||||
gboolean query_available_band_mode;
|
||||
gboolean empty_pin_query;
|
||||
gboolean radio_power_cycle;
|
||||
@@ -62,6 +65,7 @@ struct ril_slot_config {
|
||||
gboolean enable_cbs;
|
||||
gboolean enable_stk;
|
||||
gboolean network_selection_manual_0;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
gboolean use_data_profiles;
|
||||
guint mms_data_profile_id;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -116,6 +117,14 @@ gboolean ril_vendor_data_call_parse(RilVendor *self,
|
||||
data_call_parse(self, call, ver, rilp);
|
||||
}
|
||||
|
||||
gboolean ril_vendor_signal_strength_parse(RilVendor *self,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
|
||||
signal_strength_parse(self, signal_strength, rilp);
|
||||
}
|
||||
|
||||
static void ril_vendor_default_set_network(RilVendor *self,
|
||||
struct ril_network *network)
|
||||
{
|
||||
@@ -160,6 +169,13 @@ static gboolean ril_vendor_default_data_call_parse(RilVendor *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_default_signal_strength_parse(RilVendor *self,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void ril_vendor_init_base(RilVendor *self, GRilIoChannel *io)
|
||||
{
|
||||
self->io = grilio_channel_ref(io);
|
||||
@@ -190,6 +206,7 @@ static void ril_vendor_class_init(RilVendorClass* klass)
|
||||
klass->set_attach_apn_req = ril_vendor_default_set_attach_apn_req;
|
||||
klass->data_call_req = ril_vendor_default_data_call_req;
|
||||
klass->data_call_parse = ril_vendor_default_data_call_parse;
|
||||
klass->signal_strength_parse = ril_vendor_default_signal_strength_parse;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -25,6 +26,7 @@ struct ril_vendor_defaults {
|
||||
gboolean enable_stk;
|
||||
gboolean query_available_band_mode;
|
||||
gboolean use_data_profiles;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
guint mms_data_profile_id;
|
||||
};
|
||||
|
||||
@@ -37,6 +39,12 @@ struct ril_vendor_driver {
|
||||
const struct ril_slot_config *cfg);
|
||||
};
|
||||
|
||||
struct ril_vendor_signal_strength {
|
||||
gint32 gsm; /* (0-31, 99) per TS 27.007 8.5 */
|
||||
gint32 lte; /* (0-31, 99) per TS 27.007 8.5 */
|
||||
gint32 qdbm; /* 4*dBm, 0 if none */
|
||||
};
|
||||
|
||||
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name);
|
||||
struct ril_vendor *ril_vendor_create
|
||||
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
|
||||
@@ -63,6 +71,9 @@ GRilIoRequest *ril_vendor_data_call_req(struct ril_vendor *vendor, int tech,
|
||||
gboolean ril_vendor_data_call_parse(struct ril_vendor *vendor,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp);
|
||||
gboolean ril_vendor_signal_strength_parse(struct ril_vendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp);
|
||||
|
||||
/* Put vendor driver descriptors to the "__vendor" section */
|
||||
#define RIL_VENDOR_DRIVER_DEFINE(name) const struct ril_vendor_driver name \
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -42,6 +43,9 @@ typedef struct ril_vendor_class {
|
||||
gboolean (*data_call_parse)(RilVendor *vendor,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp);
|
||||
gboolean (*signal_strength_parse)(RilVendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp);
|
||||
} RilVendorClass;
|
||||
|
||||
GType ril_vendor_get_type(void);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -79,6 +80,8 @@ struct ril_mtk_flavor {
|
||||
enum ril_auth auth, const char *proto);
|
||||
gboolean (*data_call_parse_fn)(struct ril_data_call *call,
|
||||
int version, GRilIoParser *rilp);
|
||||
gboolean (*signal_strength_fn)(struct ril_vendor_signal_strength *sig,
|
||||
GRilIoParser *rilp);
|
||||
};
|
||||
|
||||
/* MTK specific RIL messages (actual codes differ from model to model!) */
|
||||
@@ -401,6 +404,96 @@ static gboolean ril_vendor_mtk_data_call_parse(RilVendor *vendor,
|
||||
data_call_parse(vendor, call, version, rilp);
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_signal_strength_1
|
||||
(struct ril_vendor_signal_strength *signal, GRilIoParser *rilp)
|
||||
{
|
||||
if (grilio_parser_bytes_remaining(rilp) == 64) {
|
||||
gint32 rsrp = 0, rssi = 0;
|
||||
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->gsm);
|
||||
grilio_parser_get_int32(rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->lte);
|
||||
grilio_parser_get_int32(rilp, &rsrp); /* rsrp */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rsrq */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rssnr */
|
||||
grilio_parser_get_int32(rilp, NULL); /* cqi */
|
||||
|
||||
/* ???? */
|
||||
grilio_parser_get_int32(rilp, NULL);
|
||||
grilio_parser_get_int32(rilp, &rssi);
|
||||
grilio_parser_get_int32(rilp, NULL);
|
||||
grilio_parser_get_int32(rilp, NULL);
|
||||
|
||||
signal->qdbm = (rssi > 0 && rssi != INT_MAX) ? (-4 * rssi) :
|
||||
(rsrp >= 44 && rsrp <= 140) ? (-4 * rsrp) : 0;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_signal_strength_2
|
||||
(struct ril_vendor_signal_strength *signal, GRilIoParser *rilp)
|
||||
{
|
||||
if (grilio_parser_bytes_remaining(rilp) == 64) {
|
||||
gint32 rsrp = 0, is_gsm = 0, rssi_qdbm = 0;
|
||||
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->gsm);
|
||||
grilio_parser_get_int32(rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->lte);
|
||||
grilio_parser_get_int32(rilp, &rsrp); /* rsrp */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rsrq */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rssnr */
|
||||
grilio_parser_get_int32(rilp, NULL); /* cqi */
|
||||
|
||||
/* WCDMA_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &is_gsm); /* isGsm */
|
||||
grilio_parser_get_int32(rilp, &rssi_qdbm); /* rssiQdbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rscpQdbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* Ecn0Qdbm*/
|
||||
|
||||
signal->qdbm = (is_gsm == 1 && rssi_qdbm < 0) ? rssi_qdbm :
|
||||
(rsrp >= 44 && rsrp <= 140) ? (-4 * rsrp) : 0;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_signal_strength_parse(RilVendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
const struct ril_mtk_flavor *flavor = RIL_VENDOR_MTK(vendor)->flavor;
|
||||
|
||||
return flavor->signal_strength_fn ?
|
||||
flavor->signal_strength_fn(signal, rilp) :
|
||||
RIL_VENDOR_CLASS(ril_vendor_mtk_parent_class)->
|
||||
signal_strength_parse(vendor, signal, rilp);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
|
||||
{
|
||||
/*
|
||||
@@ -415,6 +508,7 @@ static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
|
||||
defaults->query_available_band_mode = FALSE;
|
||||
defaults->empty_pin_query = FALSE;
|
||||
defaults->legacy_imei_query = TRUE;
|
||||
defaults->force_gsm_when_radio_off = FALSE;
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_base_init(RilVendorMtk *self, GRilIoChannel *io,
|
||||
@@ -496,20 +590,23 @@ static void ril_vendor_mtk_class_init(RilVendorMtkClass* klass)
|
||||
klass->set_attach_apn_req = ril_vendor_mtk_set_attach_apn_req;
|
||||
klass->data_call_req = ril_vendor_mtk_data_call_req;
|
||||
klass->data_call_parse = ril_vendor_mtk_data_call_parse;
|
||||
klass->signal_strength_parse = ril_vendor_mtk_signal_strength_parse;
|
||||
}
|
||||
|
||||
static const struct ril_mtk_flavor ril_mtk_flavor1 = {
|
||||
.name = "mtk1",
|
||||
.msg = &msg_mtk1,
|
||||
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_1,
|
||||
.data_call_parse_fn = NULL
|
||||
.data_call_parse_fn = NULL,
|
||||
.signal_strength_fn = &ril_vendor_mtk_signal_strength_1
|
||||
};
|
||||
|
||||
static const struct ril_mtk_flavor ril_mtk_flavor2 = {
|
||||
.name = "mtk2",
|
||||
.msg = &msg_mtk2,
|
||||
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_2,
|
||||
.data_call_parse_fn = &ril_vendor_mtk_data_call_parse_v6
|
||||
.data_call_parse_fn = &ril_vendor_mtk_data_call_parse_v6,
|
||||
.signal_strength_fn = &ril_vendor_mtk_signal_strength_2
|
||||
};
|
||||
|
||||
#define DEFAULT_MTK_TYPE (&ril_mtk_flavor1)
|
||||
|
||||
0
ofono/drivers/xmm7modem/ims.c
Executable file → Normal file
0
ofono/drivers/xmm7modem/ims.c
Executable file → Normal file
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -25,7 +26,7 @@ extern "C" {
|
||||
enum ofono_dbus_access {
|
||||
OFONO_DBUS_ACCESS_DENY, /* Deny access */
|
||||
OFONO_DBUS_ACCESS_ALLOW, /* Allow access */
|
||||
OFONO_DBUS_ACCESS_DONT_CARE, /* No decision */
|
||||
OFONO_DBUS_ACCESS_DONT_CARE /* No decision */
|
||||
};
|
||||
|
||||
enum ofono_dbus_access_intf {
|
||||
@@ -38,6 +39,7 @@ enum ofono_dbus_access_intf {
|
||||
OFONO_DBUS_ACCESS_INTF_SIMMGR, /* org.ofono.SimManager */
|
||||
OFONO_DBUS_ACCESS_INTF_MODEM, /* org.ofono.Modem */
|
||||
OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS, /* org.ofono.RadioSettings */
|
||||
OFONO_DBUS_ACCESS_INTF_STK, /* org.ofono.SimToolkit */
|
||||
OFONO_DBUS_ACCESS_INTF_COUNT
|
||||
};
|
||||
|
||||
@@ -116,6 +118,12 @@ enum ofono_dbus_access_radiosettings_method {
|
||||
OFONO_DBUS_ACCESS_RADIOSETTINGS_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_STK */
|
||||
enum ofono_dbus_access_stk_method {
|
||||
OFONO_DBUS_ACCESS_STK_REGISTER_AGENT,
|
||||
OFONO_DBUS_ACCESS_STK_METHOD_COUNT
|
||||
};
|
||||
|
||||
#define OFONO_DBUS_ACCESS_PRIORITY_LOW (-100)
|
||||
#define OFONO_DBUS_ACCESS_PRIORITY_DEFAULT (0)
|
||||
#define OFONO_DBUS_ACCESS_PRIORITY_HIGH (100)
|
||||
|
||||
@@ -139,7 +139,12 @@ struct ofono_voicecall_driver {
|
||||
/* Dials the last number again, this handles the hfp profile last number
|
||||
* dialing with the +BLDN AT command
|
||||
*/
|
||||
void (*dial_last)(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data);
|
||||
void (*dial_last)(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
|
||||
void *data);
|
||||
/* dials a number at a given memory location */
|
||||
void (*dial_memory)(struct ofono_voicecall *vc,
|
||||
unsigned int memory_location, ofono_voicecall_cb_t cb,
|
||||
void *data);
|
||||
};
|
||||
|
||||
void ofono_voicecall_en_list_notify(struct ofono_voicecall *vc,
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <ofono/ussd.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/lte.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
#include <ofono/log.h>
|
||||
@@ -483,6 +484,8 @@ static void gobi_post_sim(struct ofono_modem *modem)
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_lte_create(modem, "qmimodem", data->device);
|
||||
|
||||
if (data->features & GOBI_CAT)
|
||||
ofono_stk_create(modem, 0, "qmimodem", data->device);
|
||||
else if (data->features & GOBI_CAT_OLD)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017-2019 Jolla Ltd.
|
||||
* Copyright (C) 2017-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -22,6 +23,7 @@
|
||||
#include <gutil_macros.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ofono/storage.h>
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#include "src/ofono.h"
|
||||
@@ -44,6 +46,12 @@ enum ofono_watch_events {
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum sim_auto_select {
|
||||
SIM_AUTO_SELECT_OFF,
|
||||
SIM_AUTO_SELECT_ON,
|
||||
SIM_AUTO_SELECT_ONCE
|
||||
};
|
||||
|
||||
struct sailfish_manager_priv {
|
||||
struct sailfish_manager pub; /* Public part */
|
||||
struct sailfish_slot_driver_reg *drivers;
|
||||
@@ -52,6 +60,8 @@ struct sailfish_manager_priv {
|
||||
struct sailfish_slot_priv *data_slot;
|
||||
struct sailfish_slot_priv *mms_slot;
|
||||
sailfish_slot_ptr *slots;
|
||||
enum sim_auto_select auto_data_sim;
|
||||
gboolean auto_data_sim_done;
|
||||
int slot_count;
|
||||
guint init_countdown;
|
||||
guint init_id;
|
||||
@@ -99,6 +109,11 @@ struct sailfish_slot_priv {
|
||||
int index;
|
||||
};
|
||||
|
||||
/* Read-only config */
|
||||
#define SF_CONFIG_FILE "main.conf"
|
||||
#define SF_CONFIG_GROUP "ModemManager"
|
||||
#define SF_CONFIG_KEY_AUTO_DATA_SIM "AutoSelectDataSim"
|
||||
|
||||
/* "ril" is used for historical reasons */
|
||||
#define SF_STORE "ril"
|
||||
#define SF_STORE_GROUP "Settings"
|
||||
@@ -106,6 +121,7 @@ struct sailfish_slot_priv {
|
||||
#define SF_STORE_DEFAULT_VOICE_SIM "DefaultVoiceSim"
|
||||
#define SF_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
|
||||
#define SF_STORE_SLOTS_SEP ","
|
||||
#define SF_STORE_AUTO_DATA_SIM_DONE "AutoSelectDataSimDone"
|
||||
|
||||
/* The file where error statistics is stored. Again "rilerror" is historical */
|
||||
#define SF_ERROR_STORAGE "rilerror" /* File name */
|
||||
@@ -145,6 +161,50 @@ static inline void sailfish_slot_set_data_role(struct sailfish_slot_priv *s,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean sailfish_config_get_enum(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
{
|
||||
char *str = g_key_file_get_string(file, group, key, NULL);
|
||||
|
||||
if (str) {
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(str, '#');
|
||||
|
||||
if (comment) *comment = 0;
|
||||
g_strstrip(str);
|
||||
if (strcasecmp(str, name)) {
|
||||
va_list args;
|
||||
va_start(args, value);
|
||||
while ((name = va_arg(args, char*)) != NULL) {
|
||||
value = va_arg(args, int);
|
||||
if (!strcasecmp(str, name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
ofono_error("Invalid %s config value (%s)", key, str);
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
|
||||
if (name) {
|
||||
if (result) {
|
||||
*result = value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Update modem paths and emit D-Bus signal if necessary */
|
||||
static void sailfish_manager_update_modem_paths_full
|
||||
(struct sailfish_manager_priv *p)
|
||||
@@ -588,6 +648,27 @@ static struct sailfish_slot_priv *sailfish_manager_find_slot_imsi
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean sailfish_manager_all_sims_are_initialized_proc
|
||||
(struct sailfish_slot_priv *s, void *user_data)
|
||||
{
|
||||
if (s->pub.sim_present && s->pub.enabled && !s->watch->imsi) {
|
||||
*((gboolean*)user_data) = FALSE;
|
||||
return SF_LOOP_DONE;
|
||||
} else {
|
||||
return SF_LOOP_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean sailfish_manager_all_sims_are_initialized
|
||||
(struct sailfish_manager_priv *p)
|
||||
{
|
||||
gboolean result = TRUE;
|
||||
|
||||
sailfish_manager_foreach_slot(p,
|
||||
sailfish_manager_all_sims_are_initialized_proc, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Returns the event mask to be passed to sailfish_manager_dbus_signal.
|
||||
* The caller has a chance to OR it with other bits */
|
||||
static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
|
||||
@@ -615,7 +696,7 @@ static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
|
||||
* previously selected voice SIM is inserted, we will switch
|
||||
* back to it.
|
||||
*
|
||||
* There is no such fallback for the data.
|
||||
* A similar behavior can be configured for data SIM too.
|
||||
*/
|
||||
if (!slot) {
|
||||
slot = sailfish_manager_find_slot_imsi(p, NULL);
|
||||
@@ -648,13 +729,52 @@ static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
|
||||
slot = sailfish_manager_find_slot_imsi(p, NULL);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Should we automatically select the default data sim
|
||||
* on a multisim phone that has only one sim inserted?
|
||||
*/
|
||||
slot = NULL;
|
||||
}
|
||||
|
||||
/* Check if we need to auto-select data SIM (always or once) */
|
||||
if (!slot && (p->auto_data_sim == SIM_AUTO_SELECT_ON ||
|
||||
(p->auto_data_sim == SIM_AUTO_SELECT_ONCE &&
|
||||
!p->auto_data_sim_done))) {
|
||||
/*
|
||||
* To actually make a selection we need all present SIMs
|
||||
* to be initialized. Otherwise we may end up endlessly
|
||||
* switching data SIMs back and forth.
|
||||
*/
|
||||
if (sailfish_manager_all_sims_are_initialized(p)) {
|
||||
slot = sailfish_manager_find_slot_imsi(p, NULL);
|
||||
if (slot && slot->watch->imsi && slot->watch->online &&
|
||||
p->auto_data_sim == SIM_AUTO_SELECT_ONCE) {
|
||||
const char *imsi = slot->watch->imsi;
|
||||
|
||||
/*
|
||||
* Data SIM only needs to be auto-selected
|
||||
* once and it's done. Write that down.
|
||||
*/
|
||||
DBG("Default data sim set to %s once", imsi);
|
||||
p->auto_data_sim_done = TRUE;
|
||||
g_key_file_set_boolean(p->storage,
|
||||
SF_STORE_GROUP,
|
||||
SF_STORE_AUTO_DATA_SIM_DONE,
|
||||
p->auto_data_sim_done);
|
||||
|
||||
g_free(p->default_data_imsi);
|
||||
p->pub.default_data_imsi =
|
||||
p->default_data_imsi = g_strdup(imsi);
|
||||
g_key_file_set_string(p->storage,
|
||||
SF_STORE_GROUP,
|
||||
SF_STORE_DEFAULT_DATA_SIM,
|
||||
imsi);
|
||||
|
||||
storage_sync(NULL, SF_STORE, p->storage);
|
||||
sailfish_manager_dbus_signal(p->dbus,
|
||||
SAILFISH_MANAGER_SIGNAL_DATA_IMSI);
|
||||
}
|
||||
} else {
|
||||
DBG("Skipping auto-selection of data SIM");
|
||||
}
|
||||
}
|
||||
|
||||
if (slot && !slot->watch->online) {
|
||||
slot = NULL;
|
||||
}
|
||||
@@ -1274,6 +1394,29 @@ static struct sailfish_manager_priv *sailfish_manager_priv_new()
|
||||
|
||||
struct sailfish_manager_priv *p =
|
||||
g_slice_new0(struct sailfish_manager_priv);
|
||||
GKeyFile *conf = g_key_file_new();
|
||||
char* fn = g_build_filename(ofono_config_dir(), SF_CONFIG_FILE, NULL);
|
||||
|
||||
/* Load config */
|
||||
if (g_key_file_load_from_file(conf, fn, 0, NULL)) {
|
||||
int ival;
|
||||
|
||||
DBG("Loading configuration file %s", fn);
|
||||
if (sailfish_config_get_enum(conf, SF_CONFIG_GROUP,
|
||||
SF_CONFIG_KEY_AUTO_DATA_SIM, &ival,
|
||||
"off", SIM_AUTO_SELECT_OFF,
|
||||
"once", SIM_AUTO_SELECT_ONCE,
|
||||
"always", SIM_AUTO_SELECT_ON,
|
||||
"on", SIM_AUTO_SELECT_ON, NULL)) {
|
||||
DBG("Automatic data SIM selection: %s",
|
||||
ival == SIM_AUTO_SELECT_ONCE ? "once":
|
||||
ival == SIM_AUTO_SELECT_ON ? "on":
|
||||
"off");
|
||||
p->auto_data_sim = ival;
|
||||
}
|
||||
}
|
||||
g_key_file_free(conf);
|
||||
g_free(fn);
|
||||
|
||||
/* Load settings */
|
||||
p->storage = storage_open(NULL, SF_STORE);
|
||||
@@ -1283,6 +1426,8 @@ static struct sailfish_manager_priv *sailfish_manager_priv_new()
|
||||
p->pub.default_data_imsi = p->default_data_imsi =
|
||||
g_key_file_get_string(p->storage, SF_STORE_GROUP,
|
||||
SF_STORE_DEFAULT_DATA_SIM, NULL);
|
||||
p->auto_data_sim_done = g_key_file_get_boolean(p->storage,
|
||||
SF_STORE_GROUP, SF_STORE_AUTO_DATA_SIM_DONE, NULL);
|
||||
|
||||
DBG("Default voice sim is %s", p->default_voice_imsi ?
|
||||
p->default_voice_imsi : "(auto)");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017-2019 Jolla Ltd.
|
||||
* Copyright (C) 2017-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
@@ -1731,6 +1731,8 @@ static gboolean create_modem(gpointer key, gpointer value, gpointer user_data)
|
||||
continue;
|
||||
|
||||
if (driver_list[i].setup(modem) == TRUE) {
|
||||
ofono_modem_set_string(modem->modem, "SystemPath",
|
||||
syspath);
|
||||
ofono_modem_register(modem->modem);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
365
ofono/src/config.c
Normal file
365
ofono/src/config.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/**
|
||||
* The config_merge_files() function does the following:
|
||||
*
|
||||
* 1. Loads the specified key file (say, "/etc/foo.conf")
|
||||
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
|
||||
* for the files with the same suffix as the main file (e.g. "*.conf")
|
||||
* 3. Sorts the files from the subdirectory (alphabetically)
|
||||
* 4. Merges the contents of the additional files with the main file
|
||||
* according to their sort order.
|
||||
*
|
||||
* When the entries are merged, keys and groups overwrite the exising
|
||||
* ones by default. Keys can be suffixed with special characters to
|
||||
* remove or modify the existing entries instead:
|
||||
*
|
||||
* ':' Sets the (default) value if the key is missing
|
||||
* '+' Appends values to the string list
|
||||
* '?' Appends only new (non-existent) values to the string list
|
||||
* '-' Removes the values from the string list
|
||||
*
|
||||
* Both keys and groups can be prefixed with '!' to remove the entire key
|
||||
* or group.
|
||||
*
|
||||
* For example if we merge these two files:
|
||||
*
|
||||
* /etc/foo.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=4
|
||||
* d=5
|
||||
* [bar]
|
||||
* e=5
|
||||
*
|
||||
* /etc/foo.d/bar.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a+=2
|
||||
* b-=2
|
||||
* c=5
|
||||
* !d
|
||||
* [!bar]
|
||||
*
|
||||
* we end up with this:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=5
|
||||
*
|
||||
* Note that the list separator is assumed to be ',' (rather than default ';').
|
||||
* The keyfile passed to config_merge_files() should use the same list
|
||||
* separator, because the default values are copied from the config files
|
||||
* as is.
|
||||
*/
|
||||
|
||||
static gint config_sort_files(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
/* The comparison function for g_ptr_array_sort() doesn't take
|
||||
* the pointers from the array as arguments, it takes pointers
|
||||
* to the pointers in the array. */
|
||||
return strcmp(*(char**)a, *(char**)b);
|
||||
}
|
||||
|
||||
static char **config_collect_files(const char *path, const char *suffix)
|
||||
{
|
||||
/* Returns sorted list of regular files in the directory,
|
||||
* optionally having the specified suffix (e.g. ".conf").
|
||||
* Returns NULL if nothing appropriate has been found. */
|
||||
char **files = NULL;
|
||||
DIR *d = opendir(path);
|
||||
|
||||
if (d) {
|
||||
GPtrArray *list = g_ptr_array_new();
|
||||
const struct dirent *p;
|
||||
|
||||
while ((p = readdir(d)) != NULL) {
|
||||
/* No need to even stat . and .. */
|
||||
if (strcmp(p->d_name, ".") &&
|
||||
strcmp(p->d_name, "..") && (!suffix ||
|
||||
g_str_has_suffix(p->d_name, suffix))) {
|
||||
struct stat st;
|
||||
char *buf = g_strconcat(path, "/", p->d_name,
|
||||
NULL);
|
||||
|
||||
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
|
||||
g_ptr_array_add(list, buf);
|
||||
} else {
|
||||
g_free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (list->len > 0) {
|
||||
g_ptr_array_sort(list, config_sort_files);
|
||||
g_ptr_array_add(list, NULL);
|
||||
files = (char**)g_ptr_array_free(list, FALSE);
|
||||
} else {
|
||||
g_ptr_array_free(list, TRUE);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
static int config_list_find(char **list, gsize len, const char *value)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!strcmp(list[i], value)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void config_list_append(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key,
|
||||
char **values, gsize n, gboolean unique)
|
||||
{
|
||||
/* Note: will steal strings from values */
|
||||
if (n > 0) {
|
||||
int i;
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
|
||||
|
||||
for (i = 0; i < (int)len; i++) {
|
||||
g_ptr_array_add(newlist, list[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)n; i++) {
|
||||
char *val = values[i];
|
||||
|
||||
if (!unique || config_list_find((char**)
|
||||
newlist->pdata, newlist->len, val) < 0) {
|
||||
/* Move the string to the new list */
|
||||
g_ptr_array_add(newlist, val);
|
||||
memmove(values + i, values + i + 1,
|
||||
sizeof(char*) * (n - i));
|
||||
i--;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
if (newlist->len > len) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) newlist->pdata,
|
||||
newlist->len);
|
||||
}
|
||||
|
||||
/* Strings are deallocated by GPtrArray */
|
||||
g_ptr_array_free(newlist, TRUE);
|
||||
g_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void config_list_remove(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key, char **values, gsize n)
|
||||
{
|
||||
if (n > 0) {
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
|
||||
if (len > 0) {
|
||||
gsize i;
|
||||
const gsize oldlen = len;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
int pos;
|
||||
|
||||
/* Remove all matching values */
|
||||
while ((pos = config_list_find(list, len,
|
||||
values[i])) >= 0) {
|
||||
g_free(list[pos]);
|
||||
memmove(list + pos, list + pos + 1,
|
||||
sizeof(char*) * (len - pos));
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (len < oldlen) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) list, len);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void config_merge_group(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **keys = g_key_file_get_keys(k, group, &n, NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
char *key = keys[i];
|
||||
|
||||
if (key[0] == '!') {
|
||||
if (key[1]) {
|
||||
g_key_file_remove_key(conf, group, key+1, NULL);
|
||||
}
|
||||
} else {
|
||||
const gsize len = strlen(key);
|
||||
const char last = (len > 0) ? key[len-1] : 0;
|
||||
|
||||
if (last == '+' || last == '?') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
config_list_append(conf, k, group, key,
|
||||
values, count, last == '?');
|
||||
g_strfreev(values);
|
||||
} else if (last == '-') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
config_list_remove(conf, k, group, key,
|
||||
values, count);
|
||||
g_strfreev(values);
|
||||
} else {
|
||||
/* Overwrite the value (it must exist in k) */
|
||||
gchar *value = g_key_file_get_value(k, group,
|
||||
key, NULL);
|
||||
|
||||
if (last == ':') {
|
||||
/* Default value */
|
||||
key[len-1] = 0;
|
||||
if (!g_key_file_has_key(conf,
|
||||
group, key, NULL)) {
|
||||
g_key_file_set_value(conf,
|
||||
group, key, value);
|
||||
}
|
||||
} else {
|
||||
g_key_file_set_value(conf, group, key,
|
||||
value);
|
||||
}
|
||||
g_free(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(keys);
|
||||
}
|
||||
|
||||
static void config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **groups = g_key_file_get_groups(k, &n);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
const char *group = groups[i];
|
||||
|
||||
if (group[0] == '!') {
|
||||
g_key_file_remove_group(conf, group + 1, NULL);
|
||||
} else {
|
||||
config_merge_group(conf, k, group);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(groups);
|
||||
}
|
||||
|
||||
static void config_merge_file(GKeyFile *conf, const char *file)
|
||||
{
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_key_file_set_list_separator(k, ',');
|
||||
|
||||
if (g_key_file_load_from_file(k, file, 0, NULL)) {
|
||||
config_merge_keyfile(conf, k);
|
||||
}
|
||||
|
||||
g_key_file_unref(k);
|
||||
}
|
||||
|
||||
void config_merge_files(GKeyFile *conf, const char *file)
|
||||
{
|
||||
if (conf && file && file[0]) {
|
||||
char *dot = strrchr(file, '.');
|
||||
const char *suffix;
|
||||
char *dir;
|
||||
char **files;
|
||||
|
||||
if (!dot) {
|
||||
dir = g_strconcat(file, ".d", NULL);
|
||||
suffix = NULL;
|
||||
} else if (!dot[1]) {
|
||||
dir = g_strconcat(file, "d", NULL);
|
||||
suffix = NULL;
|
||||
} else {
|
||||
/* 2 bytes for ".d" and 1 for NULL terminator */
|
||||
dir = g_malloc(dot - file + 3);
|
||||
strncpy(dir, file, dot - file);
|
||||
strcpy(dir + (dot - file), ".d");
|
||||
suffix = dot + 1;
|
||||
}
|
||||
|
||||
files = config_collect_files(dir, suffix);
|
||||
g_free(dir);
|
||||
|
||||
/* Load the main config */
|
||||
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
|
||||
DBG("Loading %s", file);
|
||||
config_merge_file(conf, file);
|
||||
}
|
||||
|
||||
if (files) {
|
||||
char **ptr;
|
||||
|
||||
for (ptr = files; *ptr; ptr++) {
|
||||
DBG("Merging %s", *ptr);
|
||||
config_merge_file(conf, *ptr);
|
||||
}
|
||||
|
||||
g_strfreev(files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -41,6 +42,8 @@ const char *ofono_dbus_access_intf_name(enum ofono_dbus_access_intf intf)
|
||||
return OFONO_MODEM_INTERFACE;
|
||||
case OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS:
|
||||
return OFONO_RADIO_SETTINGS_INTERFACE;
|
||||
case OFONO_DBUS_ACCESS_INTF_STK:
|
||||
return OFONO_STK_INTERFACE;
|
||||
case OFONO_DBUS_ACCESS_INTF_COUNT:
|
||||
break;
|
||||
}
|
||||
@@ -165,6 +168,14 @@ const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OFONO_DBUS_ACCESS_INTF_STK:
|
||||
switch ((enum ofono_dbus_access_stk_method)method) {
|
||||
case OFONO_DBUS_ACCESS_STK_REGISTER_AGENT:
|
||||
return "RegisterAgent";
|
||||
case OFONO_DBUS_ACCESS_STK_METHOD_COUNT:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OFONO_DBUS_ACCESS_INTF_COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -805,6 +805,7 @@ void __ofono_modem_append_properties(struct ofono_modem *modem,
|
||||
struct ofono_devinfo *info;
|
||||
dbus_bool_t emergency = ofono_modem_get_emergency_mode(modem);
|
||||
const char *strtype;
|
||||
const char *system_path;
|
||||
|
||||
ofono_dbus_dict_append(dict, "Online", DBUS_TYPE_BOOLEAN,
|
||||
&modem->online);
|
||||
@@ -845,6 +846,11 @@ void __ofono_modem_append_properties(struct ofono_modem *modem,
|
||||
&info->svn);
|
||||
}
|
||||
|
||||
system_path = ofono_modem_get_string(modem, "SystemPath");
|
||||
if (system_path)
|
||||
ofono_dbus_dict_append(dict, "SystemPath", DBUS_TYPE_STRING,
|
||||
&system_path);
|
||||
|
||||
interfaces = g_new0(char *, g_slist_length(modem->interface_list) + 1);
|
||||
for (i = 0, l = modem->interface_list; l; l = l->next, i++)
|
||||
interfaces[i] = l->data;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -684,3 +685,6 @@ int mnclength(int mcc, int mnc);
|
||||
#include <ofono/netmon.h>
|
||||
#include <ofono/lte.h>
|
||||
#include <ofono/ims.h>
|
||||
|
||||
void __ofono_set_config_dir(const char *dir);
|
||||
void config_merge_files(GKeyFile *conf, const char *file);
|
||||
|
||||
@@ -139,8 +139,17 @@ static void sim_auth_unregister(struct ofono_atom *atom)
|
||||
struct ofono_sim_auth *sa = __ofono_atom_get_data(atom);
|
||||
|
||||
free_apps(sa);
|
||||
g_free(sa->nai);
|
||||
|
||||
g_free(sa->pending);
|
||||
if (sa->pending) {
|
||||
__ofono_dbus_pending_reply(&sa->pending->msg,
|
||||
__ofono_error_sim_not_ready(sa->pending->msg));
|
||||
|
||||
__ofono_sim_remove_session_watch(sa->pending->session,
|
||||
sa->pending->watch_id);
|
||||
g_free(sa->pending);
|
||||
sa->pending = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void sim_auth_remove(struct ofono_atom *atom)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -725,6 +727,12 @@ static DBusMessage *stk_register_agent(DBusConnection *conn,
|
||||
if (!dbus_validate_path(agent_path, NULL))
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
if (!__ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
|
||||
OFONO_DBUS_ACCESS_INTF_STK,
|
||||
OFONO_DBUS_ACCESS_STK_REGISTER_AGENT,
|
||||
agent_path))
|
||||
return __ofono_error_access_denied(msg);
|
||||
|
||||
stk->default_agent = stk_agent_new(agent_path,
|
||||
dbus_message_get_sender(msg),
|
||||
FALSE);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -36,10 +37,19 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include "storage.h"
|
||||
#include "ofono.h"
|
||||
|
||||
static char* config_dir = NULL;
|
||||
|
||||
void __ofono_set_config_dir(const char *dir)
|
||||
{
|
||||
g_free(config_dir);
|
||||
config_dir = g_strdup(dir);
|
||||
}
|
||||
|
||||
const char *ofono_config_dir(void)
|
||||
{
|
||||
return CONFIGDIR;
|
||||
return config_dir ? config_dir : CONFIGDIR;
|
||||
}
|
||||
|
||||
const char *ofono_storage_dir(void)
|
||||
|
||||
@@ -1798,7 +1798,7 @@ static DBusMessage *manager_dial(DBusConnection *conn,
|
||||
return __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
static void manager_dial_last_callback(const struct ofono_error *error,
|
||||
static void manager_dial_hfp_callback(const struct ofono_error *error,
|
||||
void *data)
|
||||
{
|
||||
struct ofono_voicecall *vc = data;
|
||||
@@ -1827,8 +1827,8 @@ error:
|
||||
__ofono_error_failed(vc->pending));
|
||||
}
|
||||
|
||||
static int voicecall_dial_last(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
static int voicecall_dial_hfp(struct ofono_voicecall *vc, unsigned int position,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom);
|
||||
|
||||
@@ -1838,9 +1838,6 @@ static int voicecall_dial_last(struct ofono_voicecall *vc,
|
||||
if (ofono_modem_get_online(modem) == FALSE)
|
||||
return -ENETDOWN;
|
||||
|
||||
if (vc->driver->dial_last == NULL)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (voicecalls_have_incoming(vc))
|
||||
return -EBUSY;
|
||||
|
||||
@@ -1851,7 +1848,18 @@ static int voicecall_dial_last(struct ofono_voicecall *vc,
|
||||
if (voicecalls_have_active(vc) && voicecalls_have_held(vc))
|
||||
return -EBUSY;
|
||||
|
||||
vc->driver->dial_last(vc, cb, vc);
|
||||
/* when position is not given we dial the last called number */
|
||||
if (position == 0) {
|
||||
if (vc->driver->dial_last == NULL)
|
||||
return -ENOTSUP;
|
||||
|
||||
vc->driver->dial_last(vc, cb, vc);
|
||||
} else {
|
||||
if (vc->driver->dial_memory == NULL )
|
||||
return -ENOTSUP;
|
||||
|
||||
vc->driver->dial_memory(vc, position, cb, vc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1867,7 +1875,7 @@ static DBusMessage *manager_dial_last(DBusConnection *conn,
|
||||
|
||||
vc->pending = dbus_message_ref(msg);
|
||||
|
||||
err = voicecall_dial_last(vc, manager_dial_last_callback, vc);
|
||||
err = voicecall_dial_hfp(vc, 0, manager_dial_hfp_callback, vc);
|
||||
|
||||
if (err >= 0)
|
||||
return NULL;
|
||||
@@ -1889,6 +1897,44 @@ static DBusMessage *manager_dial_last(DBusConnection *conn,
|
||||
return __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
static DBusMessage *manager_dial_memory(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ofono_voicecall *vc = data;
|
||||
int memory_location;
|
||||
int err;
|
||||
|
||||
if (vc->pending || vc->dial_req || vc->pending_em)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &memory_location,
|
||||
DBUS_TYPE_INVALID) == FALSE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
vc->pending = dbus_message_ref(msg);
|
||||
|
||||
err = voicecall_dial_hfp(vc, memory_location,
|
||||
manager_dial_hfp_callback, vc);
|
||||
if (err >= 0)
|
||||
return NULL;
|
||||
|
||||
vc->pending = NULL;
|
||||
dbus_message_unref(msg);
|
||||
|
||||
switch (err) {
|
||||
case -EINVAL:
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
case -ENETDOWN:
|
||||
return __ofono_error_not_available(msg);
|
||||
|
||||
case -ENOTSUP:
|
||||
return __ofono_error_not_implemented(msg);
|
||||
}
|
||||
|
||||
return __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
static DBusMessage *manager_transfer(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
@@ -2552,6 +2598,9 @@ static const GDBusMethodTable manager_methods[] = {
|
||||
GDBUS_ARGS({ "path", "o" }),
|
||||
manager_dial) },
|
||||
{ GDBUS_ASYNC_METHOD("DialLast", NULL, NULL, manager_dial_last)},
|
||||
{ GDBUS_ASYNC_METHOD("DialMemory",
|
||||
GDBUS_ARGS({"memory_location", "u" }), NULL,
|
||||
manager_dial_memory) },
|
||||
{ GDBUS_ASYNC_METHOD("Transfer", NULL, NULL, manager_transfer) },
|
||||
{ GDBUS_ASYNC_METHOD("SwapCalls", NULL, NULL, manager_swap_calls) },
|
||||
{ GDBUS_ASYNC_METHOD("ReleaseAndAnswer", NULL, NULL,
|
||||
|
||||
@@ -20,9 +20,11 @@ TESTS="\
|
||||
test-dbus-access \
|
||||
test-gprs-filter \
|
||||
test-provision \
|
||||
test-config \
|
||||
test-watch \
|
||||
test-ril_util \
|
||||
test-ril_config \
|
||||
test-ril_ecclist \
|
||||
test-ril-transport \
|
||||
test-ril_vendor \
|
||||
test-sms-filter \
|
||||
|
||||
448
ofono/unit/test-config.c
Normal file
448
ofono/unit/test-config.c
Normal file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include "ofono.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_ints.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define TMP_DIR_TEMPLATE "test-config-XXXXXX"
|
||||
|
||||
static gboolean test_keyfile_empty(GKeyFile *k)
|
||||
{
|
||||
gsize n = 0;
|
||||
char **groups = g_key_file_get_groups(k, &n);
|
||||
|
||||
g_strfreev(groups);
|
||||
return !n;
|
||||
}
|
||||
|
||||
static void test_merge_ignore(const char *filename, const char *contents,
|
||||
const char *dirname, const char *filename1, const char *contents1)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/", filename, NULL);
|
||||
char *subdir = g_strconcat(dir, "/", dirname, NULL);
|
||||
char *file1 = g_strconcat(subdir, "/", filename1, NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
static void test_merge1(const char *conf, const char *conf1, const char *out)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file1 = g_strconcat(subdir, "/bar.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, conf, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, conf1, -1, NULL));
|
||||
|
||||
DBG("reading %s", file);
|
||||
g_key_file_set_list_separator(k, ',');
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, out));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_basic ==== */
|
||||
|
||||
static void test_merge_basic(void)
|
||||
{
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *nonexistent = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
|
||||
config_merge_files(NULL, NULL);
|
||||
|
||||
remove(nonexistent);
|
||||
config_merge_files(k, nonexistent);
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
config_merge_files(k, NULL);
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
config_merge_files(k, "");
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
g_key_file_unref(k);
|
||||
g_free(nonexistent);
|
||||
}
|
||||
|
||||
/* ==== merge_simple ==== */
|
||||
|
||||
static void test_merge_simple(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
char *data;
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== merge_empty_dir ==== */
|
||||
|
||||
static void test_merge_empty_dir(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_ignore ==== */
|
||||
|
||||
static void test_merge_ignore0(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *subdir2 = g_strconcat(subdir, "/dir.conf", NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
/* Two empty subdirectories, one with matching name, one not */
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(!mkdir(subdir2, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(subdir2);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
g_free(subdir2);
|
||||
}
|
||||
|
||||
static void test_merge_ignore1(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\nb=3\n";
|
||||
|
||||
/* File has no suffix */
|
||||
test_merge_ignore("foo.conf", contents, "foo.d", "file", contents1);
|
||||
}
|
||||
|
||||
static void test_merge_ignore2(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[[[[[[[";
|
||||
|
||||
/* File is not a valid keyfile */
|
||||
test_merge_ignore("foo.conf", contents, "foo.d", "a.conf", contents1);
|
||||
}
|
||||
|
||||
/* ==== merge_sort ==== */
|
||||
|
||||
static void test_merge_sort(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\nb=3\n";
|
||||
static const char contents2 [] = "[foo]\nb=4\n";
|
||||
static const char result [] = "[foo]\na=1\nb=4\n";
|
||||
|
||||
/* Test file sort order */
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.", NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file1 = g_strconcat(subdir, "/1.conf", NULL);
|
||||
char *file2 = g_strconcat(subdir, "/2.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
|
||||
g_assert(g_file_set_contents(file2, contents2, -1, NULL));
|
||||
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, result));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(file2);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(file2);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_remove_group ==== */
|
||||
|
||||
static void test_merge_remove_group(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\n\n[bar]\nb=1\n";
|
||||
static const char contents1 [] = "[!bar]\n";
|
||||
static const char result [] = "[foo]\na=1\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_remove_key ==== */
|
||||
|
||||
static void test_merge_remove_key(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\n!b=\n\n!=\n";
|
||||
static const char result [] = "[foo]\na=1\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_default_value ==== */
|
||||
|
||||
static void test_merge_default_value(void)
|
||||
{
|
||||
/* b is assigned the default value, a stays as is */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[foo]\na:=2\nb:=3\n";
|
||||
static const char result [] = "[foo]\na=1\nb=3\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_list_add ==== */
|
||||
|
||||
static void test_merge_list_add0(void)
|
||||
{
|
||||
/* Adding empty list */
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na+=\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_add1(void)
|
||||
{
|
||||
/* a=1 turns into a=1,2, */
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na+=2,\n";
|
||||
static const char result [] = "[foo]\na=1,2,\nb=2\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add2(void)
|
||||
{
|
||||
/* 2 is already there */
|
||||
static const char contents [] = "[foo]\na=1,2,\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na?=2\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_add3(void)
|
||||
{
|
||||
/* 2 is already there, 3 is not */
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na?=2,3,\n";
|
||||
static const char result [] = "[foo]\na=1,2,3,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add4(void)
|
||||
{
|
||||
/* b=2,3, is created */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[foo]\nb?=2,3,\n";
|
||||
static const char result [] = "[foo]\na=1\nb=2,3,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add5(void)
|
||||
{
|
||||
/* Add a new group */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[bar]\nb=2\n";
|
||||
static const char result [] = "[foo]\na=1\n\n[bar]\nb=2\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_list_remove ==== */
|
||||
|
||||
static void test_merge_list_remove0(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove1(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=2,\n";
|
||||
static const char result [] = "[foo]\na=1,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove2(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=3\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove3(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\nb-=1\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
#define TEST_(name) "/config/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
__ofono_log_init("test-config",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("merge_basic"), test_merge_basic);
|
||||
g_test_add_func(TEST_("merge_simple"), test_merge_simple);
|
||||
g_test_add_func(TEST_("merge_empty_dir"), test_merge_empty_dir);
|
||||
g_test_add_func(TEST_("merge_ignore0"), test_merge_ignore0);
|
||||
g_test_add_func(TEST_("merge_ignore1"), test_merge_ignore1);
|
||||
g_test_add_func(TEST_("merge_ignore2"), test_merge_ignore2);
|
||||
g_test_add_func(TEST_("merge_sort"), test_merge_sort);
|
||||
g_test_add_func(TEST_("merge_remove_group"), test_merge_remove_group);
|
||||
g_test_add_func(TEST_("merge_remove_key"), test_merge_remove_key);
|
||||
g_test_add_func(TEST_("merge_default_value"), test_merge_default_value);
|
||||
g_test_add_func(TEST_("merge_list_add0"), test_merge_list_add0);
|
||||
g_test_add_func(TEST_("merge_list_add1"), test_merge_list_add1);
|
||||
g_test_add_func(TEST_("merge_list_add2"), test_merge_list_add2);
|
||||
g_test_add_func(TEST_("merge_list_add3"), test_merge_list_add3);
|
||||
g_test_add_func(TEST_("merge_list_add4"), test_merge_list_add4);
|
||||
g_test_add_func(TEST_("merge_list_add5"), test_merge_list_add5);
|
||||
g_test_add_func(TEST_("merge_list_remove0"), test_merge_list_remove0);
|
||||
g_test_add_func(TEST_("merge_list_remove1"), test_merge_list_remove1);
|
||||
g_test_add_func(TEST_("merge_list_remove2"), test_merge_list_remove2);
|
||||
g_test_add_func(TEST_("merge_list_remove3"), test_merge_list_remove3);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -103,6 +104,9 @@ static const struct test_method_name_data method_name_tests[] = {
|
||||
},{
|
||||
OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS,
|
||||
OFONO_DBUS_ACCESS_RADIOSETTINGS_METHOD_COUNT
|
||||
},{
|
||||
OFONO_DBUS_ACCESS_INTF_STK,
|
||||
OFONO_DBUS_ACCESS_STK_METHOD_COUNT
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -47,80 +48,6 @@ static void test_get_value(const char *conf, void (*test)(GKeyFile *k))
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
static gboolean test_keyfile_empty(GKeyFile *k)
|
||||
{
|
||||
gsize n = 0;
|
||||
char **groups = g_key_file_get_groups(k, &n);
|
||||
|
||||
g_strfreev(groups);
|
||||
return !n;
|
||||
}
|
||||
|
||||
static void test_merge_ignore(const char *filename, const char *contents,
|
||||
const char *dirname, const char *filename1, const char *contents1)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/", filename, NULL);
|
||||
char *subdir = g_strconcat(dir, "/", dirname, NULL);
|
||||
char *file1 = g_strconcat(subdir, "/", filename1, NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
static void test_merge1(const char *conf, const char *conf1, const char *out)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file1 = g_strconcat(subdir, "/bar.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, conf, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, conf1, -1, NULL));
|
||||
|
||||
DBG("reading %s", file);
|
||||
g_key_file_set_list_separator(k, ',');
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, out));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== get_string ==== */
|
||||
|
||||
static void test_get_string0_cb(GKeyFile *k)
|
||||
@@ -500,311 +427,6 @@ static void test_ints_to_string(void)
|
||||
g_assert(!ril_config_ints_to_string(NULL, 0));
|
||||
}
|
||||
|
||||
/* ==== merge_basic ==== */
|
||||
|
||||
static void test_merge_basic(void)
|
||||
{
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *nonexistent = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
|
||||
ril_config_merge_files(NULL, NULL);
|
||||
|
||||
remove(nonexistent);
|
||||
ril_config_merge_files(k, nonexistent);
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
ril_config_merge_files(k, NULL);
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
ril_config_merge_files(k, "");
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
g_key_file_unref(k);
|
||||
g_free(nonexistent);
|
||||
}
|
||||
|
||||
/* ==== merge_simple ==== */
|
||||
|
||||
static void test_merge_simple(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
char *data;
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== merge_empty_dir ==== */
|
||||
|
||||
static void test_merge_empty_dir(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_ignore ==== */
|
||||
|
||||
static void test_merge_ignore0(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *subdir2 = g_strconcat(subdir, "/dir.conf", NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
/* Two empty subdirectories, one with matching name, one not */
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(!mkdir(subdir2, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(subdir2);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
g_free(subdir2);
|
||||
}
|
||||
|
||||
static void test_merge_ignore1(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\nb=3\n";
|
||||
|
||||
/* File has no suffix */
|
||||
test_merge_ignore("foo.conf", contents, "foo.d", "file", contents1);
|
||||
}
|
||||
|
||||
static void test_merge_ignore2(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[[[[[[[";
|
||||
|
||||
/* File is not a valid keyfile */
|
||||
test_merge_ignore("foo.conf", contents, "foo.d", "a.conf", contents1);
|
||||
}
|
||||
|
||||
/* ==== merge_sort ==== */
|
||||
|
||||
static void test_merge_sort(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\nb=3\n";
|
||||
static const char contents2 [] = "[foo]\nb=4\n";
|
||||
static const char result [] = "[foo]\na=1\nb=4\n";
|
||||
|
||||
/* Test file sort order */
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.", NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file1 = g_strconcat(subdir, "/1.conf", NULL);
|
||||
char *file2 = g_strconcat(subdir, "/2.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
|
||||
g_assert(g_file_set_contents(file2, contents2, -1, NULL));
|
||||
|
||||
DBG("reading %s", file);
|
||||
ril_config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, result));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(file2);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(file2);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_remove_group ==== */
|
||||
|
||||
static void test_merge_remove_group(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\n\n[bar]\nb=1\n";
|
||||
static const char contents1 [] = "[!bar]\n";
|
||||
static const char result [] = "[foo]\na=1\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_remove_key ==== */
|
||||
|
||||
static void test_merge_remove_key(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\n!b=\n\n!=\n";
|
||||
static const char result [] = "[foo]\na=1\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_default_value ==== */
|
||||
|
||||
static void test_merge_default_value(void)
|
||||
{
|
||||
/* b is assigned the default value, a stays as is */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[foo]\na:=2\nb:=3\n";
|
||||
static const char result [] = "[foo]\na=1\nb=3\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_list_add ==== */
|
||||
|
||||
static void test_merge_list_add0(void)
|
||||
{
|
||||
/* Adding empty list */
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na+=\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_add1(void)
|
||||
{
|
||||
/* a=1 turns into a=1,2, */
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na+=2,\n";
|
||||
static const char result [] = "[foo]\na=1,2,\nb=2\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add2(void)
|
||||
{
|
||||
/* 2 is already there */
|
||||
static const char contents [] = "[foo]\na=1,2,\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na?=2\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_add3(void)
|
||||
{
|
||||
/* 2 is already there, 3 is not */
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na?=2,3,\n";
|
||||
static const char result [] = "[foo]\na=1,2,3,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add4(void)
|
||||
{
|
||||
/* b=2,3, is created */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[foo]\nb?=2,3,\n";
|
||||
static const char result [] = "[foo]\na=1\nb=2,3,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add5(void)
|
||||
{
|
||||
/* Add a new group */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[bar]\nb=2\n";
|
||||
static const char result [] = "[foo]\na=1\n\n[bar]\nb=2\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_list_remove ==== */
|
||||
|
||||
static void test_merge_list_remove0(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove1(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=2,\n";
|
||||
static const char result [] = "[foo]\na=1,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove2(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=3\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove3(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\nb-=1\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
#define TEST_(name) "/ril_config/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -831,26 +453,6 @@ int main(int argc, char *argv[])
|
||||
g_test_add_func(TEST_("get_enum"), test_get_enum);
|
||||
g_test_add_func(TEST_("get_ints"), test_get_ints);
|
||||
g_test_add_func(TEST_("ints_to_string"), test_ints_to_string);
|
||||
g_test_add_func(TEST_("merge_basic"), test_merge_basic);
|
||||
g_test_add_func(TEST_("merge_simple"), test_merge_simple);
|
||||
g_test_add_func(TEST_("merge_empty_dir"), test_merge_empty_dir);
|
||||
g_test_add_func(TEST_("merge_ignore0"), test_merge_ignore0);
|
||||
g_test_add_func(TEST_("merge_ignore1"), test_merge_ignore1);
|
||||
g_test_add_func(TEST_("merge_ignore2"), test_merge_ignore2);
|
||||
g_test_add_func(TEST_("merge_sort"), test_merge_sort);
|
||||
g_test_add_func(TEST_("merge_remove_group"), test_merge_remove_group);
|
||||
g_test_add_func(TEST_("merge_remove_key"), test_merge_remove_key);
|
||||
g_test_add_func(TEST_("merge_default_value"), test_merge_default_value);
|
||||
g_test_add_func(TEST_("merge_list_add0"), test_merge_list_add0);
|
||||
g_test_add_func(TEST_("merge_list_add1"), test_merge_list_add1);
|
||||
g_test_add_func(TEST_("merge_list_add2"), test_merge_list_add2);
|
||||
g_test_add_func(TEST_("merge_list_add3"), test_merge_list_add3);
|
||||
g_test_add_func(TEST_("merge_list_add4"), test_merge_list_add4);
|
||||
g_test_add_func(TEST_("merge_list_add5"), test_merge_list_add5);
|
||||
g_test_add_func(TEST_("merge_list_remove0"), test_merge_list_remove0);
|
||||
g_test_add_func(TEST_("merge_list_remove1"), test_merge_list_remove1);
|
||||
g_test_add_func(TEST_("merge_list_remove2"), test_merge_list_remove2);
|
||||
g_test_add_func(TEST_("merge_list_remove3"), test_merge_list_remove3);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
326
ofono/unit/test-ril_ecclist.c
Normal file
326
ofono/unit/test-ril_ecclist.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "drivers/ril/ril_ecclist.h"
|
||||
#include "drivers/ril/ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define TMP_DIR_TEMPLATE "test-ril_ecclist-XXXXXX"
|
||||
#define TEST_TIMEOUT_SEC (20)
|
||||
|
||||
GLOG_MODULE_DEFINE("rilmodem");
|
||||
|
||||
static gboolean test_debug = FALSE;
|
||||
|
||||
struct ril_ecclist_parse_test {
|
||||
const char* name;
|
||||
const char* in;
|
||||
const char* const* out;
|
||||
};
|
||||
|
||||
static gboolean test_timeout_cb(gpointer user_data)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean test_idle_quit_cb(gpointer loop)
|
||||
{
|
||||
g_main_loop_quit(loop);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void test_quit_cb(struct ril_ecclist *ecc, gpointer loop)
|
||||
{
|
||||
g_idle_add(test_idle_quit_cb, loop);
|
||||
}
|
||||
|
||||
static void test_inc_cb(struct ril_ecclist *ecc, gpointer ptr)
|
||||
{
|
||||
(*(int*)ptr)++;
|
||||
}
|
||||
|
||||
/* ==== parse ==== */
|
||||
|
||||
static void test_parse(gconstpointer data)
|
||||
{
|
||||
const struct ril_ecclist_parse_test *test = data;
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
struct ril_ecclist *ecc;
|
||||
|
||||
GDEBUG("Created file %s", file);
|
||||
g_assert(g_file_set_contents(file, test->in, -1, NULL));
|
||||
ecc = ril_ecclist_new(file);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)test->out));
|
||||
|
||||
ril_ecclist_unref(ecc);
|
||||
remove(file);
|
||||
remove(dir);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
static const char* null_str = NULL;
|
||||
static const char single_str_in[] = "911";
|
||||
static const char* single_str_out[] = { "911", NULL };
|
||||
static const char double_str_in[] = "911,112";
|
||||
static const char double2_str_in[] = "911, 112,";
|
||||
static const char double3_str_in[] = "911, 911, 112 ";
|
||||
static const char* double_str_out[] = { "112", "911", NULL };
|
||||
static const char mtk_str_in[] = "112,31;911,31;112,-1;911,-1";
|
||||
static const char mtk2_str_in[] = "112,31; 911,31; 112; 911 ";
|
||||
|
||||
static const struct ril_ecclist_parse_test tests[] = {
|
||||
{ "empty", "", &null_str },
|
||||
{ "single", single_str_in, single_str_out },
|
||||
{ "double", double_str_in, double_str_out },
|
||||
{ "double2", double2_str_in, double_str_out },
|
||||
{ "double3", double3_str_in, double_str_out },
|
||||
{ "mtk", mtk_str_in, double_str_out },
|
||||
{ "mtk2", mtk2_str_in, double_str_out }
|
||||
};
|
||||
|
||||
/* ==== file_perm ==== */
|
||||
|
||||
static void test_file_perm()
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
int count = 0;
|
||||
struct ril_ecclist *ecc;
|
||||
gulong id[2];
|
||||
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
guint test_timeout_id = test_debug ? 0 :
|
||||
g_timeout_add_seconds(TEST_TIMEOUT_SEC, test_timeout_cb, NULL);
|
||||
|
||||
GDEBUG("Created file %s", file);
|
||||
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
|
||||
ecc = ril_ecclist_new(file);
|
||||
id[0] = ril_ecclist_add_list_changed_handler(ecc, test_inc_cb, &count);
|
||||
id[1] = ril_ecclist_add_list_changed_handler(ecc, test_quit_cb, loop);
|
||||
|
||||
g_assert(id[0]);
|
||||
g_assert(id[1]);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)single_str_out));
|
||||
|
||||
/* Modify the file */
|
||||
g_assert(g_file_set_contents(file, double_str_in, -1, NULL));
|
||||
|
||||
/* ril_ecclist needs event loop to process filesystem change events */
|
||||
g_main_loop_run(loop);
|
||||
|
||||
g_assert(count == 1);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)double_str_out));
|
||||
|
||||
/* Making file unreadable resets the ecc list */
|
||||
GDEBUG("Making file %s unreadable", file);
|
||||
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
|
||||
g_assert(chmod(file, 0) == 0);
|
||||
count = 0;
|
||||
g_main_loop_run(loop);
|
||||
g_assert(count == 1);
|
||||
g_assert(!ecc->list);
|
||||
|
||||
if (test_timeout_id) {
|
||||
g_source_remove(test_timeout_id);
|
||||
}
|
||||
g_main_loop_unref(loop);
|
||||
ril_ecclist_remove_handler(ecc, id[0]);
|
||||
ril_ecclist_remove_handler(ecc, id[1]);
|
||||
ril_ecclist_unref(ecc);
|
||||
remove(dir);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== file_change ==== */
|
||||
|
||||
static void test_file_change()
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
int count = 0;
|
||||
struct ril_ecclist *ecc;
|
||||
gulong id[2];
|
||||
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
guint test_timeout_id = test_debug ? 0 :
|
||||
g_timeout_add_seconds(TEST_TIMEOUT_SEC, test_timeout_cb, NULL);
|
||||
|
||||
GDEBUG("Created file %s", file);
|
||||
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
|
||||
ecc = ril_ecclist_new(file);
|
||||
id[0] = ril_ecclist_add_list_changed_handler(ecc, test_inc_cb, &count);
|
||||
id[1] = ril_ecclist_add_list_changed_handler(ecc, test_quit_cb, loop);
|
||||
|
||||
g_assert(id[0]);
|
||||
g_assert(id[1]);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)single_str_out));
|
||||
|
||||
/* Modify the file */
|
||||
g_assert(g_file_set_contents(file, double_str_in, -1, NULL));
|
||||
|
||||
/* ril_ecclist needs event loop to process filesystem change events */
|
||||
g_main_loop_run(loop);
|
||||
|
||||
g_assert(count == 1);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)double_str_out));
|
||||
|
||||
/* Removing the file resets the ecc list */
|
||||
GDEBUG("Removing file %s", file);
|
||||
g_assert(remove(file) == 0);
|
||||
count = 0;
|
||||
g_main_loop_run(loop);
|
||||
g_assert(count == 1);
|
||||
g_assert(!ecc->list);
|
||||
|
||||
if (test_timeout_id) {
|
||||
g_source_remove(test_timeout_id);
|
||||
}
|
||||
g_main_loop_unref(loop);
|
||||
ril_ecclist_remove_handler(ecc, id[0]);
|
||||
ril_ecclist_remove_handler(ecc, id[1]);
|
||||
ril_ecclist_unref(ecc);
|
||||
remove(dir);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== dir_change ==== */
|
||||
|
||||
static void test_dir_change()
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
int count = 0;
|
||||
struct ril_ecclist *ecc;
|
||||
gulong id[3];
|
||||
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
|
||||
guint test_timeout_id = test_debug ? 0 :
|
||||
g_timeout_add_seconds(TEST_TIMEOUT_SEC, test_timeout_cb, NULL);
|
||||
|
||||
GDEBUG("Created directory %s", dir);
|
||||
ecc = ril_ecclist_new(file);
|
||||
id[0] = ril_ecclist_add_list_changed_handler(ecc, test_inc_cb, &count);
|
||||
id[1] = ril_ecclist_add_list_changed_handler(ecc, test_quit_cb, loop);
|
||||
|
||||
g_assert(id[0]);
|
||||
g_assert(id[1]);
|
||||
g_assert(!ecc->list);
|
||||
GDEBUG("Created file %s", file);
|
||||
g_assert(g_file_set_contents(file, single_str_in, -1, NULL));
|
||||
|
||||
/* ril_ecclist needs event loop to process filesystem change events */
|
||||
g_main_loop_run(loop);
|
||||
|
||||
g_assert(count == 1);
|
||||
g_assert(gutil_strv_equal(ecc->list, (char**)single_str_out));
|
||||
|
||||
/* Removing the directory resets the ecc list */
|
||||
GDEBUG("Removing directory %s", dir);
|
||||
g_assert(remove(file) == 0);
|
||||
g_assert(remove(dir) == 0);
|
||||
count = 0;
|
||||
g_main_loop_run(loop);
|
||||
g_assert(count == 1);
|
||||
g_assert(!ecc->list);
|
||||
|
||||
if (test_timeout_id) {
|
||||
g_source_remove(test_timeout_id);
|
||||
}
|
||||
g_main_loop_unref(loop);
|
||||
ril_ecclist_remove_handler(ecc, id[0]);
|
||||
ril_ecclist_remove_handler(ecc, id[1]);
|
||||
ril_ecclist_unref(ecc);
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== null ==== */
|
||||
|
||||
static void test_null(void)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_build_filename(dir, "ecclist", NULL);
|
||||
struct ril_ecclist *ecc;
|
||||
|
||||
/* Make sure neither directory nor file exist */
|
||||
remove(dir);
|
||||
ecc = ril_ecclist_new(file);
|
||||
g_assert(ecc);
|
||||
g_assert(!ecc->list);
|
||||
g_assert(!ril_ecclist_new(NULL));
|
||||
g_assert(!ril_ecclist_ref(NULL));
|
||||
g_assert(!ril_ecclist_add_list_changed_handler(NULL, NULL, NULL));
|
||||
g_assert(!ril_ecclist_add_list_changed_handler(ecc, NULL, NULL));
|
||||
ril_ecclist_unref(NULL);
|
||||
ril_ecclist_remove_handler(NULL, 0);
|
||||
ril_ecclist_remove_handler(ecc, 0);
|
||||
ril_ecclist_unref(ril_ecclist_ref(ecc));
|
||||
ril_ecclist_unref(ecc);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
#define TEST_(name) "/ril_ecclist/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_default.name = "test-ril_ecclist";
|
||||
gutil_log_default.level = g_test_verbose() ?
|
||||
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
|
||||
__ofono_log_init(gutil_log_default.name,
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
if (argc > 1 && !strcmp(argv[1] , "-d")) {
|
||||
test_debug = TRUE;
|
||||
GDEBUG("Debugging on (no timeout)");
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(tests); i++) {
|
||||
const struct ril_ecclist_parse_test* test = tests + i;
|
||||
char* path = g_strconcat(TEST_("parse/"), test->name, NULL);
|
||||
|
||||
g_test_add_data_func(path, test, test_parse);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("file_perm"), test_file_perm);
|
||||
g_test_add_func(TEST_("file_change"), test_file_change);
|
||||
g_test_add_func(TEST_("dir_change"), test_dir_change);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017-2019 Jolla Ltd.
|
||||
* Copyright (C) 2017-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -46,6 +47,7 @@
|
||||
#define TEST_SPN "Test"
|
||||
#define TEST_ERROR_KEY "Error"
|
||||
#define TEST_SLOT_ERROR_KEY "SlotError"
|
||||
#define TEST_CONFIG_DIR_TEMPLATE "test-saifish_manager-config-XXXXXX"
|
||||
|
||||
extern struct ofono_plugin_desc __ofono_builtin_sailfish_manager;
|
||||
static GMainLoop *test_loop = NULL;
|
||||
@@ -970,6 +972,128 @@ static void test_voice_sim(void)
|
||||
test_common_deinit();
|
||||
}
|
||||
|
||||
/* ==== auto_data_sim ==== */
|
||||
|
||||
static gboolean test_auto_data_sim_done(gpointer user_data)
|
||||
{
|
||||
test_slot_manager *sm = user_data;
|
||||
test_slot *s = sm->slot;
|
||||
struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
|
||||
struct ofono_watch *w = ofono_watch_new(TEST_PATH);
|
||||
struct ofono_watch *w2 = ofono_watch_new(TEST_PATH_1);
|
||||
struct ofono_modem modem;
|
||||
struct ofono_sim sim;
|
||||
struct ofono_sim sim2;
|
||||
|
||||
memset(&modem, 0, sizeof(modem));
|
||||
memset(&sim, 0, sizeof(sim));
|
||||
sim.mcc = TEST_MCC;
|
||||
sim.mnc = TEST_MNC;
|
||||
sim.state = OFONO_SIM_STATE_READY;
|
||||
sim2 = sim;
|
||||
|
||||
/* Assign IMSI to the SIMs */
|
||||
w->modem = &modem;
|
||||
fake_watch_signal_queue(w, FAKE_WATCH_SIGNAL_MODEM_CHANGED);
|
||||
fake_watch_set_ofono_sim(w, &sim);
|
||||
fake_watch_set_ofono_iccid(w, TEST_ICCID);
|
||||
fake_watch_set_ofono_imsi(w, TEST_IMSI);
|
||||
fake_watch_emit_queued_signals(w);
|
||||
|
||||
w2->modem = &modem;
|
||||
fake_watch_signal_queue(w2, FAKE_WATCH_SIGNAL_MODEM_CHANGED);
|
||||
fake_watch_set_ofono_sim(w2, &sim2);
|
||||
fake_watch_set_ofono_iccid(w2, TEST_ICCID_1);
|
||||
fake_watch_set_ofono_imsi(w2, TEST_IMSI_1);
|
||||
fake_watch_emit_queued_signals(w2);
|
||||
|
||||
/* No data SIM yet, only voice SIM is assigned */
|
||||
g_assert(s->data_role == SAILFISH_DATA_ROLE_NONE);
|
||||
g_assert(!m->default_voice_imsi);
|
||||
g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
|
||||
g_assert(!m->default_data_imsi);
|
||||
g_assert(!m->default_data_path);
|
||||
|
||||
/* Set the first modem online */
|
||||
w->online = TRUE;
|
||||
fake_watch_signal_queue(w, FAKE_WATCH_SIGNAL_ONLINE_CHANGED);
|
||||
fake_watch_emit_queued_signals(w);
|
||||
|
||||
/* Now data modem must point to the first slot */
|
||||
g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
|
||||
|
||||
ofono_watch_unref(w);
|
||||
ofono_watch_unref(w2);
|
||||
g_main_loop_quit(test_loop);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static guint test_auto_data_sim_start(test_slot_manager *sm)
|
||||
{
|
||||
struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
|
||||
test_slot *s = g_new0(test_slot, 1);
|
||||
test_slot *s2 = g_new0(test_slot, 1);
|
||||
|
||||
DBG("");
|
||||
|
||||
/* Create the slots */
|
||||
DBG("");
|
||||
s->handle = sailfish_manager_slot_add(sm->handle, s, TEST_PATH,
|
||||
OFONO_RADIO_ACCESS_MODE_GSM, NULL, TEST_IMEISV,
|
||||
SAILFISH_SIM_STATE_PRESENT);
|
||||
s2->handle = sailfish_manager_slot_add(sm->handle, s2, TEST_PATH_1,
|
||||
OFONO_RADIO_ACCESS_MODE_GSM, NULL, TEST_IMEISV,
|
||||
SAILFISH_SIM_STATE_PRESENT);
|
||||
sm->slot = s;
|
||||
sm->slot2 = s2;
|
||||
sailfish_slot_manager_started(sm->handle);
|
||||
|
||||
g_assert(!m->ready);
|
||||
sailfish_manager_imei_obtained(s->handle, TEST_IMEI);
|
||||
g_assert(!m->ready);
|
||||
sailfish_manager_imei_obtained(s2->handle, TEST_IMEI_1);
|
||||
g_assert(m->ready);
|
||||
|
||||
g_idle_add(test_auto_data_sim_done, sm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_auto_data_sim(gconstpointer option)
|
||||
{
|
||||
static const struct sailfish_slot_driver test_auto_data_sim_driver = {
|
||||
.name = "auto_data_sim",
|
||||
.manager_create = test_slot_manager_create,
|
||||
.manager_start = test_auto_data_sim_start,
|
||||
.manager_free = test_slot_manager_free,
|
||||
.slot_enabled_changed = test_slot_enabled_changed,
|
||||
.slot_free = test_slot_free
|
||||
};
|
||||
char *cfg_dir = g_dir_make_tmp(TEST_CONFIG_DIR_TEMPLATE, NULL);
|
||||
char *cfg_file = g_build_filename(cfg_dir, "main.conf", NULL);
|
||||
GKeyFile* cfg = g_key_file_new();
|
||||
struct sailfish_slot_driver_reg *reg;
|
||||
|
||||
g_key_file_set_string(cfg, "ModemManager", "AutoSelectDataSim", option);
|
||||
g_assert(g_key_file_save_to_file(cfg, cfg_file, NULL));
|
||||
g_key_file_unref(cfg);
|
||||
|
||||
__ofono_set_config_dir(cfg_dir);
|
||||
test_common_init();
|
||||
reg = sailfish_slot_driver_register(&test_auto_data_sim_driver);
|
||||
g_assert(reg);
|
||||
|
||||
g_main_loop_run(test_loop);
|
||||
|
||||
sailfish_slot_driver_unregister(reg);
|
||||
test_common_deinit();
|
||||
|
||||
__ofono_set_config_dir(NULL);
|
||||
remove(cfg_file);
|
||||
remove(cfg_dir);
|
||||
g_free(cfg_file);
|
||||
g_free(cfg_dir);
|
||||
}
|
||||
|
||||
/* ==== data_sim ==== */
|
||||
|
||||
static gboolean test_data_sim_done(gpointer user_data)
|
||||
@@ -1066,8 +1190,17 @@ static void test_data_sim(void)
|
||||
.slot_enabled_changed = test_slot_enabled_changed,
|
||||
.slot_free = test_slot_free
|
||||
};
|
||||
char *cfg_dir = g_dir_make_tmp(TEST_CONFIG_DIR_TEMPLATE, NULL);
|
||||
char *cfg_file = g_build_filename(cfg_dir, "main.conf", NULL);
|
||||
GKeyFile* cfg = g_key_file_new();
|
||||
struct sailfish_slot_driver_reg *reg;
|
||||
|
||||
/* Invalid AutoSelectDataSim option is treated as "off" */
|
||||
g_key_file_set_string(cfg, "ModemManager", "AutoSelectDataSim", "x");
|
||||
g_assert(g_key_file_save_to_file(cfg, cfg_file, NULL));
|
||||
g_key_file_unref(cfg);
|
||||
|
||||
__ofono_set_config_dir(cfg_dir);
|
||||
test_common_init();
|
||||
reg = sailfish_slot_driver_register(&test_data_sim_driver);
|
||||
g_assert(reg);
|
||||
@@ -1076,6 +1209,12 @@ static void test_data_sim(void)
|
||||
|
||||
sailfish_slot_driver_unregister(reg);
|
||||
test_common_deinit();
|
||||
|
||||
__ofono_set_config_dir(NULL);
|
||||
remove(cfg_file);
|
||||
remove(cfg_dir);
|
||||
g_free(cfg_file);
|
||||
g_free(cfg_dir);
|
||||
}
|
||||
|
||||
/* ==== mms_sim ==== */
|
||||
@@ -1511,6 +1650,12 @@ int main(int argc, char *argv[])
|
||||
g_test_add_func(TEST_("cancel_start"), test_cancel_start);
|
||||
g_test_add_func(TEST_("voice_sim"), test_voice_sim);
|
||||
g_test_add_func(TEST_("data_sim"), test_data_sim);
|
||||
g_test_add_data_func(TEST_("auto_data_sim_on"), "on",
|
||||
test_auto_data_sim);
|
||||
g_test_add_data_func(TEST_("auto_data_sim_always"), "always",
|
||||
test_auto_data_sim);
|
||||
g_test_add_data_func(TEST_("auto_data_sim_once"), "once",
|
||||
test_auto_data_sim);
|
||||
g_test_add_func(TEST_("mms_sim"), test_mms_sim);
|
||||
g_test_add_func(TEST_("multisim"), test_multisim);
|
||||
g_test_add_func(TEST_("storage"), test_storage);
|
||||
|
||||
@@ -500,8 +500,8 @@ static void test_application_entry_decode(void)
|
||||
g_assert(app[1]->label != NULL);
|
||||
g_assert(!strcmp(app[1]->label, "MIDPfiles"));
|
||||
|
||||
g_free(ef_dir);
|
||||
g_slist_free_full(entries, (GDestroyNotify) sim_app_record_free);
|
||||
g_free(ef_dir);
|
||||
}
|
||||
|
||||
static void test_get_3g_path(void)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Name: ofono
|
||||
Summary: Open Source Telephony
|
||||
Version: 1.22
|
||||
Version: 1.23
|
||||
Release: 1
|
||||
Group: Communications/Connectivity Adaptation
|
||||
License: GPLv2
|
||||
|
||||
2
upstream
2
upstream
Submodule upstream updated: 82f54044a8...8766cedac6
Reference in New Issue
Block a user