forked from sailfishos/ofono
Compare commits
27 Commits
mer/1.23+g
...
mer/1.23+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c0f5094a6 | ||
|
|
4208b6d9ea | ||
|
|
59e304d474 | ||
|
|
30a2424507 | ||
|
|
e4f3ec6322 | ||
|
|
95fd4efc37 | ||
|
|
ef5ee98508 | ||
|
|
4220e7d5e8 | ||
|
|
33c067a75f | ||
|
|
29616c04d0 | ||
|
|
beb997d914 | ||
|
|
cefc03e5ed | ||
|
|
85d99536ee | ||
|
|
ea36baa4c1 | ||
|
|
b95a089c00 | ||
|
|
c8dbf5494b | ||
|
|
cfb75f473d | ||
|
|
edd91c94eb | ||
|
|
af0ab142e1 | ||
|
|
dffc04d404 | ||
|
|
97b5fcbd87 | ||
|
|
d7e740347f | ||
|
|
1116ca2481 | ||
|
|
3d147843c4 | ||
|
|
c01dc63cbc | ||
|
|
297926ed24 | ||
|
|
6ef1174ea8 |
1
ofono/.gitignore
vendored
1
ofono/.gitignore
vendored
@@ -45,6 +45,7 @@ unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-dbus-access
|
||||
unit/test-dbus-clients
|
||||
unit/test-dbus-queue
|
||||
unit/test-gprs-filter
|
||||
unit/test-ril_config
|
||||
|
||||
@@ -26,7 +26,7 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
include/sms-filter.h include/gprs-filter.h \
|
||||
include/voicecall-filter.h include/dbus-access.h \
|
||||
include/ril-constants.h include/ril-transport.h \
|
||||
include/watch.h gdbus/gdbus.h \
|
||||
include/watch.h gdbus/gdbus.h include/dbus-clients.h \
|
||||
include/netmon.h include/lte.h include/ims.h \
|
||||
include/storage.h
|
||||
|
||||
@@ -775,7 +775,8 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
||||
src/handsfree-audio.c src/bluetooth.h \
|
||||
src/sim-mnclength.c src/voicecallagent.c \
|
||||
src/sms-filter.c src/gprs-filter.c \
|
||||
src/dbus-queue.c src/dbus-access.c src/config.c \
|
||||
src/dbus-clients.c src/dbus-queue.c \
|
||||
src/dbus-access.c src/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 \
|
||||
@@ -981,7 +982,7 @@ unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
|
||||
unit/fake_sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||
gdbus/object.c \
|
||||
gdbus/object.c src/dbus-clients.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
@DBUS_GLIB_CFLAGS@
|
||||
@@ -1164,6 +1165,14 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_caif_OBJECTS)
|
||||
|
||||
unit_test_dbus_clients_SOURCES = unit/test-dbus-clients.c unit/test-dbus.c \
|
||||
src/dbus-clients.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_dbus_clients_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_dbus_clients_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_clients_OBJECTS)
|
||||
unit_tests += unit/test-dbus-clients
|
||||
|
||||
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
|
||||
src/dbus-queue.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
|
||||
@@ -278,6 +278,13 @@ Properties boolean Active [readwrite]
|
||||
via this proxy. All other values are left
|
||||
out in this case.
|
||||
|
||||
array{string} ProxyCSCF [readonly, optional]
|
||||
|
||||
Holds the list of P-CSCF (SIP proxy) for this
|
||||
context. Only used by IMS connections.
|
||||
|
||||
This is a Sailfish OS specific extension.
|
||||
|
||||
dict IPv6.Settings [readonly, optional]
|
||||
|
||||
Holds all the IPv6 network settings
|
||||
@@ -304,6 +311,13 @@ Properties boolean Active [readwrite]
|
||||
|
||||
Holds the gateway IP for this connection.
|
||||
|
||||
array{string} ProxyCSCF [readonly, optional]
|
||||
|
||||
Holds the list of P-CSCF (SIP proxy) for this
|
||||
context. Only used by IMS connections.
|
||||
|
||||
This is a Sailfish OS specific extension.
|
||||
|
||||
string MessageProxy [readwrite, MMS only]
|
||||
|
||||
Holds the MMS Proxy setting.
|
||||
|
||||
@@ -47,6 +47,7 @@ struct ril_cell_info {
|
||||
gulong event_id;
|
||||
guint query_id;
|
||||
guint set_rate_id;
|
||||
gboolean enabled;
|
||||
};
|
||||
|
||||
enum ril_cell_info_signal {
|
||||
@@ -331,7 +332,8 @@ static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
DBG_(self, "");
|
||||
GASSERT(self->query_id);
|
||||
self->query_id = 0;
|
||||
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
|
||||
ril_cell_info_update_cells(self,
|
||||
(status == RIL_E_SUCCESS && self->enabled) ?
|
||||
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
|
||||
}
|
||||
|
||||
@@ -348,12 +350,14 @@ static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
static gboolean ril_cell_info_retry(GRilIoRequest* request, int ril_status,
|
||||
const void* response_data, guint response_len, void* user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
return self->enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +377,8 @@ static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1,
|
||||
(self->update_rate_ms >= 0) ? self->update_rate_ms : INT_MAX);
|
||||
(self->update_rate_ms >= 0 && self->enabled) ?
|
||||
self->update_rate_ms : INT_MAX);
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_request_set_retry_func(req, ril_cell_info_retry);
|
||||
@@ -387,7 +392,8 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self)
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
|
||||
if (self->enabled && self->radio->state == RADIO_STATE_ON &&
|
||||
self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
@@ -482,6 +488,21 @@ static void ril_cell_info_set_update_interval_proc
|
||||
if (self->update_rate_ms != ms) {
|
||||
self->update_rate_ms = ms;
|
||||
DBG_(self, "%d ms", ms);
|
||||
if (self->enabled && self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_set_enabled_proc(struct sailfish_cell_info *info,
|
||||
gboolean enabled)
|
||||
{
|
||||
struct ril_cell_info *self = ril_cell_info_cast(info);
|
||||
|
||||
if (self->enabled != enabled) {
|
||||
self->enabled = enabled;
|
||||
DBG_(self, "%d", enabled);
|
||||
ril_cell_info_refresh(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
@@ -497,7 +518,8 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
ril_cell_info_unref_proc,
|
||||
ril_cell_info_add_cells_changed_handler_proc,
|
||||
ril_cell_info_remove_handler_proc,
|
||||
ril_cell_info_set_update_interval_proc
|
||||
ril_cell_info_set_update_interval_proc,
|
||||
ril_cell_info_set_enabled_proc
|
||||
};
|
||||
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
@@ -519,6 +541,9 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
ril_cell_info_refresh(self);
|
||||
|
||||
/* Disable updates by default */
|
||||
self->enabled = FALSE;
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#define CTX_ID_NONE ((unsigned int)(-1))
|
||||
|
||||
#define MAX_MTU 1280
|
||||
#define MAX_MMS_MTU 1280
|
||||
|
||||
struct ril_gprs_context_call {
|
||||
struct ril_data_request *req;
|
||||
@@ -108,8 +108,15 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
if (call) {
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = ril_data_call_dup(call);
|
||||
if (!gcd->mtu_watch) {
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
|
||||
if (ofono_gprs_context_get_type(gcd->gc) ==
|
||||
OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
/*
|
||||
* Some MMS providers have a problem with MTU
|
||||
* greater than 1280. Let's be safe.
|
||||
*/
|
||||
if (!gcd->mtu_watch) {
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MMS_MTU);
|
||||
}
|
||||
}
|
||||
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
ril_data_call_grab(gcd->data, call->cid, gcd);
|
||||
@@ -247,34 +254,59 @@ static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
typedef void (*ofono_gprs_context_list_setter_t)(struct ofono_gprs_context *gc,
|
||||
const char **list);
|
||||
|
||||
static void ril_gprs_context_set_servers(struct ofono_gprs_context *gc,
|
||||
char * const *list, ofono_gprs_context_list_setter_t set_ipv4,
|
||||
ofono_gprs_context_list_setter_t set_ipv6)
|
||||
{
|
||||
int i;
|
||||
char * const *list = call->dnses;
|
||||
const char **ip_list = NULL, **ip_ptr = NULL;
|
||||
const char **ipv6_list = NULL, **ipv6_ptr = NULL;
|
||||
const int n = gutil_strv_length(list);
|
||||
const char **ip_dns = g_new0(const char *, n+1);
|
||||
const char **ipv6_dns = g_new0(const char *, n+1);
|
||||
const char **ip_ptr = ip_dns;
|
||||
const char **ipv6_ptr = ipv6_dns;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_ptr) {
|
||||
ip_list = g_new0(const char *, n - i + 1);
|
||||
ip_ptr = ip_list;
|
||||
}
|
||||
*ip_ptr++ = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_ptr) {
|
||||
ipv6_list = g_new0(const char *, n - i + 1);
|
||||
ipv6_ptr = ipv6_list;
|
||||
}
|
||||
*ipv6_ptr++ = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, ip_dns);
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc, ipv6_dns);
|
||||
set_ipv4(gc, ip_list);
|
||||
set_ipv6(gc, ipv6_list);
|
||||
|
||||
g_free(ip_dns);
|
||||
g_free(ipv6_dns);
|
||||
g_free(ip_list);
|
||||
g_free(ipv6_list);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
ril_gprs_context_set_servers(gc, call->dnses,
|
||||
ofono_gprs_context_set_ipv4_dns_servers,
|
||||
ofono_gprs_context_set_ipv6_dns_servers);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
ril_gprs_context_set_servers(gc, call->pcscf,
|
||||
ofono_gprs_context_set_ipv4_proxy_cscf,
|
||||
ofono_gprs_context_set_ipv6_proxy_cscf);
|
||||
}
|
||||
|
||||
/* Only compares the stuff that's important to us */
|
||||
@@ -282,7 +314,8 @@ static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
#define DATA_CALL_ADDRESS_CHANGED (0x02)
|
||||
#define DATA_CALL_GATEWAY_CHANGED (0x04)
|
||||
#define DATA_CALL_DNS_CHANGED (0x08)
|
||||
#define DATA_CALL_ALL_CHANGED (0x0f)
|
||||
#define DATA_CALL_PCSCF_CHANGED (0x10)
|
||||
#define DATA_CALL_ALL_CHANGED (0x1f)
|
||||
static int ril_gprs_context_data_call_change(
|
||||
const struct ril_data_call *c1,
|
||||
const struct ril_data_call *c2)
|
||||
@@ -308,6 +341,10 @@ static int ril_gprs_context_data_call_change(
|
||||
changes |= DATA_CALL_DNS_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->pcscf, c2->pcscf)) {
|
||||
changes |= DATA_CALL_PCSCF_CHANGED;
|
||||
}
|
||||
|
||||
return changes;
|
||||
} else {
|
||||
return DATA_CALL_ALL_CHANGED;
|
||||
@@ -380,6 +417,11 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_PCSCF_CHANGED) {
|
||||
DBG("P-CSCF changed");
|
||||
ril_gprs_context_set_proxy_cscf(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
|
||||
ril_data_call_free(prev_call);
|
||||
}
|
||||
@@ -421,6 +463,7 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
ril_gprs_context_set_proxy_cscf(gc, call);
|
||||
ril_error_init_ok(&error);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -340,6 +340,7 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
if (md->modem.config.enable_cbs) {
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
ofono_sim_auth_create(modem);
|
||||
}
|
||||
|
||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include "simutil.h"
|
||||
#include "util.h"
|
||||
#include "ofono.h"
|
||||
@@ -86,6 +88,7 @@ struct ril_sim {
|
||||
gboolean empty_pin_query_allowed;
|
||||
gboolean inserted;
|
||||
guint idle_id; /* Used by register and SIM reset callbacks */
|
||||
guint list_apps_id;
|
||||
gulong card_event_id[SIM_CARD_EVENT_COUNT];
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
guint query_pin_retries_id;
|
||||
@@ -118,12 +121,25 @@ struct ril_sim_cbd_io {
|
||||
ofono_sim_write_cb_t write;
|
||||
ofono_sim_imsi_cb_t imsi;
|
||||
ofono_query_facility_lock_cb_t query_facility_lock;
|
||||
ofono_sim_open_channel_cb_t open_channel;
|
||||
ofono_sim_close_channel_cb_t close_channel;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
guint req_id;
|
||||
};
|
||||
|
||||
struct ril_sim_session_cbd {
|
||||
struct ril_sim *sd;
|
||||
struct ril_sim_card *card;
|
||||
ofono_sim_logical_access_cb_t cb;
|
||||
gpointer data;
|
||||
int ref_count;
|
||||
int session_id;
|
||||
int cla;
|
||||
guint req_id;
|
||||
};
|
||||
|
||||
struct ril_sim_pin_cbd {
|
||||
struct ril_sim *sd;
|
||||
ofono_sim_lock_unlock_cb_t cb;
|
||||
@@ -150,6 +166,16 @@ struct ril_sim_retry_query {
|
||||
GRilIoRequest *(*new_req)(struct ril_sim *sd);
|
||||
};
|
||||
|
||||
/* TS 102.221 */
|
||||
#define APP_TEMPLATE_TAG 0x61
|
||||
#define APP_ID_TAG 0x4F
|
||||
|
||||
struct ril_sim_list_apps {
|
||||
struct ril_sim *sd;
|
||||
ofono_sim_list_apps_cb_t cb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static GRilIoRequest *ril_sim_empty_sim_pin_req(struct ril_sim *sd);
|
||||
static GRilIoRequest *ril_sim_empty_sim_puk_req(struct ril_sim *sd);
|
||||
static void ril_sim_query_retry_count_cb(GRilIoChannel *io, int status,
|
||||
@@ -218,6 +244,45 @@ static void ril_sim_cbd_io_start(struct ril_sim_cbd_io *cbd, GRilIoRequest* req,
|
||||
ril_sim_card_sim_io_started(cbd->card, cbd->req_id);
|
||||
}
|
||||
|
||||
static struct ril_sim_session_cbd *ril_sim_session_cbd_new(struct ril_sim *sd,
|
||||
int session_id, int cla, ofono_sim_logical_access_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim_session_cbd *cbd = g_new0(struct ril_sim_session_cbd, 1);
|
||||
|
||||
cbd->sd = sd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
cbd->card = ril_sim_card_ref(sd->card);
|
||||
cbd->session_id = session_id;
|
||||
cbd->cla = cla;
|
||||
cbd->ref_count = 1;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_sim_session_cbd_unref(void *data)
|
||||
{
|
||||
struct ril_sim_session_cbd *cbd = data;
|
||||
|
||||
if (--(cbd->ref_count) < 1) {
|
||||
ril_sim_card_sim_io_finished(cbd->card, cbd->req_id);
|
||||
ril_sim_card_unref(cbd->card);
|
||||
g_free(cbd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_session_cbd_start(struct ril_sim_session_cbd *cbd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc cb)
|
||||
{
|
||||
struct ril_sim *sd = cbd->sd;
|
||||
const guint finished_req = cbd->req_id;
|
||||
|
||||
cbd->ref_count++;
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req, code, cb,
|
||||
ril_sim_session_cbd_unref, cbd);
|
||||
ril_sim_card_sim_io_started(cbd->card, cbd->req_id);
|
||||
ril_sim_card_sim_io_finished(cbd->card, finished_req);
|
||||
}
|
||||
|
||||
static void ril_sim_pin_cbd_state_event_count_cb(struct ril_sim_card *sc,
|
||||
void *user_data)
|
||||
{
|
||||
@@ -307,30 +372,13 @@ static void ril_sim_append_path(struct ril_sim *sd, GRilIoRequest *req,
|
||||
grilio_request_append_utf8(req, hex_path);
|
||||
DBG_(sd, "%s", hex_path);
|
||||
g_free(hex_path);
|
||||
} else if (fileid == SIM_EF_ICCID_FILEID || fileid == SIM_EFPL_FILEID) {
|
||||
/*
|
||||
* Special catch-all for EF_ICCID (unique card ID)
|
||||
* and EF_PL files which exist in the root directory.
|
||||
* As the sim_info_cb function may not have yet
|
||||
* recorded the app_type for the SIM, and the path
|
||||
* for both files is the same for 2g|3g, just hard-code.
|
||||
*
|
||||
* See 'struct ef_db' in:
|
||||
* ../../src/simutil.c for more details.
|
||||
*/
|
||||
DBG_(sd, "%s", ROOTMF);
|
||||
grilio_request_append_utf8(req, ROOTMF);
|
||||
} else {
|
||||
/*
|
||||
* The only known case of this is EFPHASE_FILED (0x6FAE).
|
||||
* The ef_db table ( see /src/simutil.c ) entry for
|
||||
* EFPHASE contains a value of 0x0000 for it's
|
||||
* 'parent3g' member. This causes a NULL path to
|
||||
* be returned.
|
||||
* Catch-all for EF_ICCID, EF_PL and other files absent
|
||||
* from ef_db table in src/simutil.c, hard-code ROOTMF.
|
||||
*/
|
||||
|
||||
DBG_(sd, "returning empty path.");
|
||||
grilio_request_append_utf8(req, NULL);
|
||||
DBG_(sd, "%s (default)", ROOTMF);
|
||||
grilio_request_append_utf8(req, ROOTMF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1422,6 +1470,294 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_sim_list_apps_cb(void *data)
|
||||
{
|
||||
struct ril_sim_list_apps *rd = data;
|
||||
struct ril_sim *sd = rd->sd;
|
||||
const struct ril_sim_card_status *status = sd->card->status;
|
||||
struct ofono_error error;
|
||||
|
||||
GASSERT(sd->list_apps_id);
|
||||
sd->list_apps_id = 0;
|
||||
|
||||
if (status) {
|
||||
int i, n = status->num_apps;
|
||||
GByteArray *tlv = g_byte_array_sized_new(n * 20);
|
||||
|
||||
/* Reconstruct EFdir contents */
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *hex = status->apps[i].aid;
|
||||
gsize hex_len = hex ? strlen(hex) : 0;
|
||||
long aid_size;
|
||||
guint8 aid[16];
|
||||
|
||||
if (hex_len >= 2 && hex_len <= 2 * sizeof(aid) &&
|
||||
!(hex_len & 0x01) && decode_hex_own_buf(hex,
|
||||
hex_len, &aid_size, 0, aid)) {
|
||||
guint8 buf[4];
|
||||
|
||||
/*
|
||||
* TS 102.221
|
||||
* 13 Application independent files
|
||||
* 13.1 EFdir
|
||||
*
|
||||
* Application template TLV object.
|
||||
*/
|
||||
buf[0] = APP_TEMPLATE_TAG;
|
||||
buf[1] = (guint8)(aid_size + 2);
|
||||
buf[2] = APP_ID_TAG;
|
||||
buf[3] = (guint8)(aid_size);
|
||||
g_byte_array_append(tlv, buf, sizeof(buf));
|
||||
g_byte_array_append(tlv, aid, aid_size);
|
||||
}
|
||||
}
|
||||
DBG_(sd, "reporting %u apps %u bytes", n, tlv->len);
|
||||
rd->cb(ril_error_ok(&error), tlv->data, tlv->len, rd->data);
|
||||
g_byte_array_unref(tlv);
|
||||
} else {
|
||||
DBG_(sd, "no SIM card, no apps");
|
||||
rd->cb(ril_error_failure(&error), NULL, 0, rd->data);
|
||||
}
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_sim_list_apps(struct ofono_sim *sim,
|
||||
ofono_sim_list_apps_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
struct ril_sim_list_apps *rd = g_new(struct ril_sim_list_apps, 1);
|
||||
|
||||
rd->sd = sd;
|
||||
rd->cb = cb;
|
||||
rd->data = data;
|
||||
if (sd->list_apps_id) {
|
||||
g_source_remove(sd->list_apps_id);
|
||||
}
|
||||
sd->list_apps_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_sim_list_apps_cb, rd, g_free);
|
||||
}
|
||||
|
||||
static void ril_sim_open_channel_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_open_channel_cb_t cb = cbd->cb.open_channel;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
guint32 n, session_id;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_uint32(&rilp, &n) && n >= 1 &&
|
||||
grilio_parser_get_uint32(&rilp, &session_id)) {
|
||||
DBG_(cbd->sd, "%u", session_id);
|
||||
cb(ril_error_ok(&error), session_id, cbd->data);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ofono_error("Open logical channel failure: %s",
|
||||
ril_error_to_string(status));
|
||||
}
|
||||
|
||||
cb(ril_error_failure(&error), 0, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_sim_open_channel(struct ofono_sim *sim,
|
||||
const unsigned char *aid, unsigned int len,
|
||||
ofono_sim_open_channel_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
char *aid_hex = encode_hex(aid, len, 0);
|
||||
|
||||
DBG_(sd, "%s", aid_hex);
|
||||
grilio_request_append_utf8(req, aid_hex);
|
||||
grilio_request_append_int32(req, 0);
|
||||
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_OPEN_CHANNEL,
|
||||
ril_sim_open_channel_cb);
|
||||
grilio_request_unref(req);
|
||||
g_free(aid_hex);
|
||||
}
|
||||
|
||||
static void ril_sim_close_channel_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ofono_error("Close logical channel failure: %s",
|
||||
ril_error_to_string(status));
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
cbd->cb.close_channel(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_sim_close_channel(struct ofono_sim *sim, int session_id,
|
||||
ofono_sim_close_channel_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG_(sd, "%u", session_id);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, session_id);
|
||||
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_CLOSE_CHANNEL,
|
||||
ril_sim_close_channel_cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sim_logical_access_get_results_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_session_cbd *cbd = user_data;
|
||||
ofono_sim_logical_access_cb_t cb = cbd->cb;
|
||||
struct ril_sim_io_response *res;
|
||||
struct ofono_error err;
|
||||
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&err), res->data, res->data_len, cbd->data);
|
||||
} else if (res) {
|
||||
cb(ril_error_sim(&err, res->sw1, res->sw2), NULL, 0, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&err), NULL, 0, cbd->data);
|
||||
}
|
||||
ril_sim_io_response_free(res);
|
||||
}
|
||||
|
||||
static void ril_sim_logical_access_transmit(struct ril_sim_session_cbd *cbd,
|
||||
int ins, int p1, int p2, int p3, const char *hex_data,
|
||||
GRilIoChannelResponseFunc cb)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG_(cbd->sd, "session=%u,cmd=%02X,%02X,%02X,%02X,%02X,%s",
|
||||
cbd->session_id, cbd->cla, ins, p1, p2, p3,
|
||||
hex_data ? hex_data : "");
|
||||
grilio_request_append_int32(req, cbd->session_id);
|
||||
grilio_request_append_int32(req, cbd->cla);
|
||||
grilio_request_append_int32(req, ins);
|
||||
grilio_request_append_int32(req, p1);
|
||||
grilio_request_append_int32(req, p2);
|
||||
grilio_request_append_int32(req, p3);
|
||||
grilio_request_append_utf8(req, hex_data);
|
||||
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||
ril_sim_session_cbd_start(cbd, req,
|
||||
RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL, cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sim_logical_access_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_session_cbd *cbd = user_data;
|
||||
ofono_sim_logical_access_cb_t cb = cbd->cb;
|
||||
struct ril_sim_io_response *res;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(cbd->sd, "");
|
||||
cbd->req_id = 0;
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (res && status == RIL_E_SUCCESS) {
|
||||
/*
|
||||
* TS 102 221
|
||||
* 7.3.1.1.5.2 Case 4 commands
|
||||
*
|
||||
* If the UICC receives a case 4 command, after processing
|
||||
* the data sent with the C-APDU, it shall return:
|
||||
*
|
||||
* a) procedure bytes '61 xx' instructing the transport
|
||||
* layer of the terminal to issue a GET RESPONSE command
|
||||
* with a maximum length of 'xx'; or
|
||||
* b) status indicating a warning or error condition (but
|
||||
* not SW1 SW2 = '90 00').
|
||||
*
|
||||
* The GET RESPONSE command so issued is then treated as
|
||||
* described for case 2 commands.
|
||||
*/
|
||||
if (res->sw1 == 0x61) {
|
||||
ril_sim_logical_access_transmit(cbd,
|
||||
CMD_GET_RESPONSE, 0, 0, res->sw2, NULL,
|
||||
ril_sim_logical_access_get_results_cb);
|
||||
} else if (ril_sim_io_response_ok(res)) {
|
||||
cb(ril_error_ok(&error), res->data, res->data_len,
|
||||
cbd->data);
|
||||
} else {
|
||||
cb(ril_error_sim(&error, res->sw1, res->sw2), NULL, 0,
|
||||
cbd->data);
|
||||
}
|
||||
} else {
|
||||
cb(ril_error_failure(&error), NULL, 0, cbd->data);
|
||||
}
|
||||
ril_sim_io_response_free(res);
|
||||
}
|
||||
|
||||
static void ril_sim_logical_access(struct ofono_sim *sim, int session_id,
|
||||
const unsigned char *pdu, unsigned int len,
|
||||
ofono_sim_logical_access_cb_t cb, void *data)
|
||||
{
|
||||
/* SIM Command APDU: CLA INS P1 P2 P3 Data */
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char* hex_data;
|
||||
char *tmp;
|
||||
struct ril_sim_session_cbd *cbd = ril_sim_session_cbd_new(sd,
|
||||
session_id, pdu[0], cb, data);
|
||||
|
||||
GASSERT(len >= 5);
|
||||
if (len > 5) {
|
||||
hex_data = tmp = encode_hex(pdu + 5, len - 5, 0);
|
||||
} else {
|
||||
tmp = NULL;
|
||||
hex_data = "";
|
||||
}
|
||||
|
||||
ril_sim_logical_access_transmit(cbd, pdu[1], pdu[2], pdu[3], pdu[4],
|
||||
hex_data, ril_sim_logical_access_cb);
|
||||
ril_sim_session_cbd_unref(cbd);
|
||||
g_free(tmp);
|
||||
}
|
||||
|
||||
static void ril_sim_session_read_binary(struct ofono_sim *sim, int session,
|
||||
int fileid, int start, int length,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
|
||||
ofono_error("session_read_binary not implemented");
|
||||
cb(ril_error_failure(&error), NULL, 0, data);
|
||||
}
|
||||
|
||||
static void ril_sim_session_read_record(struct ofono_sim *sim, int session_id,
|
||||
int fileid, int record, int length,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
|
||||
ofono_error("session_read_record not implemented");
|
||||
cb(ril_error_failure(&error), NULL, 0, data);
|
||||
}
|
||||
|
||||
static void ril_sim_session_read_info(struct ofono_sim *sim, int session_id,
|
||||
int fileid, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_file_info_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
|
||||
ofono_error("session_read_info not implemented");
|
||||
cb(ril_error_failure(&error), -1, -1, -1, NULL, 0, data);
|
||||
}
|
||||
|
||||
static void ril_sim_refresh_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
@@ -1503,6 +1839,9 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
ofono_sim_set_data(sim, NULL);
|
||||
|
||||
if (sd->list_apps_id) {
|
||||
g_source_remove(sd->list_apps_id);
|
||||
}
|
||||
if (sd->idle_id) {
|
||||
g_source_remove(sd->idle_id);
|
||||
}
|
||||
@@ -1547,7 +1886,14 @@ const struct ofono_sim_driver ril_sim_driver = {
|
||||
.reset_passwd = ril_sim_pin_send_puk,
|
||||
.change_passwd = ril_sim_change_passwd,
|
||||
.query_pin_retries = ril_sim_query_pin_retries,
|
||||
.query_facility_lock = ril_sim_query_facility_lock
|
||||
.query_facility_lock = ril_sim_query_facility_lock,
|
||||
.list_apps = ril_sim_list_apps,
|
||||
.open_channel2 = ril_sim_open_channel,
|
||||
.close_channel = ril_sim_close_channel,
|
||||
.session_read_binary = ril_sim_session_read_binary,
|
||||
.session_read_record = ril_sim_session_read_record,
|
||||
.session_read_info = ril_sim_session_read_info,
|
||||
.logical_access = ril_sim_logical_access
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
55
ofono/include/dbus-clients.h
Normal file
55
ofono/include/dbus-clients.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef OFONO_DBUS_CLIENTS_H
|
||||
#define OFONO_DBUS_CLIENTS_H
|
||||
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
/* Since mer/1.23+git31 */
|
||||
|
||||
struct ofono_dbus_clients;
|
||||
|
||||
typedef void (*ofono_dbus_clients_notify_func)(const char *name,
|
||||
void *user_data);
|
||||
|
||||
struct ofono_dbus_clients *ofono_dbus_clients_new(DBusConnection *conn,
|
||||
ofono_dbus_clients_notify_func notify, void *user_data);
|
||||
void ofono_dbus_clients_free(struct ofono_dbus_clients *clients);
|
||||
|
||||
unsigned int ofono_dbus_clients_count(struct ofono_dbus_clients *clients);
|
||||
|
||||
ofono_bool_t ofono_dbus_clients_add(struct ofono_dbus_clients *clients,
|
||||
const char *name);
|
||||
ofono_bool_t ofono_dbus_clients_remove(struct ofono_dbus_clients *clients,
|
||||
const char *name);
|
||||
|
||||
void ofono_dbus_clients_signal(struct ofono_dbus_clients *clients,
|
||||
DBusMessage *signal);
|
||||
void ofono_dbus_clients_signal_property_changed(struct ofono_dbus_clients *dc,
|
||||
const char *path, const char *interface, const char *name,
|
||||
int type, const void *value);
|
||||
|
||||
#endif /* OFONO_DBUS_CLIENTS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -3,7 +3,7 @@
|
||||
* oFono - Open Telephony stack for Linux
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-2016 Jolla Ltd.
|
||||
* Copyright (C) 2013-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -14,10 +14,6 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_DBUS_H
|
||||
@@ -83,6 +79,8 @@ extern "C" {
|
||||
DBUS_TYPE_VARIANT_AS_STRING \
|
||||
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
|
||||
|
||||
#define OFONO_ERROR_INTERFACE "org.ofono.Error"
|
||||
|
||||
DBusConnection *ofono_dbus_get_connection(void);
|
||||
|
||||
void ofono_dbus_dict_append(DBusMessageIter *dict, const char *key, int type,
|
||||
@@ -110,6 +108,11 @@ int ofono_dbus_signal_dict_property_changed(DBusConnection *conn,
|
||||
const char *name, int type,
|
||||
const void *value);
|
||||
|
||||
/* Since mer/1.23+git31 */
|
||||
DBusMessage *ofono_dbus_signal_new_property_changed(const char *path,
|
||||
const char *interface,
|
||||
const char *name,
|
||||
int type, const void *value);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -128,6 +129,8 @@ void ofono_gprs_context_set_ipv4_gateway(struct ofono_gprs_context *gc,
|
||||
const char *gateway);
|
||||
void ofono_gprs_context_set_ipv4_dns_servers(struct ofono_gprs_context *gc,
|
||||
const char **dns);
|
||||
void ofono_gprs_context_set_ipv4_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const char **pcscf); /* Since mer/1.23+git30 */
|
||||
|
||||
void ofono_gprs_context_set_ipv6_address(struct ofono_gprs_context *gc,
|
||||
const char *address);
|
||||
@@ -137,6 +140,8 @@ void ofono_gprs_context_set_ipv6_gateway(struct ofono_gprs_context *gc,
|
||||
const char *gateway);
|
||||
void ofono_gprs_context_set_ipv6_dns_servers(struct ofono_gprs_context *gc,
|
||||
const char **dns);
|
||||
void ofono_gprs_context_set_ipv6_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const char **pcscf); /* Since mer/1.23+git30 */
|
||||
|
||||
void ofono_gprs_context_signal_change(struct ofono_gprs_context *gc,
|
||||
unsigned int cid);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -210,6 +211,10 @@ struct ofono_sim_driver {
|
||||
void (*logical_access)(struct ofono_sim *sim, int session_id,
|
||||
const unsigned char *pdu, unsigned int len,
|
||||
ofono_sim_logical_access_cb_t cb, void *data);
|
||||
/* Since mer/1.23+git28 */
|
||||
void (*open_channel2)(struct ofono_sim *sim, const unsigned char *aid,
|
||||
unsigned int len, ofono_sim_open_channel_cb_t cb,
|
||||
void *data);
|
||||
};
|
||||
|
||||
int ofono_sim_driver_register(const struct ofono_sim_driver *d);
|
||||
|
||||
@@ -128,6 +128,14 @@ void sailfish_cell_info_set_update_interval(struct sailfish_cell_info *info,
|
||||
}
|
||||
}
|
||||
|
||||
void sailfish_cell_info_set_enabled(struct sailfish_cell_info *info,
|
||||
gboolean enabled)
|
||||
{
|
||||
if (info && info->proc->set_enabled) {
|
||||
info->proc->set_enabled(info, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -89,6 +89,7 @@ struct sailfish_cell_info_proc {
|
||||
sailfish_cell_info_cb_t cb, void *arg);
|
||||
void (*remove_handler)(struct sailfish_cell_info *info, gulong id);
|
||||
void (*set_update_interval)(struct sailfish_cell_info *info, int ms);
|
||||
void (*set_enabled)(struct sailfish_cell_info *info, gboolean enabled);
|
||||
};
|
||||
|
||||
/* Utilities */
|
||||
@@ -107,6 +108,8 @@ void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
|
||||
gulong id);
|
||||
void sailfish_cell_info_set_update_interval(struct sailfish_cell_info *info,
|
||||
int ms);
|
||||
void sailfish_cell_info_set_enabled(struct sailfish_cell_info *info,
|
||||
gboolean enabled);
|
||||
|
||||
#endif /* SAILFISH_CELINFO_H */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
* Copyright (C) 2016-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/dbus.h>
|
||||
#include <ofono/dbus-clients.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
@@ -35,11 +36,13 @@ struct sailfish_cell_info_dbus {
|
||||
gulong handler_id;
|
||||
guint next_cell_id;
|
||||
GSList *entries;
|
||||
struct ofono_dbus_clients *clients;
|
||||
};
|
||||
|
||||
#define CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
|
||||
#define CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
|
||||
#define CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
|
||||
#define CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL "Unsubscribed"
|
||||
|
||||
#define CELL_DBUS_INTERFACE_VERSION (1)
|
||||
#define CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
|
||||
@@ -322,21 +325,24 @@ static void sailfish_cell_info_dbus_emit_path_list
|
||||
(struct sailfish_cell_info_dbus *dbus, const char *name,
|
||||
GPtrArray *list)
|
||||
{
|
||||
guint i;
|
||||
DBusMessageIter it, array;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
if (ofono_dbus_clients_count(dbus->clients)) {
|
||||
guint i;
|
||||
DBusMessageIter it, a;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE, name);
|
||||
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &a);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
dbus_message_iter_append_basic(&a,
|
||||
DBUS_TYPE_OBJECT_PATH, &path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &a);
|
||||
ofono_dbus_clients_signal(dbus->clients, signal);
|
||||
dbus_message_unref(signal);
|
||||
}
|
||||
}
|
||||
|
||||
static int sailfish_cell_info_dbus_compare(const struct sailfish_cell *c1,
|
||||
@@ -366,6 +372,23 @@ static int sailfish_cell_info_dbus_compare(const struct sailfish_cell *c1,
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_emit_signal
|
||||
(struct sailfish_cell_info_dbus *dbus,
|
||||
const char *path, const char *intf,
|
||||
const char *name, int type, ...)
|
||||
{
|
||||
if (ofono_dbus_clients_count(dbus->clients)) {
|
||||
va_list args;
|
||||
DBusMessage *signal = dbus_message_new_signal(path, intf, name);
|
||||
|
||||
va_start(args, type);
|
||||
dbus_message_append_args_valist(signal, type, args);
|
||||
ofono_dbus_clients_signal(dbus->clients, signal);
|
||||
dbus_message_unref(signal);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_property_changed
|
||||
(struct sailfish_cell_info_dbus *dbus,
|
||||
const struct sailfish_cell_entry *entry, int mask)
|
||||
@@ -377,7 +400,8 @@ static void sailfish_cell_info_dbus_property_changed
|
||||
|
||||
if (mask & SAILFISH_CELL_PROPERTY_REGISTERED) {
|
||||
const dbus_bool_t registered = (cell->registered != FALSE);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
|
||||
sailfish_cell_info_dbus_emit_signal(dbus, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_BOOLEAN, ®istered, DBUS_TYPE_INVALID);
|
||||
@@ -386,9 +410,10 @@ static void sailfish_cell_info_dbus_property_changed
|
||||
|
||||
for (i = 0; i < n && mask; i++) {
|
||||
if (mask & prop[i].flag) {
|
||||
ofono_dbus_signal_property_changed(dbus->conn,
|
||||
entry->path, CELL_DBUS_INTERFACE,
|
||||
prop[i].name, DBUS_TYPE_INT32,
|
||||
ofono_dbus_clients_signal_property_changed(
|
||||
dbus->clients, entry->path,
|
||||
CELL_DBUS_INTERFACE, prop[i].name,
|
||||
DBUS_TYPE_INT32,
|
||||
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
|
||||
mask &= ~prop[i].flag;
|
||||
}
|
||||
@@ -411,7 +436,7 @@ static void sailfish_cell_info_dbus_update_entries
|
||||
sailfish_cell_compare_func)) {
|
||||
DBG("%s removed", entry->path);
|
||||
dbus->entries = g_slist_delete_link(dbus->entries, l);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
sailfish_cell_info_dbus_emit_signal(dbus, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
CELL_DBUS_REMOVED_SIGNAL,
|
||||
DBUS_TYPE_INVALID);
|
||||
@@ -492,29 +517,67 @@ static void sailfish_cell_info_dbus_cells_changed_cb
|
||||
((struct sailfish_cell_info_dbus *)arg, TRUE);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_error_failed(DBusMessage *msg,
|
||||
const char *explanation)
|
||||
{
|
||||
return g_dbus_create_error(msg, OFONO_ERROR_INTERFACE ".Failed", "%s",
|
||||
explanation);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_get_cells(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_cell_info_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, array;
|
||||
GSList *l;
|
||||
const char *sender = dbus_message_get_sender(msg);
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct sailfish_cell_entry *entry = l->data;
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&entry->path);
|
||||
if (ofono_dbus_clients_add(dbus->clients, sender)) {
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, a;
|
||||
GSList *l;
|
||||
|
||||
sailfish_cell_info_set_enabled(dbus->info, TRUE);
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &a);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct sailfish_cell_entry *entry = l->data;
|
||||
|
||||
dbus_message_iter_append_basic(&a,
|
||||
DBUS_TYPE_OBJECT_PATH, &entry->path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &a);
|
||||
return reply;
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
return reply;
|
||||
return sailfish_cell_info_dbus_error_failed(msg, "Operation failed");
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_unsubscribe(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_cell_info_dbus *dbus = data;
|
||||
const char *sender = dbus_message_get_sender(msg);
|
||||
|
||||
DBG("%s", sender);
|
||||
if (ofono_dbus_clients_remove(dbus->clients, sender)) {
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE,
|
||||
CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL);
|
||||
|
||||
if (!ofono_dbus_clients_count(dbus->clients)) {
|
||||
sailfish_cell_info_set_enabled(dbus->info, FALSE);
|
||||
}
|
||||
dbus_message_set_destination(signal, sender);
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
return dbus_message_new_method_return(msg);
|
||||
}
|
||||
return sailfish_cell_info_dbus_error_failed(msg, "Not subscribed");
|
||||
}
|
||||
|
||||
static const GDBusMethodTable sailfish_cell_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetCells", NULL,
|
||||
GDBUS_ARGS({ "paths", "ao" }),
|
||||
sailfish_cell_info_dbus_get_cells) },
|
||||
{ GDBUS_METHOD("Unsubscribe", NULL, NULL,
|
||||
sailfish_cell_info_dbus_unsubscribe) },
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -523,9 +586,20 @@ static const GDBusSignalTable sailfish_cell_info_dbus_signals[] = {
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL,
|
||||
GDBUS_ARGS({})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void sailfish_cell_info_dbus_disconnect_cb(const char *name, void *data)
|
||||
{
|
||||
struct sailfish_cell_info_dbus *dbus = data;
|
||||
|
||||
if (!ofono_dbus_clients_count(dbus->clients)) {
|
||||
sailfish_cell_info_set_enabled(dbus->info, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
|
||||
(struct ofono_modem *modem, struct sailfish_cell_info *info)
|
||||
{
|
||||
@@ -550,6 +624,8 @@ struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
|
||||
ofono_modem_add_interface(modem,
|
||||
CELL_INFO_DBUS_INTERFACE);
|
||||
sailfish_cell_info_dbus_update_entries(dbus, FALSE);
|
||||
dbus->clients = ofono_dbus_clients_new(dbus->conn,
|
||||
sailfish_cell_info_dbus_disconnect_cb, dbus);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("CellInfo D-Bus register failed");
|
||||
@@ -565,6 +641,7 @@ void sailfish_cell_info_dbus_free(struct sailfish_cell_info_dbus *dbus)
|
||||
GSList *l;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
ofono_dbus_clients_free(dbus->clients);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE);
|
||||
|
||||
|
||||
182
ofono/src/dbus-clients.c
Normal file
182
ofono/src/dbus-clients.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <ofono/dbus-clients.h>
|
||||
#include <ofono/gdbus.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
struct ofono_dbus_client {
|
||||
struct ofono_dbus_clients *clients;
|
||||
char *name;
|
||||
unsigned int watch_id;
|
||||
};
|
||||
|
||||
struct ofono_dbus_clients {
|
||||
DBusConnection* conn;
|
||||
GHashTable* table;
|
||||
ofono_dbus_clients_notify_func notify;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
/* Compatible with GDestroyNotify */
|
||||
static void ofono_dbus_client_free(struct ofono_dbus_client *client)
|
||||
{
|
||||
struct ofono_dbus_clients *clients = client->clients;
|
||||
|
||||
/* Callers make sure that client parameter is not NULL */
|
||||
if (client->watch_id) {
|
||||
g_dbus_remove_watch(clients->conn, client->watch_id);
|
||||
}
|
||||
g_free(client->name);
|
||||
g_slice_free(struct ofono_dbus_client, client);
|
||||
}
|
||||
|
||||
static void ofono_dbus_clients_disconnect_notify(DBusConnection *connection,
|
||||
void *user_data)
|
||||
{
|
||||
struct ofono_dbus_client *client = user_data;
|
||||
struct ofono_dbus_clients *self = client->clients;
|
||||
char *name = client->name;
|
||||
|
||||
/*
|
||||
* Steal the name so that it doesn't get freed by
|
||||
* ofono_dbus_client_free(). We want to pass it to
|
||||
* the callback but first we need to delete client's
|
||||
* entry from the hashtable.
|
||||
*/
|
||||
client->name = NULL;
|
||||
DBG("%s is gone", name);
|
||||
g_hash_table_remove(self->table, name);
|
||||
if (self->notify) {
|
||||
self->notify(name, self->user_data);
|
||||
}
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
struct ofono_dbus_clients *ofono_dbus_clients_new(DBusConnection *conn,
|
||||
ofono_dbus_clients_notify_func notify, void *user_data)
|
||||
{
|
||||
if (conn) {
|
||||
struct ofono_dbus_clients *self =
|
||||
g_slice_new0(struct ofono_dbus_clients);
|
||||
|
||||
self->conn = dbus_connection_ref(conn);
|
||||
self->table = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
NULL, (GDestroyNotify) ofono_dbus_client_free);
|
||||
self->notify = notify;
|
||||
self->user_data = user_data;
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ofono_dbus_clients_free(struct ofono_dbus_clients *self)
|
||||
{
|
||||
if (self) {
|
||||
g_hash_table_destroy(self->table);
|
||||
dbus_connection_unref(self->conn);
|
||||
g_slice_free(struct ofono_dbus_clients, self);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int ofono_dbus_clients_count(struct ofono_dbus_clients *self)
|
||||
{
|
||||
return self ? g_hash_table_size(self->table) : 0;
|
||||
}
|
||||
|
||||
ofono_bool_t ofono_dbus_clients_add(struct ofono_dbus_clients *self,
|
||||
const char *name)
|
||||
{
|
||||
if (self && name) {
|
||||
struct ofono_dbus_client *client =
|
||||
g_slice_new0(struct ofono_dbus_client);
|
||||
|
||||
client->clients = self;
|
||||
client->name = g_strdup(name);
|
||||
client->watch_id = g_dbus_add_disconnect_watch(self->conn,
|
||||
client->name, ofono_dbus_clients_disconnect_notify,
|
||||
client, NULL);
|
||||
|
||||
if (client->watch_id) {
|
||||
DBG("%s is registered", client->name);
|
||||
g_hash_table_replace(self->table, (gpointer)
|
||||
client->name, client);
|
||||
return TRUE;
|
||||
} else {
|
||||
DBG("failed to register %s", client->name);
|
||||
ofono_dbus_client_free(client);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ofono_bool_t ofono_dbus_clients_remove(struct ofono_dbus_clients *self,
|
||||
const char *name)
|
||||
{
|
||||
return self && name && g_hash_table_remove(self->table, name);
|
||||
}
|
||||
|
||||
void ofono_dbus_clients_signal(struct ofono_dbus_clients *self,
|
||||
DBusMessage *signal)
|
||||
{
|
||||
if (self && signal && g_hash_table_size(self->table)) {
|
||||
GHashTableIter it;
|
||||
gpointer key;
|
||||
const char *last_name = NULL;
|
||||
|
||||
g_hash_table_iter_init(&it, self->table);
|
||||
g_hash_table_iter_next(&it, &key, NULL);
|
||||
last_name = key;
|
||||
|
||||
while (g_hash_table_iter_next(&it, &key, NULL)) {
|
||||
DBusMessage *copy = dbus_message_copy(signal);
|
||||
|
||||
dbus_message_set_destination(copy, key);
|
||||
g_dbus_send_message(self->conn, copy);
|
||||
}
|
||||
|
||||
/*
|
||||
* The last one. Note that g_dbus_send_message() unrefs
|
||||
* the message, we need compensate for that by adding a
|
||||
* reference. The caller still owns the message when this
|
||||
* function returns.
|
||||
*/
|
||||
dbus_message_ref(signal);
|
||||
dbus_message_set_destination(signal, last_name);
|
||||
g_dbus_send_message(self->conn, signal);
|
||||
}
|
||||
}
|
||||
|
||||
void ofono_dbus_clients_signal_property_changed(struct ofono_dbus_clients *self,
|
||||
const char *path, const char *interface, const char *name,
|
||||
int type, const void *value)
|
||||
{
|
||||
if (self && g_hash_table_size(self->table)) {
|
||||
DBusMessage *sig = ofono_dbus_signal_new_property_changed(path,
|
||||
interface, name, type, value);
|
||||
|
||||
ofono_dbus_clients_signal(self, sig);
|
||||
dbus_message_unref(sig);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,10 +14,6 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -29,8 +26,6 @@
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#define OFONO_ERROR_INTERFACE "org.ofono.Error"
|
||||
|
||||
static DBusConnection *g_connection;
|
||||
|
||||
struct error_mapping_entry {
|
||||
@@ -209,8 +204,8 @@ void ofono_dbus_dict_append_dict(DBusMessageIter *dict, const char *key,
|
||||
dbus_message_iter_close_container(dict, &entry);
|
||||
}
|
||||
|
||||
int ofono_dbus_signal_property_changed(DBusConnection *conn,
|
||||
const char *path,
|
||||
/* Since mer/1.23+git31 */
|
||||
DBusMessage *ofono_dbus_signal_new_property_changed(const char *path,
|
||||
const char *interface,
|
||||
const char *name,
|
||||
int type, const void *value)
|
||||
@@ -219,11 +214,8 @@ int ofono_dbus_signal_property_changed(DBusConnection *conn,
|
||||
DBusMessageIter iter;
|
||||
|
||||
signal = dbus_message_new_signal(path, interface, "PropertyChanged");
|
||||
if (signal == NULL) {
|
||||
ofono_error("Unable to allocate new %s.PropertyChanged signal",
|
||||
interface);
|
||||
return -1;
|
||||
}
|
||||
if (signal == NULL)
|
||||
return NULL;
|
||||
|
||||
dbus_message_iter_init_append(signal, &iter);
|
||||
|
||||
@@ -231,6 +223,24 @@ int ofono_dbus_signal_property_changed(DBusConnection *conn,
|
||||
|
||||
append_variant(&iter, type, value);
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
int ofono_dbus_signal_property_changed(DBusConnection *conn,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *name,
|
||||
int type, const void *value)
|
||||
{
|
||||
DBusMessage *signal = ofono_dbus_signal_new_property_changed(path,
|
||||
interface, name, type, value);
|
||||
|
||||
if (signal == NULL) {
|
||||
ofono_error("Unable to allocate new %s.PropertyChanged signal",
|
||||
interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return g_dbus_send_message(conn, signal);
|
||||
}
|
||||
|
||||
|
||||
@@ -994,18 +994,17 @@ static void bac_cb(GAtServer *server, GAtServerRequestType type,
|
||||
/*
|
||||
* CVSD codec is mandatory and must come first.
|
||||
* See HFP v1.6 4.34.1
|
||||
* However, some headsets send the list in wrong order,
|
||||
* but function fine otherwise, so to get those working
|
||||
* let's not be pedantic about the codec order.
|
||||
*/
|
||||
if (g_at_result_iter_next_number(&iter, &val) == FALSE ||
|
||||
val != HFP_CODEC_CVSD)
|
||||
goto fail;
|
||||
|
||||
em->bac_received = TRUE;
|
||||
|
||||
em->negotiated_codec = 0;
|
||||
em->r_codecs[CVSD_OFFSET].supported = TRUE;
|
||||
|
||||
while (g_at_result_iter_next_number(&iter, &val)) {
|
||||
switch (val) {
|
||||
case HFP_CODEC_CVSD:
|
||||
em->bac_received = TRUE;
|
||||
em->negotiated_codec = 0;
|
||||
em->r_codecs[CVSD_OFFSET].supported = TRUE;
|
||||
break;
|
||||
case HFP_CODEC_MSBC:
|
||||
em->r_codecs[MSBC_OFFSET].supported = TRUE;
|
||||
break;
|
||||
@@ -1015,6 +1014,11 @@ static void bac_cb(GAtServer *server, GAtServerRequestType type,
|
||||
}
|
||||
}
|
||||
|
||||
if (!em->bac_received) {
|
||||
DBG("Mandatory codec %d not received.", HFP_CODEC_CVSD);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
|
||||
|
||||
/*
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -97,6 +97,7 @@ struct ipv4_settings {
|
||||
char *netmask;
|
||||
char *gateway;
|
||||
char **dns;
|
||||
char **pcscf;
|
||||
char *proxy;
|
||||
};
|
||||
|
||||
@@ -105,6 +106,7 @@ struct ipv6_settings {
|
||||
unsigned char prefix_len;
|
||||
char *gateway;
|
||||
char **dns;
|
||||
char **pcscf;
|
||||
};
|
||||
|
||||
struct context_settings {
|
||||
@@ -410,6 +412,7 @@ static void context_settings_free(struct context_settings *settings)
|
||||
g_free(settings->ipv4->netmask);
|
||||
g_free(settings->ipv4->gateway);
|
||||
g_strfreev(settings->ipv4->dns);
|
||||
g_strfreev(settings->ipv4->pcscf);
|
||||
g_free(settings->ipv4->proxy);
|
||||
|
||||
g_free(settings->ipv4);
|
||||
@@ -420,6 +423,7 @@ static void context_settings_free(struct context_settings *settings)
|
||||
g_free(settings->ipv6->ip);
|
||||
g_free(settings->ipv6->gateway);
|
||||
g_strfreev(settings->ipv6->dns);
|
||||
g_strfreev(settings->ipv6->pcscf);
|
||||
|
||||
g_free(settings->ipv6);
|
||||
settings->ipv6 = NULL;
|
||||
@@ -484,6 +488,11 @@ static void context_settings_append_ipv4(struct context_settings *settings,
|
||||
DBUS_TYPE_STRING,
|
||||
&settings->ipv4->dns);
|
||||
|
||||
if (settings->ipv4->pcscf)
|
||||
ofono_dbus_dict_append_array(&array, "ProxyCSCF",
|
||||
DBUS_TYPE_STRING,
|
||||
&settings->ipv4->pcscf);
|
||||
|
||||
done:
|
||||
dbus_message_iter_close_container(&variant, &array);
|
||||
|
||||
@@ -549,6 +558,11 @@ static void context_settings_append_ipv6(struct context_settings *settings,
|
||||
DBUS_TYPE_STRING,
|
||||
&settings->ipv6->dns);
|
||||
|
||||
if (settings->ipv6->pcscf)
|
||||
ofono_dbus_dict_append_array(&array, "ProxyCSCF",
|
||||
DBUS_TYPE_STRING,
|
||||
&settings->ipv6->pcscf);
|
||||
|
||||
done:
|
||||
dbus_message_iter_close_container(&variant, &array);
|
||||
|
||||
@@ -3417,6 +3431,18 @@ void ofono_gprs_context_set_ipv4_dns_servers(struct ofono_gprs_context *gc,
|
||||
settings->ipv4->dns = g_strdupv((char **) dns);
|
||||
}
|
||||
|
||||
void ofono_gprs_context_set_ipv4_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const char **pcscf)
|
||||
{
|
||||
struct context_settings *settings = gc->settings;
|
||||
|
||||
if (settings->ipv4 == NULL)
|
||||
return;
|
||||
|
||||
g_strfreev(settings->ipv4->pcscf);
|
||||
settings->ipv4->pcscf = g_strdupv((char **) pcscf);
|
||||
}
|
||||
|
||||
void ofono_gprs_context_set_ipv6_address(struct ofono_gprs_context *gc,
|
||||
const char *address)
|
||||
{
|
||||
@@ -3464,6 +3490,18 @@ void ofono_gprs_context_set_ipv6_dns_servers(struct ofono_gprs_context *gc,
|
||||
settings->ipv6->dns = g_strdupv((char **) dns);
|
||||
}
|
||||
|
||||
void ofono_gprs_context_set_ipv6_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const char **pcscf)
|
||||
{
|
||||
struct context_settings *settings = gc->settings;
|
||||
|
||||
if (settings->ipv6 == NULL)
|
||||
return;
|
||||
|
||||
g_strfreev(settings->ipv6->pcscf);
|
||||
settings->ipv6->pcscf = g_strdupv((char **) pcscf);
|
||||
}
|
||||
|
||||
void ofono_gprs_context_signal_change(struct ofono_gprs_context *gc,
|
||||
unsigned int cid)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -388,6 +388,7 @@ unsigned short __ofono_sms_get_next_ref(struct ofono_sms *sms);
|
||||
|
||||
#include <ofono/sim.h>
|
||||
|
||||
struct sim_aid;
|
||||
struct ofono_sim_aid_session;
|
||||
enum sim_app_type;
|
||||
|
||||
@@ -426,7 +427,7 @@ void __ofono_sim_remove_session_watch(struct ofono_sim_aid_session *session,
|
||||
unsigned int id);
|
||||
|
||||
struct ofono_sim_aid_session *__ofono_sim_get_session_by_aid(
|
||||
struct ofono_sim *sim, unsigned char *aid);
|
||||
struct ofono_sim *sim, const struct sim_aid *aid);
|
||||
|
||||
struct ofono_sim_aid_session *__ofono_sim_get_session_by_type(
|
||||
struct ofono_sim *sim, enum sim_app_type type);
|
||||
@@ -436,7 +437,7 @@ int __ofono_sim_session_get_id(struct ofono_sim_aid_session *session);
|
||||
enum sim_app_type __ofono_sim_session_get_type(
|
||||
struct ofono_sim_aid_session *session);
|
||||
|
||||
unsigned char *__ofono_sim_session_get_aid(
|
||||
const struct sim_aid *__ofono_sim_session_get_aid(
|
||||
struct ofono_sim_aid_session *session);
|
||||
|
||||
const char *__ofono_sim_get_impi(struct ofono_sim *sim);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -62,7 +63,7 @@ struct auth_request {
|
||||
};
|
||||
|
||||
struct aid_object {
|
||||
uint8_t aid[16];
|
||||
struct sim_aid aid;
|
||||
char *path;
|
||||
enum sim_app_type type;
|
||||
};
|
||||
@@ -82,7 +83,7 @@ struct ofono_sim_auth {
|
||||
/*
|
||||
* Find an application by path. 'path' should be a DBusMessage object path.
|
||||
*/
|
||||
static uint8_t *find_aid_by_path(GSList *aid_objects,
|
||||
static const struct aid_object *find_aid_by_path(GSList *aid_objects,
|
||||
const char *path)
|
||||
{
|
||||
GSList *iter = aid_objects;
|
||||
@@ -91,7 +92,7 @@ static uint8_t *find_aid_by_path(GSList *aid_objects,
|
||||
struct aid_object *obj = iter->data;
|
||||
|
||||
if (!strcmp(path, obj->path))
|
||||
return obj->aid;
|
||||
return obj;
|
||||
|
||||
iter = g_slist_next(iter);
|
||||
}
|
||||
@@ -208,14 +209,10 @@ static void handle_umts(struct ofono_sim_auth *sa, const uint8_t *resp,
|
||||
DBusMessage *reply = NULL;
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter dict;
|
||||
const uint8_t *res = NULL;
|
||||
const uint8_t *ck = NULL;
|
||||
const uint8_t *ik = NULL;
|
||||
const uint8_t *auts = NULL;
|
||||
const uint8_t *kc = NULL;
|
||||
struct data_block res, ck, ik, auts, sres, kc;
|
||||
|
||||
if (!sim_parse_umts_authenticate(resp, len, &res, &ck, &ik,
|
||||
&auts, &kc))
|
||||
&auts, &sres, &kc))
|
||||
goto umts_end;
|
||||
|
||||
reply = dbus_message_new_method_return(sa->pending->msg);
|
||||
@@ -225,15 +222,23 @@ static void handle_umts(struct ofono_sim_auth *sa, const uint8_t *resp,
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
"{say}", &dict);
|
||||
|
||||
if (auts) {
|
||||
append_dict_byte_array(&dict, "AUTS", auts, 14);
|
||||
} else {
|
||||
append_dict_byte_array(&dict, "RES", res, 8);
|
||||
append_dict_byte_array(&dict, "CK", ck, 16);
|
||||
append_dict_byte_array(&dict, "IK", ik, 16);
|
||||
if (kc)
|
||||
append_dict_byte_array(&dict, "Kc", kc, 8);
|
||||
}
|
||||
if (auts.data)
|
||||
append_dict_byte_array(&dict, "AUTS", auts.data, auts.len);
|
||||
|
||||
if (sres.data)
|
||||
append_dict_byte_array(&dict, "SRES", sres.data, sres.len);
|
||||
|
||||
if (res.data)
|
||||
append_dict_byte_array(&dict, "RES", res.data, res.len);
|
||||
|
||||
if (ck.data)
|
||||
append_dict_byte_array(&dict, "CK", ck.data, ck.len);
|
||||
|
||||
if (ik.data)
|
||||
append_dict_byte_array(&dict, "IK", ik.data, ik.len);
|
||||
|
||||
if (kc.data)
|
||||
append_dict_byte_array(&dict, "Kc", kc.data, kc.len);
|
||||
|
||||
dbus_message_iter_close_container(&iter, &dict);
|
||||
|
||||
@@ -380,7 +385,7 @@ static DBusMessage *usim_gsm_authenticate(DBusConnection *conn,
|
||||
struct ofono_sim_auth *sa = data;
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter array;
|
||||
uint8_t *aid;
|
||||
const struct aid_object *obj;
|
||||
|
||||
if (sa->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
@@ -420,13 +425,20 @@ static DBusMessage *usim_gsm_authenticate(DBusConnection *conn,
|
||||
/*
|
||||
* retrieve session from SIM
|
||||
*/
|
||||
aid = find_aid_by_path(sa->aid_objects, dbus_message_get_path(msg));
|
||||
sa->pending->session = __ofono_sim_get_session_by_aid(sa->sim, aid);
|
||||
obj = find_aid_by_path(sa->aid_objects, dbus_message_get_path(msg));
|
||||
sa->pending->session = __ofono_sim_get_session_by_aid(sa->sim,
|
||||
&obj->aid);
|
||||
sa->pending->msg = dbus_message_ref(msg);
|
||||
sa->pending->watch_id = __ofono_sim_add_session_watch(
|
||||
sa->pending->session, get_session_cb, sa, NULL);
|
||||
|
||||
return NULL;
|
||||
if (!sa->pending->watch_id) {
|
||||
g_free(sa->pending);
|
||||
sa->pending = NULL;
|
||||
return __ofono_error_not_supported(msg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
format_error:
|
||||
g_free(sa->pending);
|
||||
@@ -442,7 +454,7 @@ static DBusMessage *umts_common(DBusConnection *conn, DBusMessage *msg,
|
||||
uint32_t rlen;
|
||||
uint32_t alen;
|
||||
struct ofono_sim_auth *sa = data;
|
||||
uint8_t *aid;
|
||||
const struct aid_object *obj;
|
||||
|
||||
if (sa->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
@@ -467,12 +479,18 @@ static DBusMessage *umts_common(DBusConnection *conn, DBusMessage *msg,
|
||||
/*
|
||||
* retrieve session from SIM
|
||||
*/
|
||||
aid = find_aid_by_path(sa->aid_objects, dbus_message_get_path(msg));
|
||||
sa->pending->session = __ofono_sim_get_session_by_aid(sa->sim, aid);
|
||||
|
||||
obj = find_aid_by_path(sa->aid_objects, dbus_message_get_path(msg));
|
||||
sa->pending->session = __ofono_sim_get_session_by_aid(sa->sim,
|
||||
&obj->aid);
|
||||
sa->pending->watch_id = __ofono_sim_add_session_watch(
|
||||
sa->pending->session, get_session_cb, sa, NULL);
|
||||
|
||||
if (!sa->pending->watch_id) {
|
||||
g_free(sa->pending);
|
||||
sa->pending = NULL;
|
||||
return __ofono_error_not_supported(msg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -702,14 +720,15 @@ static void sim_auth_register(struct ofono_sim_auth *sa)
|
||||
|
||||
ret = sprintf(new->path, "%s/", path);
|
||||
|
||||
encode_hex_own_buf(r->aid, 16, 0, new->path + ret);
|
||||
encode_hex_own_buf(r->aid.aid, r->aid.len, 0,
|
||||
new->path + ret);
|
||||
|
||||
g_dbus_register_interface(conn, new->path,
|
||||
OFONO_USIM_APPLICATION_INTERFACE,
|
||||
sim_auth_usim_app, NULL, NULL,
|
||||
sa, NULL);
|
||||
|
||||
memcpy(new->aid, r->aid, 16);
|
||||
new->aid = r->aid;
|
||||
|
||||
break;
|
||||
case SIM_APP_TYPE_ISIM:
|
||||
@@ -717,14 +736,15 @@ static void sim_auth_register(struct ofono_sim_auth *sa)
|
||||
|
||||
ret = sprintf(new->path, "%s/", path);
|
||||
|
||||
encode_hex_own_buf(r->aid, 16, 0, new->path + ret);
|
||||
encode_hex_own_buf(r->aid.aid, r->aid.len, 0,
|
||||
new->path + ret);
|
||||
|
||||
g_dbus_register_interface(conn, new->path,
|
||||
OFONO_ISIM_APPLICATION_INTERFACE,
|
||||
sim_auth_isim_app, NULL, NULL,
|
||||
sa, NULL);
|
||||
|
||||
memcpy(new->aid, r->aid, 16);
|
||||
new->aid = r->aid;
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -2441,7 +2442,7 @@ struct ofono_sim_context *ofono_sim_context_create_isim(
|
||||
|
||||
if (session->record->type == SIM_APP_TYPE_ISIM) {
|
||||
return sim_fs_context_new_with_aid(sim->simfs_isim,
|
||||
session->record->aid);
|
||||
&session->record->aid);
|
||||
}
|
||||
|
||||
iter = g_slist_next(iter);
|
||||
@@ -3667,6 +3668,26 @@ const char *__ofono_sim_get_impi(struct ofono_sim *sim)
|
||||
static void open_channel_cb(const struct ofono_error *error, int session_id,
|
||||
void *data);
|
||||
|
||||
static gboolean open_channel(struct ofono_sim_aid_session *session)
|
||||
{
|
||||
struct ofono_sim *sim = session->sim;
|
||||
const struct ofono_sim_driver *driver = sim->driver;
|
||||
const struct sim_aid *aid = &session->record->aid;
|
||||
|
||||
if (driver->open_channel2) {
|
||||
driver->open_channel2(sim, aid->aid, aid->len, open_channel_cb,
|
||||
session);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (driver->open_channel && aid->len == 16) {
|
||||
driver->open_channel(sim, aid->aid, open_channel_cb, session);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void close_channel_cb(const struct ofono_error *error, void *data)
|
||||
{
|
||||
struct ofono_sim_aid_session *session = data;
|
||||
@@ -3680,10 +3701,8 @@ static void close_channel_cb(const struct ofono_error *error, void *data)
|
||||
* An atom requested to open during a close, we can re-open
|
||||
* here.
|
||||
*/
|
||||
session->sim->driver->open_channel(session->sim,
|
||||
session->record->aid, open_channel_cb,
|
||||
session);
|
||||
return;
|
||||
if (open_channel(session))
|
||||
return;
|
||||
}
|
||||
|
||||
session->state = SESSION_STATE_INACTIVE;
|
||||
@@ -3758,10 +3777,12 @@ unsigned int __ofono_sim_add_session_watch(
|
||||
* If the session is inactive and there are no watchers, open
|
||||
* a new session.
|
||||
*/
|
||||
session->state = SESSION_STATE_OPENING;
|
||||
session->sim->driver->open_channel(session->sim,
|
||||
session->record->aid, open_channel_cb,
|
||||
session);
|
||||
if (open_channel(session)) {
|
||||
session->state = SESSION_STATE_OPENING;
|
||||
} else {
|
||||
g_free(item);
|
||||
return 0;
|
||||
}
|
||||
} else if (session->state == SESSION_STATE_OPEN) {
|
||||
/*
|
||||
* Session is already open and available, just call the
|
||||
@@ -3794,14 +3815,15 @@ void __ofono_sim_remove_session_watch(struct ofono_sim_aid_session *session,
|
||||
}
|
||||
|
||||
struct ofono_sim_aid_session *__ofono_sim_get_session_by_aid(
|
||||
struct ofono_sim *sim, unsigned char *aid)
|
||||
struct ofono_sim *sim, const struct sim_aid *aid)
|
||||
{
|
||||
GSList *iter = sim->aid_sessions;
|
||||
|
||||
while (iter) {
|
||||
struct ofono_sim_aid_session *session = iter->data;
|
||||
|
||||
if (!memcmp(session->record->aid, aid, 16))
|
||||
if (session->record->aid.len == aid->len &&
|
||||
!memcmp(session->record->aid.aid, aid->aid, aid->len))
|
||||
return session;
|
||||
|
||||
iter = g_slist_next(iter);
|
||||
@@ -3838,10 +3860,10 @@ enum sim_app_type __ofono_sim_session_get_type(
|
||||
return session->record->type;
|
||||
}
|
||||
|
||||
unsigned char *__ofono_sim_session_get_aid(
|
||||
const struct sim_aid *__ofono_sim_session_get_aid(
|
||||
struct ofono_sim_aid_session *session)
|
||||
{
|
||||
return session->record->aid;
|
||||
return &session->record->aid;
|
||||
}
|
||||
|
||||
GSList *__ofono_sim_get_aid_list(struct ofono_sim *sim)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -164,7 +165,7 @@ struct ofono_sim_context *sim_fs_context_new(struct sim_fs *fs)
|
||||
}
|
||||
|
||||
struct ofono_sim_context *sim_fs_context_new_with_aid(struct sim_fs *fs,
|
||||
unsigned char *aid)
|
||||
const struct sim_aid *aid)
|
||||
{
|
||||
struct ofono_sim_context *context = sim_fs_context_new(fs);
|
||||
|
||||
@@ -404,18 +405,18 @@ static void sim_fs_op_read_block_cb(const struct ofono_error *error,
|
||||
}
|
||||
|
||||
start_block = op->offset / 256;
|
||||
end_block = (op->offset + (op->num_bytes - 1)) / 256;
|
||||
end_block = op->num_bytes ? (op->offset + op->num_bytes - 1) / 256 :
|
||||
start_block;
|
||||
|
||||
if (op->current == start_block) {
|
||||
bufoff = 0;
|
||||
dataoff = op->offset % 256;
|
||||
tocopy = MIN(256 - op->offset % 256,
|
||||
op->num_bytes - op->current * 256);
|
||||
tocopy = MIN(256 - dataoff, op->num_bytes);
|
||||
} else {
|
||||
bufoff = (op->current - start_block - 1) * 256 +
|
||||
bufoff = (op->current - start_block) * 256 -
|
||||
op->offset % 256;
|
||||
dataoff = 0;
|
||||
tocopy = MIN(256, op->num_bytes - op->current * 256);
|
||||
tocopy = MIN(256, op->num_bytes - bufoff);
|
||||
}
|
||||
|
||||
DBG("bufoff: %d, dataoff: %d, tocopy: %d",
|
||||
@@ -484,13 +485,12 @@ static gboolean sim_fs_op_read_block(gpointer user_data)
|
||||
bufoff = 0;
|
||||
seekoff = SIM_CACHE_HEADER_SIZE + op->current * 256 +
|
||||
op->offset % 256;
|
||||
toread = MIN(256 - op->offset % 256,
|
||||
op->num_bytes - op->current * 256);
|
||||
toread = MIN(256 - op->offset % 256, op->num_bytes);
|
||||
} else {
|
||||
bufoff = (op->current - start_block - 1) * 256 +
|
||||
bufoff = (op->current - start_block) * 256 -
|
||||
op->offset % 256;
|
||||
seekoff = SIM_CACHE_HEADER_SIZE + op->current * 256;
|
||||
toread = MIN(256, op->num_bytes - op->current * 256);
|
||||
toread = MIN(256, op->num_bytes - bufoff);
|
||||
}
|
||||
|
||||
DBG("bufoff: %d, seekoff: %d, toread: %d",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -20,6 +21,7 @@
|
||||
*/
|
||||
|
||||
struct sim_fs;
|
||||
struct sim_aid;
|
||||
|
||||
typedef void (*sim_fs_read_info_cb_t)(int ok, unsigned char file_status,
|
||||
int total_length, int record_length,
|
||||
@@ -30,7 +32,7 @@ struct sim_fs *sim_fs_new(struct ofono_sim *sim,
|
||||
struct ofono_sim_context *sim_fs_context_new(struct sim_fs *fs);
|
||||
|
||||
struct ofono_sim_context *sim_fs_context_new_with_aid(struct sim_fs *fs,
|
||||
unsigned char *aid);
|
||||
const struct sim_aid *aid);
|
||||
|
||||
unsigned int sim_fs_file_watch_add(struct ofono_sim_context *context,
|
||||
int id, ofono_sim_file_changed_cb_t cb,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -1572,20 +1573,17 @@ GSList *sim_parse_app_template_entries(const unsigned char *buffer, int len)
|
||||
/* Find all the application entries */
|
||||
while ((dataobj = ber_tlv_find_by_tag(buffer, 0x61, len,
|
||||
&dataobj_len)) != NULL) {
|
||||
struct sim_app_record app;
|
||||
struct sim_app_record *app;
|
||||
const unsigned char *aid, *label;
|
||||
int label_len;
|
||||
int label_len, aid_len;
|
||||
char *app_label;
|
||||
|
||||
/* Find the aid (mandatory) */
|
||||
aid = ber_tlv_find_by_tag(dataobj, 0x4f, dataobj_len,
|
||||
&app.aid_len);
|
||||
if (!aid || app.aid_len < 0x01 || app.aid_len > 0x10)
|
||||
&aid_len);
|
||||
if (!aid || aid_len < 0x01 || aid_len > 0x10)
|
||||
goto error;
|
||||
|
||||
memcpy(app.aid, aid, app.aid_len);
|
||||
|
||||
app.type = (app.aid[5] << 8) | app.aid[6];
|
||||
|
||||
/* Find the label (optional) */
|
||||
label = ber_tlv_find_by_tag(dataobj, 0x50, dataobj_len,
|
||||
&label_len);
|
||||
@@ -1594,14 +1592,21 @@ GSList *sim_parse_app_template_entries(const unsigned char *buffer, int len)
|
||||
* Label field uses the extra complicated
|
||||
* encoding in 102.221 Annex A
|
||||
*/
|
||||
app.label = sim_string_to_utf8(label, label_len);
|
||||
app_label = sim_string_to_utf8(label, label_len);
|
||||
|
||||
if (app.label == NULL)
|
||||
if (app_label == NULL)
|
||||
goto error;
|
||||
} else
|
||||
app.label = NULL;
|
||||
app_label = NULL;
|
||||
|
||||
ret = g_slist_prepend(ret, g_memdup(&app, sizeof(app)));
|
||||
app = g_new0(struct sim_app_record, 1);
|
||||
|
||||
memcpy(app->aid.aid, aid, aid_len);
|
||||
app->aid.len = aid_len;
|
||||
app->label = app_label;
|
||||
app->type = (aid[5] << 8) | aid[6];
|
||||
|
||||
ret = g_slist_prepend(ret, app);
|
||||
|
||||
len -= (dataobj - buffer) + dataobj_len;
|
||||
buffer = dataobj + dataobj_len;
|
||||
@@ -1667,67 +1672,135 @@ int sim_build_gsm_authenticate(unsigned char *buffer, int len,
|
||||
return build_authenticate(buffer, rand, NULL);
|
||||
}
|
||||
|
||||
gboolean sim_parse_umts_authenticate(const unsigned char *buffer,
|
||||
int len, const unsigned char **res, const unsigned char **ck,
|
||||
const unsigned char **ik, const unsigned char **auts,
|
||||
const unsigned char **kc)
|
||||
gboolean sim_parse_umts_authenticate(const unsigned char *buffer, int len,
|
||||
struct data_block *res, struct data_block *ck,
|
||||
struct data_block *ik, struct data_block *auts,
|
||||
struct data_block *sres, struct data_block *kc)
|
||||
{
|
||||
if (len < 16 || !buffer)
|
||||
const unsigned char *ptr = buffer;
|
||||
const unsigned char *end = ptr + len;
|
||||
unsigned int l;
|
||||
|
||||
if (!buffer || len < 2)
|
||||
return FALSE;
|
||||
|
||||
switch (buffer[0]) {
|
||||
memset(res, 0, sizeof(*res));
|
||||
memset(ck, 0, sizeof(*ck));
|
||||
memset(ik, 0, sizeof(*ik));
|
||||
memset(kc, 0, sizeof(*kc));
|
||||
memset(auts, 0, sizeof(*auts));
|
||||
memset(sres, 0, sizeof(*sres));
|
||||
|
||||
/*
|
||||
* TS 31.102
|
||||
* 7.1.2.1 GSM/3G security context
|
||||
*/
|
||||
switch (*ptr++) {
|
||||
case 0xdb:
|
||||
/* 'DB' + '08' + RES(16) + '10' + CK(32) + '10' + IK(32) = 43 */
|
||||
if (len < 43)
|
||||
goto umts_end;
|
||||
/*
|
||||
* Response parameters/data, case 1, 3G security context,
|
||||
* command successful:
|
||||
*
|
||||
* "Successful 3G authentication" tag = 'DB'
|
||||
* 'DB' + L3 + RES(L3) + L4 + CK(L4) + L5 + IK(L5) + 8 + Kc(8)
|
||||
*/
|
||||
l = *ptr++; /* L3 */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
/* success */
|
||||
if (buffer[1] != 0x08)
|
||||
goto umts_end;
|
||||
res->data = ptr;
|
||||
res->len = l;
|
||||
ptr += l;
|
||||
|
||||
*res = buffer + 2;
|
||||
if (ptr == end)
|
||||
return FALSE;
|
||||
|
||||
if (buffer[10] != 0x10)
|
||||
goto umts_end;
|
||||
l = *ptr++; /* L4 */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
*ck = buffer + 11;
|
||||
ck->data = ptr;
|
||||
ck->len = l;
|
||||
ptr += l;
|
||||
|
||||
if (buffer[27] != 0x10)
|
||||
goto umts_end;
|
||||
if (ptr == end)
|
||||
return FALSE;
|
||||
|
||||
*ik = buffer + 28;
|
||||
l = *ptr++; /* L5 */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
if (len >= 53 && kc) {
|
||||
if (buffer[44] != 0x08)
|
||||
goto umts_end;
|
||||
ik->data = ptr;
|
||||
ik->len = l;
|
||||
ptr += l;
|
||||
|
||||
*kc = buffer + 45;
|
||||
} else {
|
||||
*kc = NULL;
|
||||
if (ptr < end) {
|
||||
l = *ptr++;
|
||||
if (l != 8 || (ptr + l) != end)
|
||||
return FALSE;
|
||||
|
||||
kc->data = ptr;
|
||||
kc->len = l;
|
||||
ptr += l;
|
||||
}
|
||||
|
||||
*auts = NULL;
|
||||
return TRUE;
|
||||
|
||||
break;
|
||||
case 0xdc:
|
||||
/* 'DC' + '0E' + AUTS(14) = 16 */
|
||||
if (len < 16)
|
||||
goto umts_end;
|
||||
/*
|
||||
* Response parameters/data, case 2, 3G security context,
|
||||
* synchronisation failure:
|
||||
*
|
||||
* "Synchronisation failure" tag = 'DC'
|
||||
* 'DC' + L1 + AUTS(L1)
|
||||
*/
|
||||
l = *ptr++; /* L1 */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
/* sync error */
|
||||
if (buffer[1] != 0x0e)
|
||||
goto umts_end;
|
||||
auts->data = ptr;
|
||||
auts->len = l;
|
||||
ptr += l;
|
||||
|
||||
*auts = buffer + 2;
|
||||
if (ptr != end)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
case 0x04:
|
||||
/*
|
||||
* Response parameters/data, case 3, GSM security context,
|
||||
* command successful:
|
||||
*
|
||||
* 4 + SRES(4) + 8 + Kc(8)
|
||||
*/
|
||||
l = 4; /* Already skipped this one */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
sres->data = ptr;
|
||||
sres->len = l;
|
||||
ptr += l;
|
||||
|
||||
if (ptr == end)
|
||||
return FALSE;
|
||||
|
||||
l = *ptr++; /* 8 */
|
||||
if (l != 8 || (ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
kc->data = ptr;
|
||||
kc->len = l;
|
||||
ptr += l;
|
||||
|
||||
if (ptr != end)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
break;
|
||||
default:
|
||||
goto umts_end;
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
umts_end:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -314,9 +314,13 @@ struct sim_ef_info {
|
||||
enum sim_file_access perm_update;
|
||||
};
|
||||
|
||||
struct sim_app_record {
|
||||
struct sim_aid {
|
||||
unsigned char aid[16];
|
||||
int aid_len;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
struct sim_app_record {
|
||||
struct sim_aid aid;
|
||||
char *label;
|
||||
enum sim_app_type type;
|
||||
};
|
||||
@@ -371,6 +375,11 @@ struct comprehension_tlv_builder {
|
||||
struct ber_tlv_builder *parent;
|
||||
};
|
||||
|
||||
struct data_block {
|
||||
const unsigned char *data;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
void simple_tlv_iter_init(struct simple_tlv_iter *iter,
|
||||
const unsigned char *pdu, unsigned int len);
|
||||
gboolean simple_tlv_iter_next(struct simple_tlv_iter *iter);
|
||||
@@ -526,10 +535,10 @@ int sim_build_umts_authenticate(unsigned char *buffer, int len,
|
||||
int sim_build_gsm_authenticate(unsigned char *buffer, int len,
|
||||
const unsigned char *rand);
|
||||
|
||||
gboolean sim_parse_umts_authenticate(const unsigned char *buffer,
|
||||
int len, const unsigned char **res, const unsigned char **ck,
|
||||
const unsigned char **ik, const unsigned char **auts,
|
||||
const unsigned char **kc);
|
||||
gboolean sim_parse_umts_authenticate(const unsigned char *buffer, int len,
|
||||
struct data_block *res, struct data_block *ck,
|
||||
struct data_block *ik, struct data_block *auts,
|
||||
struct data_block *sres, struct data_block *kc);
|
||||
|
||||
gboolean sim_parse_gsm_authenticate(const unsigned char *buffer, int len,
|
||||
const unsigned char **sres, const unsigned char **kc);
|
||||
|
||||
@@ -18,6 +18,7 @@ TESTS="\
|
||||
test-caif \
|
||||
test-dbus-queue \
|
||||
test-dbus-access \
|
||||
test-dbus-clients \
|
||||
test-gprs-filter \
|
||||
test-provision \
|
||||
test-config \
|
||||
|
||||
280
ofono/unit/test-dbus-clients.c
Normal file
280
ofono/unit/test-dbus-clients.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2021 Jolla Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "test-dbus.h"
|
||||
|
||||
#include <ofono/dbus-clients.h>
|
||||
#include <ofono/dbus.h>
|
||||
#include <ofono/log.h>
|
||||
#include "ofono.h"
|
||||
|
||||
#include <gutil_log.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define TEST_TIMEOUT (10) /* seconds */
|
||||
#define TEST_SENDER ":1.0"
|
||||
#define TEST_SENDER_1 ":1.1"
|
||||
|
||||
#define TEST_DBUS_PATH "/test"
|
||||
#define TEST_DBUS_INTERFACE "test.interface"
|
||||
#define TEST_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
|
||||
#define TEST_PROPERTY_NAME "Test"
|
||||
#define TEST_PROPERTY_VALUE "test"
|
||||
|
||||
struct test_data {
|
||||
struct test_dbus_context dbus;
|
||||
struct ofono_dbus_clients *clients;
|
||||
int count;
|
||||
};
|
||||
|
||||
static gboolean test_debug;
|
||||
|
||||
/* ==== dummy interface ==== */
|
||||
|
||||
#define test_register_interface(methods,signals,data) \
|
||||
g_assert(g_dbus_register_interface(ofono_dbus_get_connection(), \
|
||||
TEST_DBUS_PATH, TEST_DBUS_INTERFACE, \
|
||||
methods, signals, NULL, data, NULL))
|
||||
|
||||
#define test_register_dummy_interface() \
|
||||
test_register_interface(test_dummy_methods, \
|
||||
test_property_change_signal, NULL)
|
||||
|
||||
static DBusMessage *test_dummy_handler(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable test_dummy_methods[] = {
|
||||
{ GDBUS_ASYNC_METHOD("Dummy", NULL, NULL, test_dummy_handler) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable test_property_change_signal[] = {
|
||||
{ GDBUS_SIGNAL("PropertyChanged",
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* ==== common ==== */
|
||||
|
||||
static gboolean test_timeout(gpointer param)
|
||||
{
|
||||
g_assert(!"TIMEOUT");
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static guint test_setup_timeout(void)
|
||||
{
|
||||
if (test_debug) {
|
||||
return 0;
|
||||
} else {
|
||||
return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean test_loop_quit(gpointer data)
|
||||
{
|
||||
g_main_loop_quit(data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void test_loop_quit_later(GMainLoop *loop)
|
||||
{
|
||||
g_idle_add(test_loop_quit, loop);
|
||||
}
|
||||
|
||||
/* ==== null ==== */
|
||||
|
||||
static void test_null(void)
|
||||
{
|
||||
/* We are NULL tolerant: */
|
||||
ofono_dbus_clients_free(NULL);
|
||||
ofono_dbus_clients_signal(NULL, NULL);
|
||||
ofono_dbus_clients_signal_property_changed(NULL,NULL,NULL,NULL,0,NULL);
|
||||
g_assert(!ofono_dbus_clients_new(NULL, NULL, NULL));
|
||||
g_assert(!ofono_dbus_clients_count(NULL));
|
||||
g_assert(!ofono_dbus_clients_add(NULL, NULL));
|
||||
g_assert(!ofono_dbus_clients_remove(NULL, NULL));
|
||||
}
|
||||
|
||||
/* ==== basic ==== */
|
||||
|
||||
static void test_basic_notify_func(const char *name, void *loop)
|
||||
{
|
||||
g_assert_cmpstr(name, == ,TEST_SENDER);
|
||||
g_main_loop_quit(loop);
|
||||
}
|
||||
|
||||
static void test_basic_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_data *test = G_CAST(dbus, struct test_data, dbus);
|
||||
const char *value = TEST_PROPERTY_VALUE;
|
||||
DBusMessage *signal =
|
||||
ofono_dbus_signal_new_property_changed(TEST_DBUS_PATH,
|
||||
TEST_DBUS_INTERFACE, TEST_PROPERTY_NAME,
|
||||
DBUS_TYPE_STRING, &value);
|
||||
|
||||
test->clients = ofono_dbus_clients_new(ofono_dbus_get_connection(),
|
||||
test_basic_notify_func, test->dbus.loop);
|
||||
|
||||
g_assert(!ofono_dbus_clients_add(test->clients, NULL));
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
|
||||
g_assert(ofono_dbus_clients_remove(test->clients, TEST_SENDER));
|
||||
g_assert(!ofono_dbus_clients_remove(test->clients, TEST_SENDER));
|
||||
|
||||
/* OK to add the same thing twice */
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test->clients), == ,1);
|
||||
test_dbus_watch_disconnect_all();
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test->clients), == ,0);
|
||||
|
||||
/* There's nothing to remove */
|
||||
g_assert(!ofono_dbus_clients_remove(test->clients, TEST_SENDER));
|
||||
g_assert(!ofono_dbus_clients_remove(test->clients, NULL));
|
||||
|
||||
/* These have no effect because client list is empty: */
|
||||
ofono_dbus_clients_signal(test->clients, NULL);
|
||||
ofono_dbus_clients_signal(test->clients, signal);
|
||||
ofono_dbus_clients_signal_property_changed(test->clients, NULL, NULL,
|
||||
NULL, 0, NULL);
|
||||
ofono_dbus_clients_signal_property_changed(test->clients,
|
||||
TEST_DBUS_PATH, TEST_DBUS_INTERFACE,
|
||||
TEST_PROPERTY_NAME, DBUS_TYPE_STRING, &value);
|
||||
|
||||
/* test_basic_notify_func() has called test_loop_quit_later() */
|
||||
dbus_message_unref(signal);
|
||||
}
|
||||
|
||||
static void test_basic(void)
|
||||
{
|
||||
struct test_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_basic_start;
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
g_assert(test.clients);
|
||||
ofono_dbus_clients_free(test.clients);
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== signal ==== */
|
||||
|
||||
static void test_signal_handle(struct test_dbus_context *dbus, DBusMessage *msg)
|
||||
{
|
||||
struct test_data *test = G_CAST(dbus, struct test_data, dbus);
|
||||
|
||||
g_assert_cmpstr(dbus_message_get_path(msg), == ,TEST_DBUS_PATH);
|
||||
g_assert_cmpstr(dbus_message_get_interface(msg), == ,
|
||||
TEST_DBUS_INTERFACE);
|
||||
g_assert_cmpstr(dbus_message_get_member(msg), == ,
|
||||
TEST_PROPERTY_CHANGED_SIGNAL);
|
||||
test->count++;
|
||||
if (test->count == 2) {
|
||||
test_loop_quit_later(dbus->loop);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_signal_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_data *test = G_CAST(dbus, struct test_data, dbus);
|
||||
const char *value = TEST_PROPERTY_VALUE;
|
||||
|
||||
test_register_dummy_interface();
|
||||
test->clients = ofono_dbus_clients_new(ofono_dbus_get_connection(),
|
||||
NULL, NULL);
|
||||
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER_1));
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test->clients), == ,2);
|
||||
|
||||
ofono_dbus_clients_signal_property_changed(test->clients,
|
||||
TEST_DBUS_PATH, TEST_DBUS_INTERFACE,
|
||||
TEST_PROPERTY_NAME, DBUS_TYPE_STRING, &value);
|
||||
/* And wait for 2 signals to arrive */
|
||||
}
|
||||
|
||||
static void test_signal(void)
|
||||
{
|
||||
struct test_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_signal_start;
|
||||
test.dbus.handle_signal = test_signal_handle;
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test.clients), == ,2);
|
||||
test_dbus_watch_disconnect_all();
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test.clients), == ,0);
|
||||
ofono_dbus_clients_free(test.clients);
|
||||
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_(name) "/dbus-clients/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
|
||||
test_debug = TRUE;
|
||||
} else {
|
||||
GWARN("Unsupported command line option %s", arg);
|
||||
}
|
||||
}
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_default.level = g_test_verbose() ?
|
||||
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
|
||||
__ofono_log_init("test-dbus-clients",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("signal"), test_signal);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -133,6 +133,13 @@ guint g_dbus_add_signal_watch(DBusConnection *connection, const char *sender,
|
||||
return test_dbus_add_watch(connection, NULL, destroy, user_data);
|
||||
}
|
||||
|
||||
guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name,
|
||||
GDBusWatchFunction func, void *user_data,
|
||||
GDBusDestroyFunction destroy)
|
||||
{
|
||||
return test_dbus_add_watch(connection, func, destroy, user_data);
|
||||
}
|
||||
|
||||
gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
|
||||
{
|
||||
struct test_dbus_watch *prev = NULL;
|
||||
@@ -303,6 +310,9 @@ static DBusHandlerResult test_dbus_client_message_cb(DBusConnection *conn,
|
||||
dbus_message_get_path(msg));
|
||||
test->client_signals = g_slist_append(test->client_signals,
|
||||
dbus_message_ref(msg));
|
||||
if (test->handle_signal) {
|
||||
test->handle_signal(test, msg);
|
||||
}
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
} else {
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -25,6 +25,7 @@ struct test_dbus_context {
|
||||
DBusConnection *client_connection;
|
||||
GSList* client_signals;
|
||||
void (*start)(struct test_dbus_context *test);
|
||||
void (*handle_signal)(struct test_dbus_context *test, DBusMessage *msg);
|
||||
guint timeout_id;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -31,6 +31,7 @@
|
||||
#define CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
|
||||
#define CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
|
||||
#define CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
|
||||
#define CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL "Unsubscribed"
|
||||
|
||||
#define CELL_DBUS_INTERFACE_VERSION (1)
|
||||
#define CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
|
||||
@@ -66,7 +67,7 @@ static gboolean test_timeout(gpointer param)
|
||||
|
||||
static guint test_setup_timeout(void)
|
||||
{
|
||||
if (!test_debug) {
|
||||
if (test_debug) {
|
||||
return 0;
|
||||
} else {
|
||||
return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, NULL);
|
||||
@@ -102,6 +103,19 @@ static DBusMessage *test_new_cell_call(const char *path, const char *method)
|
||||
return msg;
|
||||
}
|
||||
|
||||
static void test_submit_cell_info_call(DBusConnection* connection,
|
||||
const char *method, DBusPendingCallNotifyFunction notify,
|
||||
void *data)
|
||||
{
|
||||
DBusMessage *msg = test_new_cell_info_call(method);
|
||||
DBusPendingCall* call;
|
||||
|
||||
g_assert(dbus_connection_send_with_reply(connection, msg, &call,
|
||||
DBUS_TIMEOUT_INFINITE));
|
||||
dbus_pending_call_set_notify(call, notify, data, NULL);
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
static void test_submit_get_all_call(DBusConnection* connection,
|
||||
const char *cell_path, DBusPendingCallNotifyFunction notify,
|
||||
void *data)
|
||||
@@ -186,6 +200,26 @@ static void test_check_get_all_reply(DBusPendingCall *call,
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
|
||||
static void test_check_empty_reply(DBusPendingCall *call)
|
||||
{
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
DBusMessageIter it;
|
||||
|
||||
g_assert(dbus_message_get_type(reply) ==
|
||||
DBUS_MESSAGE_TYPE_METHOD_RETURN);
|
||||
dbus_message_iter_init(reply, &it);
|
||||
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
|
||||
static void test_check_error(DBusPendingCall *call, const char* name)
|
||||
{
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
|
||||
g_assert(dbus_message_is_error(reply, name));
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
|
||||
static struct sailfish_cell *test_cell_init_gsm1(struct sailfish_cell *cell)
|
||||
{
|
||||
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
@@ -311,19 +345,13 @@ struct test_get_cells_data {
|
||||
static void test_get_cells_call(struct test_get_cells_data *test,
|
||||
DBusPendingCallNotifyFunction notify)
|
||||
{
|
||||
DBusPendingCall *call;
|
||||
DBusConnection *connection = test->context.client_connection;
|
||||
DBusMessage *msg = test_new_cell_info_call("GetCells");
|
||||
|
||||
g_assert(dbus_connection_send_with_reply(connection, msg, &call,
|
||||
DBUS_TIMEOUT_INFINITE));
|
||||
dbus_pending_call_set_notify(call, notify, test, NULL);
|
||||
dbus_message_unref(msg);
|
||||
test_submit_cell_info_call(test->context.client_connection, "GetCells",
|
||||
notify, test);
|
||||
}
|
||||
|
||||
static void test_get_cells_start_reply3(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_get_cells_data *test = data;
|
||||
struct test_get_cells_data *test = data;
|
||||
DBusMessageIter it;
|
||||
DBusMessage *signal = test_dbus_take_signal(&test->context,
|
||||
test->modem.path, CELL_INFO_DBUS_INTERFACE,
|
||||
@@ -344,7 +372,7 @@ static void test_get_cells_start_reply3(DBusPendingCall *call, void *data)
|
||||
|
||||
static void test_get_cells_start_reply2(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_get_cells_data *test = data;
|
||||
struct test_get_cells_data *test = data;
|
||||
const char *cell_added = "/test/cell_1";
|
||||
struct sailfish_cell cell;
|
||||
DBusMessageIter it;
|
||||
@@ -371,7 +399,7 @@ static void test_get_cells_start_reply2(DBusPendingCall *call, void *data)
|
||||
|
||||
static void test_get_cells_start_reply1(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_get_cells_data *test = data;
|
||||
struct test_get_cells_data *test = data;
|
||||
struct sailfish_cell cell;
|
||||
|
||||
DBG("");
|
||||
@@ -432,7 +460,7 @@ struct test_get_all_data {
|
||||
|
||||
static void test_get_all_reply(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_get_all_data *test = data;
|
||||
struct test_get_all_data *test = data;
|
||||
|
||||
DBG("");
|
||||
test_check_get_all_reply(call, &test->cell, test->type);
|
||||
@@ -519,7 +547,7 @@ struct test_get_version_data {
|
||||
|
||||
static void test_get_version_reply(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_get_version_data *test = data;
|
||||
struct test_get_version_data *test = data;
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
dbus_int32_t version;
|
||||
|
||||
@@ -588,7 +616,7 @@ struct test_get_type_data {
|
||||
|
||||
static void test_get_type_reply(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_get_type_data *test = data;
|
||||
struct test_get_type_data *test = data;
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
DBusMessageIter it;
|
||||
|
||||
@@ -656,7 +684,7 @@ struct test_get_registered_data {
|
||||
|
||||
static void test_get_registered_reply(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_get_registered_data *test = data;
|
||||
struct test_get_registered_data *test = data;
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
DBusMessageIter it;
|
||||
|
||||
@@ -725,7 +753,7 @@ struct test_get_properties_data {
|
||||
|
||||
static void test_get_properties_reply(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_get_properties_data *test = data;
|
||||
struct test_get_properties_data *test = data;
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(call);
|
||||
DBusMessageIter it, array;
|
||||
|
||||
@@ -799,9 +827,9 @@ struct test_registered_changed_data {
|
||||
const char *cell_path;
|
||||
};
|
||||
|
||||
static void test_registered_changed_reply(DBusPendingCall *call, void *data)
|
||||
static void test_registered_changed_reply2(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_registered_changed_data *test = data;
|
||||
struct test_registered_changed_data *test = data;
|
||||
|
||||
DBG("");
|
||||
test_check_get_all_reply(call, &test->cell, test->type);
|
||||
@@ -810,17 +838,14 @@ static void test_registered_changed_reply(DBusPendingCall *call, void *data)
|
||||
test_loop_quit_later(test->context.loop);
|
||||
}
|
||||
|
||||
static void test_registered_changed_start(struct test_dbus_context *context)
|
||||
static void test_registered_changed_reply1(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_registered_changed_data *test =
|
||||
G_CAST(context, struct test_registered_changed_data, context);
|
||||
struct test_registered_changed_data *test = data;
|
||||
struct sailfish_cell *first_cell;
|
||||
|
||||
DBG("");
|
||||
test->info = fake_cell_info_new();
|
||||
fake_cell_info_add_cell(test->info, &test->cell);
|
||||
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
|
||||
g_assert(test->dbus);
|
||||
test_check_get_cells_reply(call, test->cell_path, NULL);
|
||||
dbus_pending_call_unref(call);
|
||||
|
||||
/* Trigger "RegisteredChanged" signal */
|
||||
first_cell = test->info->cells->data;
|
||||
@@ -828,8 +853,24 @@ static void test_registered_changed_start(struct test_dbus_context *context)
|
||||
first_cell->registered = !first_cell->registered;
|
||||
fake_cell_info_cells_changed(test->info);
|
||||
|
||||
test_submit_get_all_call(context->client_connection, test->cell_path,
|
||||
test_registered_changed_reply, test);
|
||||
test_submit_get_all_call(test->context.client_connection,
|
||||
test->cell_path, test_registered_changed_reply2, test);
|
||||
}
|
||||
|
||||
static void test_registered_changed_start(struct test_dbus_context *context)
|
||||
{
|
||||
struct test_registered_changed_data *test =
|
||||
G_CAST(context, struct test_registered_changed_data, context);
|
||||
|
||||
DBG("");
|
||||
test->info = fake_cell_info_new();
|
||||
fake_cell_info_add_cell(test->info, &test->cell);
|
||||
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
|
||||
g_assert(test->dbus);
|
||||
|
||||
/* Submit GetCells to enable "RegisteredChanged" signals */
|
||||
test_submit_cell_info_call(test->context.client_connection, "GetCells",
|
||||
test_registered_changed_reply1, test);
|
||||
}
|
||||
|
||||
static void test_registered_changed(void)
|
||||
@@ -871,28 +912,26 @@ struct test_property_changed_data {
|
||||
const char *cell_path;
|
||||
};
|
||||
|
||||
static void test_property_changed_reply1(DBusPendingCall *call, void *data)
|
||||
static void test_property_changed_reply2(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_property_changed_data *test = data;
|
||||
struct test_property_changed_data *test = data;
|
||||
|
||||
DBG("");
|
||||
test_check_get_all_reply(call, &test->cell, test->type);
|
||||
dbus_pending_call_unref(call);
|
||||
|
||||
test_loop_quit_later(test->context.loop);
|
||||
test_dbus_watch_disconnect_all();
|
||||
}
|
||||
|
||||
static void test_property_changed_start(struct test_dbus_context *context)
|
||||
static void test_property_changed_reply1(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_property_changed_data *test =
|
||||
G_CAST(context, struct test_property_changed_data, context);
|
||||
struct test_property_changed_data *test = data;
|
||||
struct sailfish_cell *first_cell;
|
||||
|
||||
DBG("");
|
||||
test->info = fake_cell_info_new();
|
||||
fake_cell_info_add_cell(test->info, &test->cell);
|
||||
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
|
||||
g_assert(test->dbus);
|
||||
test_check_get_cells_reply(call, test->cell_path, NULL);
|
||||
dbus_pending_call_unref(call);
|
||||
|
||||
/* Trigger "PropertyChanged" signal */
|
||||
first_cell = test->info->cells->data;
|
||||
@@ -900,8 +939,24 @@ static void test_property_changed_start(struct test_dbus_context *context)
|
||||
(++(first_cell->info.gsm.signalStrength));
|
||||
fake_cell_info_cells_changed(test->info);
|
||||
|
||||
test_submit_get_all_call(context->client_connection, test->cell_path,
|
||||
test_property_changed_reply1, test);
|
||||
test_submit_get_all_call(test->context.client_connection,
|
||||
test->cell_path, test_property_changed_reply2, test);
|
||||
}
|
||||
|
||||
static void test_property_changed_start(struct test_dbus_context *context)
|
||||
{
|
||||
struct test_property_changed_data *test =
|
||||
G_CAST(context, struct test_property_changed_data, context);
|
||||
|
||||
DBG("");
|
||||
test->info = fake_cell_info_new();
|
||||
fake_cell_info_add_cell(test->info, &test->cell);
|
||||
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
|
||||
g_assert(test->dbus);
|
||||
|
||||
/* Submit GetCells to enable "PropertyChanged" signals */
|
||||
test_submit_cell_info_call(test->context.client_connection, "GetCells",
|
||||
test_property_changed_reply1, test);
|
||||
}
|
||||
|
||||
static void test_property_changed(void)
|
||||
@@ -931,6 +986,106 @@ static void test_property_changed(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== Unsubscribe ==== */
|
||||
|
||||
struct test_unsubscribe_data {
|
||||
struct ofono_modem modem;
|
||||
struct test_dbus_context context;
|
||||
struct sailfish_cell_info *info;
|
||||
struct sailfish_cell_info_dbus *dbus;
|
||||
struct sailfish_cell cell;
|
||||
const char *type;
|
||||
const char *cell_path;
|
||||
};
|
||||
|
||||
static void test_unsubscribe_reply3(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_unsubscribe_data *test = data;
|
||||
|
||||
DBG("");
|
||||
test_check_error(call, OFONO_ERROR_INTERFACE ".Failed");
|
||||
dbus_pending_call_unref(call);
|
||||
|
||||
test_loop_quit_later(test->context.loop);
|
||||
test_dbus_watch_disconnect_all();
|
||||
}
|
||||
|
||||
static void test_unsubscribe_reply2(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_unsubscribe_data *test = data;
|
||||
struct sailfish_cell *first_cell;
|
||||
|
||||
DBG("");
|
||||
test_check_empty_reply(call);
|
||||
dbus_pending_call_unref(call);
|
||||
|
||||
/* No "PropertyChanged" signal is expected because it's disabled */
|
||||
first_cell = test->info->cells->data;
|
||||
test->cell.info.gsm.signalStrength =
|
||||
(++(first_cell->info.gsm.signalStrength));
|
||||
fake_cell_info_cells_changed(test->info);
|
||||
|
||||
/* Submit Unsubscribe and expect and error */
|
||||
test_submit_cell_info_call(test->context.client_connection,
|
||||
"Unsubscribe", test_unsubscribe_reply3, test);
|
||||
}
|
||||
|
||||
static void test_unsubscribe_reply1(DBusPendingCall *call, void *data)
|
||||
{
|
||||
struct test_unsubscribe_data *test = data;
|
||||
|
||||
DBG("");
|
||||
test_check_get_cells_reply(call, test->cell_path, NULL);
|
||||
dbus_pending_call_unref(call);
|
||||
|
||||
/* Submit Unsubscribe to disable "PropertyChanged" signals */
|
||||
test_submit_cell_info_call(test->context.client_connection,
|
||||
"Unsubscribe", test_unsubscribe_reply2, test);
|
||||
}
|
||||
|
||||
static void test_unsubscribe_start(struct test_dbus_context *context)
|
||||
{
|
||||
struct test_unsubscribe_data *test =
|
||||
G_CAST(context, struct test_unsubscribe_data, context);
|
||||
|
||||
DBG("");
|
||||
test->info = fake_cell_info_new();
|
||||
fake_cell_info_add_cell(test->info, &test->cell);
|
||||
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
|
||||
g_assert(test->dbus);
|
||||
|
||||
/* Submit GetCells to enable "PropertyChanged" signals */
|
||||
test_submit_cell_info_call(test->context.client_connection, "GetCells",
|
||||
test_unsubscribe_reply1, test);
|
||||
}
|
||||
|
||||
static void test_unsubscribe(void)
|
||||
{
|
||||
struct test_unsubscribe_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test.modem.path = TEST_MODEM_PATH;
|
||||
test.context.start = test_unsubscribe_start;
|
||||
test_cell_init_gsm1(&test.cell);
|
||||
test.type = "gsm";
|
||||
test.cell_path = "/test/cell_0";
|
||||
test_dbus_setup(&test.context);
|
||||
|
||||
g_main_loop_run(test.context.loop);
|
||||
|
||||
/* We must have received "Unsubscribed" signal */
|
||||
g_assert(test_dbus_find_signal(&test.context, test.modem.path,
|
||||
CELL_INFO_DBUS_INTERFACE, CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL));
|
||||
|
||||
sailfish_cell_info_unref(test.info);
|
||||
sailfish_cell_info_dbus_free(test.dbus);
|
||||
test_dbus_shutdown(&test.context);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_(name) "/sailfish_cell_info_dbus/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -966,6 +1121,7 @@ int main(int argc, char *argv[])
|
||||
g_test_add_func(TEST_("GetProperties"), test_get_properties);
|
||||
g_test_add_func(TEST_("RegisteredChanged"), test_registered_changed);
|
||||
g_test_add_func(TEST_("PropertyChanged"), test_property_changed);
|
||||
g_test_add_func(TEST_("Unsubscribe"), test_unsubscribe);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -491,12 +492,12 @@ static void test_application_entry_decode(void)
|
||||
app[0] = entries->next->data;
|
||||
app[1] = entries->data;
|
||||
|
||||
g_assert(app[0]->aid_len == 0x10);
|
||||
g_assert(!memcmp(app[0]->aid, &ef_dir[4], 0x10));
|
||||
g_assert(app[0]->aid.len == 0x10);
|
||||
g_assert(!memcmp(app[0]->aid.aid, &ef_dir[4], 0x10));
|
||||
g_assert(app[0]->label == NULL);
|
||||
|
||||
g_assert(app[1]->aid_len == 0x0c);
|
||||
g_assert(!memcmp(app[1]->aid, &ef_dir[37], 0x0c));
|
||||
g_assert(app[1]->aid.len == 0x0c);
|
||||
g_assert(!memcmp(app[1]->aid.aid, &ef_dir[37], 0x0c));
|
||||
g_assert(app[1]->label != NULL);
|
||||
g_assert(!strcmp(app[1]->label, "MIDPfiles"));
|
||||
|
||||
@@ -529,32 +530,34 @@ static void test_get_2g_path(void)
|
||||
static void test_auth_build_parse(void)
|
||||
{
|
||||
unsigned char auth_cmd[40];
|
||||
const unsigned char rand[16] = { 0x00, 0x01, 0x02, 0x03, 0x04,0x05,
|
||||
const unsigned char rand[] = { 0x00, 0x01, 0x02, 0x03, 0x04,0x05,
|
||||
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f };
|
||||
const unsigned char sres[4] = { 0x00, 0x11, 0x22, 0x33 };
|
||||
const unsigned char sres[] = { 0x00, 0x11, 0x22, 0x33 };
|
||||
const unsigned char *sres_p;
|
||||
struct data_block sres_b;
|
||||
const unsigned char kc[8] = { 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56,
|
||||
0x78, 0x9a };
|
||||
const unsigned char *kc_p;
|
||||
struct data_block kc_b;
|
||||
const unsigned char gsm_success[] = { 0x04, 0x00, 0x11, 0x22, 0x33,
|
||||
0x08,0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x9a };
|
||||
const unsigned char autn[16] = { 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a,
|
||||
const unsigned char autn[] = { 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a,
|
||||
0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
|
||||
0x01, 0x00 };
|
||||
const unsigned char res[8] = { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa,
|
||||
const unsigned char res[] = { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa,
|
||||
0x11, 0x22 };
|
||||
const unsigned char *res_p;
|
||||
const unsigned char ck[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
|
||||
struct data_block res_b;
|
||||
const unsigned char ck[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
|
||||
0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
|
||||
const unsigned char *ck_p;
|
||||
const unsigned char ik[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd,
|
||||
struct data_block ck_b;
|
||||
const unsigned char ik[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd,
|
||||
0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
|
||||
const unsigned char *ik_p;
|
||||
const unsigned char auts[16] = { 0xde, 0xea, 0xbe, 0xef, 0xde, 0xea,
|
||||
0xbe, 0xef, 0xde, 0xea, 0xbe, 0xef, 0xde, 0xea,
|
||||
0xbe, 0xef };
|
||||
const unsigned char *auts_p;
|
||||
struct data_block ik_b;
|
||||
const unsigned char auts[] = { 0xde, 0xea,
|
||||
0xbe, 0xef, 0xde, 0xea, 0xbe, 0xef, 0xde, 0xea, 0xbe,
|
||||
0xef, 0xde, 0xea };
|
||||
struct data_block auts_b;
|
||||
|
||||
const unsigned char umts_success[] = { 0xdb, 0x08, 0xff, 0xee, 0xdd,
|
||||
0xcc, 0xbb, 0xaa, 0x11, 0x22, 0x10, 0x00, 0x11, 0x22,
|
||||
@@ -572,6 +575,8 @@ static void test_auth_build_parse(void)
|
||||
const unsigned char umts_sync_failure[] = { 0xdc, 0x0e, 0xde, 0xea,
|
||||
0xbe, 0xef, 0xde, 0xea, 0xbe, 0xef, 0xde, 0xea, 0xbe,
|
||||
0xef, 0xde, 0xea };
|
||||
const unsigned char case3[] = { 0x04, 0x01, 0x02, 0x03, 0x04,
|
||||
0x08, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x9a };
|
||||
int len = 0;
|
||||
|
||||
/* test GSM auth command */
|
||||
@@ -606,31 +611,96 @@ static void test_auth_build_parse(void)
|
||||
g_assert(!memcmp(sres_p, sres, 4));
|
||||
g_assert(!memcmp(kc_p, kc, 8));
|
||||
|
||||
/* test truncated messages */
|
||||
g_assert(!sim_parse_umts_authenticate(umts_success, 1,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(umts_success, 2,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(umts_success, 10,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(umts_success, 11,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(umts_success, 27,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(umts_success, 28,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(umts_sync_failure, 2,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(case3, 2,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(case3, 5,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(case3, 6,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
|
||||
/* the extra byte won't actually be accessed */
|
||||
g_assert(!sim_parse_umts_authenticate(umts_success,
|
||||
sizeof(umts_success) + 1,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(umts_sync_failure,
|
||||
sizeof(umts_sync_failure) + 1,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert(!sim_parse_umts_authenticate(case3, sizeof(case3) + 1,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
|
||||
/* unrecognized data */
|
||||
g_assert(!sim_parse_umts_authenticate(case3 + 1, sizeof(case3) - 1,
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
|
||||
/* test UMTS success parse, no kc */
|
||||
g_assert(sim_parse_umts_authenticate(umts_success, sizeof(umts_success),
|
||||
&res_p, &ck_p, &ik_p, &auts_p, &kc_p));
|
||||
g_assert(!memcmp(res_p, res, 8));
|
||||
g_assert(!memcmp(ck_p, ck, 16));
|
||||
g_assert(!memcmp(ik_p, ik, 16));
|
||||
g_assert(!auts_p && !kc_p);
|
||||
&res_b, &ck_b, &ik_b, &auts_b, &sres_b, &kc_b));
|
||||
g_assert_cmpuint(res_b.len, == , sizeof(res));
|
||||
g_assert(!memcmp(res_b.data, res, sizeof(res)));
|
||||
g_assert_cmpuint(ck_b.len, == , sizeof(ck));
|
||||
g_assert(!memcmp(ck_b.data, ck, sizeof(ck)));
|
||||
g_assert_cmpuint(ik_b.len, == , sizeof(ik));
|
||||
g_assert(!memcmp(ik_b.data, ik, sizeof(ik)));
|
||||
g_assert(!sres_b.len && !sres_b.data);
|
||||
g_assert(!auts_b.len && !auts_b.data);
|
||||
g_assert(!kc_b.len && !kc_b.data);
|
||||
|
||||
/* test UMTS sync failure */
|
||||
g_assert(sim_parse_umts_authenticate(umts_sync_failure,
|
||||
sizeof(umts_sync_failure),
|
||||
&res_p, &ck_p, &ik_p, &auts_p,
|
||||
&kc_p));
|
||||
g_assert(!memcmp(auts_p, auts, 14));
|
||||
&res_b, &ck_b, &ik_b, &auts_b,
|
||||
&sres_b, &kc_b));
|
||||
g_assert_cmpuint(auts_b.len, == , sizeof(auts));
|
||||
g_assert(!memcmp(auts_b.data, auts, sizeof(auts)));
|
||||
g_assert(!res_b.len && !res_b.data);
|
||||
g_assert(!ck_b.len && !ck_b.data);
|
||||
g_assert(!ik_b.len && !ik_b.data);
|
||||
g_assert(!sres_b.len && !sres_b.data);
|
||||
g_assert(!kc_b.len && !kc_b.data);
|
||||
|
||||
/* test UMTS success parse, with kc */
|
||||
g_assert(sim_parse_umts_authenticate(umts_success_kc,
|
||||
sizeof(umts_success_kc),
|
||||
&res_p, &ck_p, &ik_p, &auts_p,
|
||||
&kc_p));
|
||||
g_assert(!memcmp(res_p, res, 8));
|
||||
g_assert(!memcmp(ck_p, ck, 16));
|
||||
g_assert(!memcmp(ik_p, ik, 16));
|
||||
g_assert(!memcmp(kc_p, kc, 8));
|
||||
g_assert(!auts_p);
|
||||
&res_b, &ck_b, &ik_b, &auts_b,
|
||||
&sres_b, &kc_b));
|
||||
g_assert_cmpuint(res_b.len, == , sizeof(res));
|
||||
g_assert(!memcmp(res_b.data, res, sizeof(res)));
|
||||
g_assert_cmpuint(ck_b.len, == , sizeof(ck));
|
||||
g_assert(!memcmp(ck_b.data, ck, sizeof(ck)));
|
||||
g_assert_cmpuint(ik_b.len, == , sizeof(ik));
|
||||
g_assert(!memcmp(ik_b.data, ik, sizeof(ik)));
|
||||
g_assert_cmpuint(kc_b.len, == , sizeof(kc));
|
||||
g_assert(!memcmp(kc_b.data, kc, sizeof(kc)));
|
||||
g_assert(!sres_b.len && !sres_b.data);
|
||||
g_assert(!auts_b.len && !auts_b.data);
|
||||
|
||||
/* test case3 */
|
||||
g_assert(sim_parse_umts_authenticate(case3, sizeof(case3),
|
||||
&res_b, &ck_b, &ik_b, &auts_b,
|
||||
&sres_b, &kc_b));
|
||||
g_assert(!res_b.len && !res_b.data);
|
||||
g_assert(!ck_b.len && !ck_b.data);
|
||||
g_assert(!ik_b.len && !ik_b.data);
|
||||
g_assert(!auts_b.len && !auts_b.data);
|
||||
g_assert_cmpuint(sres_b.len, == , 4);
|
||||
g_assert(!memcmp(sres_b.data, case3 + 1, sres_b.len));
|
||||
g_assert_cmpuint(kc_b.len, == , sizeof(kc));
|
||||
g_assert(!memcmp(kc_b.data, kc, sizeof(kc)));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
||||
@@ -130,6 +130,9 @@ systemctl daemon-reload ||:
|
||||
%postun
|
||||
systemctl daemon-reload ||:
|
||||
|
||||
%transfiletriggerin -- %{_libdir}/ofono/plugins
|
||||
systemctl try-restart ofono.service ||:
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%license COPYING
|
||||
|
||||
Reference in New Issue
Block a user