[-]
[+]
|
Changed |
_service:tar_git:ofono.changes
|
|
[-]
[+]
|
Changed |
_service:tar_git:ofono.spec
^
|
|
[-]
[+]
|
Changed |
_service
^
|
@@ -1,7 +1,7 @@
<services>
<service name="tar_git">
<param name="url">https://git.merproject.org/slava/ofono.git</param>
- <param name="branch">optionalmodem</param>
- <param name="revision">81299a0</param>
+ <param name="branch">master</param>
+ <param name="revision">2d18086</param>
</service>
</services>
|
[-]
[+]
|
Deleted |
_service:tar_git:ofono-1.19+git12+optionalmodem.20170515084831.1.g81299a0.tar.bz2/ofono/drivers/ril/ril_mtu.c
^
|
@@ -1,223 +0,0 @@
-/*
- * oFono - Open Source Telephony - RIL-based devices
- *
- * Copyright (C) 2016 Jolla Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "ril_mtu.h"
-#include "ril_log.h"
-
-#include <net/if.h>
-#include <sys/ioctl.h>
-
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-struct ril_mtu_watch {
- int max_mtu;
- char *ifname;
- void *buf;
- int bufsize;
- GIOChannel *channel;
- guint io_watch;
- int fd;
-};
-
-static void ril_mtu_watch_limit_mtu(struct ril_mtu_watch *self)
-{
- int fd = socket(PF_INET, SOCK_DGRAM, 0);
- if (fd >= 0) {
- struct ifreq ifr;
- memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, self->ifname, IFNAMSIZ);
- if (ioctl(fd, SIOCGIFMTU, &ifr) < 0 ||
- ifr.ifr_mtu > self->max_mtu) {
- DBG("%s mtu %d => %d", self->ifname, ifr.ifr_mtu,
- self->max_mtu);
- ifr.ifr_mtu = self->max_mtu;
- if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
- ofono_error("Failed to set MTU");
- }
- }
- close(fd);
- }
-}
-
-static void ril_mtu_watch_handle_rtattr(struct ril_mtu_watch *self,
- const struct rtattr *rta, int len)
-{
- int mtu = 0;
- const char *ifname = NULL;
- while (len > 0 && RTA_OK(rta, len) && (!mtu || !ifname)) {
- switch (rta->rta_type) {
- case IFLA_IFNAME:
- ifname = RTA_DATA(rta);
- break;
- case IFLA_MTU:
- mtu = *((int*)RTA_DATA(rta));
- break;
- }
- rta = RTA_NEXT(rta, len);
- }
- if (mtu > self->max_mtu && !g_strcmp0(ifname, self->ifname)) {
- DBG("%s %d", ifname, mtu);
- ril_mtu_watch_limit_mtu(self);
- }
-}
-
-static void ril_mtu_watch_handle_ifinfomsg(struct ril_mtu_watch *self,
- const struct ifinfomsg *ifi, int len)
-{
- if (ifi->ifi_flags & IFF_UP) {
- const struct rtattr *rta = IFLA_RTA(ifi);
- ril_mtu_watch_handle_rtattr(self, rta,
- len - ((char*)rta - (char*)ifi));
- }
-}
-
-static void ril_mtu_watch_handle_nlmsg(struct ril_mtu_watch *self,
- const struct nlmsghdr *hdr, int len)
-{
- while (len > 0 && NLMSG_OK(hdr, len)) {
- if (hdr->nlmsg_type == RTM_NEWLINK) {
- ril_mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr),
- IFLA_PAYLOAD(hdr));
- }
- hdr = NLMSG_NEXT(hdr, len);
- }
-}
-
-static gboolean ril_mtu_watch_event(GIOChannel *ch, GIOCondition cond,
- gpointer data)
-{
- struct ril_mtu_watch *self = data;
- struct sockaddr_nl addr;
- socklen_t addrlen = sizeof(addr);
- ssize_t result = recvfrom(self->fd, self->buf, self->bufsize, 0,
- (struct sockaddr *)&addr, &addrlen);
- if (result > 0) {
- if (!addr.nl_pid) {
- ril_mtu_watch_handle_nlmsg(self, self->buf, result);
- }
- return G_SOURCE_CONTINUE;
- } else if (result == 0 || errno == EINTR || errno == EAGAIN) {
- return G_SOURCE_CONTINUE;
- } else {
- DBG("%s error %d", self->ifname, errno);
- self->io_watch = 0;
- return G_SOURCE_REMOVE;
- }
-}
-
-static gboolean ril_mtu_watch_open_socket(struct ril_mtu_watch *self)
-{
- GASSERT(self->fd < 0);
- self->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (self->fd >= 0) {
- struct sockaddr_nl nl;
- memset(&nl, 0, sizeof(nl));
- nl.nl_pid = getpid();
- nl.nl_family = AF_NETLINK;
- nl.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
- RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE |
- RTMGRP_LINK;
-
- if (bind(self->fd, (struct sockaddr*)&nl, sizeof(nl)) >= 0) {
- return TRUE;
- }
- close(self->fd);
- self->fd = -1;
- }
- return FALSE;
-}
-
-static gboolean ril_mtu_watch_start(struct ril_mtu_watch *self)
-{
- if (self->fd >= 0) {
- return TRUE;
- } else if (ril_mtu_watch_open_socket(self)) {
- GASSERT(!self->channel);
- GASSERT(!self->io_watch);
- self->channel = g_io_channel_unix_new(self->fd);
- if (self->channel) {
- g_io_channel_set_encoding(self->channel, NULL, NULL);
- g_io_channel_set_buffered(self->channel, FALSE);
- self->io_watch = g_io_add_watch(self->channel,
- G_IO_IN | G_IO_NVAL | G_IO_HUP,
- ril_mtu_watch_event, self);
- return TRUE;
- }
- close(self->fd);
- self->fd = -1;
- }
- return FALSE;
-}
-
-static void ril_mtu_watch_stop(struct ril_mtu_watch *self)
-{
- if (self->io_watch) {
- g_source_remove(self->io_watch);
- self->io_watch = 0;
- }
- if (self->channel) {
- g_io_channel_shutdown(self->channel, TRUE, NULL);
- g_io_channel_unref(self->channel);
- self->channel = NULL;
- }
- if (self->fd >= 0) {
- close(self->fd);
- self->fd = -1;
- }
-}
-
-struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu)
-{
- struct ril_mtu_watch *self = g_new0(struct ril_mtu_watch, 1);
- self->fd = -1;
- self->max_mtu = max_mtu;
- self->bufsize = 4096;
- self->buf = g_malloc(self->bufsize);
- return self;
-}
-
-void ril_mtu_watch_free(struct ril_mtu_watch *self)
-{
- if (self) {
- ril_mtu_watch_stop(self);
- g_free(self->ifname);
- g_free(self->buf);
- g_free(self);
- }
-}
-
-void ril_mtu_watch_set_ifname(struct ril_mtu_watch *self, const char *ifname)
-{
- if (self && g_strcmp0(self->ifname, ifname)) {
- g_free(self->ifname);
- if (ifname) {
- self->ifname = g_strdup(ifname);
- ril_mtu_watch_limit_mtu(self);
- ril_mtu_watch_start(self);
- } else {
- self->ifname = NULL;
- ril_mtu_watch_stop(self);
- }
- }
-}
-
-/*
- * Local Variables:
- * mode: C
- * c-basic-offset: 8
- * indent-tabs-mode: t
- * End:
- */
|
[-]
[+]
|
Deleted |
_service:tar_git:ofono-1.19+git12+optionalmodem.20170515084831.1.g81299a0.tar.bz2/ofono/drivers/ril/ril_mtu.h
^
|
@@ -1,33 +0,0 @@
-/*
- * oFono - Open Source Telephony - RIL-based devices
- *
- * Copyright (C) 2016 Jolla Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef RIL_MTU_H
-#define RIL_MTU_H
-
-#include "ril_types.h"
-
-struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu);
-void ril_mtu_watch_free(struct ril_mtu_watch *mw);
-void ril_mtu_watch_set_ifname(struct ril_mtu_watch *mw, const char *ifname);
-
-#endif /* RIL_MTU_H */
-
-/*
- * Local Variables:
- * mode: C
- * c-basic-offset: 8
- * indent-tabs-mode: t
- * End:
- */
|
[-]
[+]
|
Deleted |
_service:tar_git:ofono-1.19+git12+optionalmodem.20170515084831.1.g81299a0.tar.bz2/ofono/drivers/ril/ril_plugin_dbus.c
^
|
@@ -1,956 +0,0 @@
-/*
- * oFono - Open Source Telephony - RIL-based devices
- *
- * Copyright (C) 2015-2017 Jolla Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "ril_plugin.h"
-
-#include <ofono/log.h>
-#include <ofono/dbus.h>
-
-#include <gutil_strv.h>
-#include <gutil_log.h>
-#include <gdbus.h>
-
-#include "ofono.h"
-
-typedef void (*ril_plugin_dbus_append_fn)(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus);
-typedef gboolean (*ril_plugin_dbus_slot_select_fn)
- (const struct ril_slot_info *slot);
-typedef const char *(*ril_plugin_dbus_slot_string_fn)
- (const struct ril_slot_info *slot);
-
-struct ril_plugin_dbus_request {
- DBusMessage *msg;
- ril_plugin_dbus_append_fn fn;
-};
-
-struct ril_plugin_dbus {
- struct ril_plugin *plugin;
- DBusConnection *conn;
- gboolean block_imei_req;
- GSList *blocked_imei_req;
- guint mms_watch;
-};
-
-#define RIL_DBUS_PATH "/"
-#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
-#define RIL_DBUS_INTERFACE_VERSION (6)
-
-#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
-#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
-#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED "DefaultVoiceSimChanged"
-#define RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED "DefaultDataSimChanged"
-#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED "DefaultVoiceModemChanged"
-#define RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED "DefaultDataModemChanged"
-#define RIL_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
-#define RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
-#define RIL_DBUS_SIGNAL_READY_CHANGED "ReadyChanged"
-#define RIL_DBUS_SIGNAL_MODEM_ERROR "ModemError"
-#define RIL_DBUS_IMSI_AUTO "auto"
-
-#define RIL_DBUS_ERROR_SIGNATURE "si"
-
-static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
-{
- return slot->enabled;
-}
-
-static gboolean ril_plugin_dbus_present(const struct ril_slot_info *slot)
-{
- return slot->sim_present;
-}
-
-static const char *ril_plugin_dbus_imei(const struct ril_slot_info *slot)
-{
- return slot->imei;
-}
-
-static void ril_plugin_dbus_append_path_array(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn selector)
-{
- DBusMessageIter array;
- const struct ril_slot_info *const *ptr = dbus->plugin->slots;
-
- dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
-
- while (*ptr) {
- const struct ril_slot_info *slot = *ptr++;
- if (!selector || selector(slot)) {
- const char *path = slot->path;
- dbus_message_iter_append_basic(&array,
- DBUS_TYPE_OBJECT_PATH, &path);
- }
- }
-
- dbus_message_iter_close_container(it, &array);
-}
-
-static void ril_plugin_dbus_append_string_array(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_string_fn fn)
-{
- DBusMessageIter array;
- const struct ril_slot_info *const *ptr = dbus->plugin->slots;
-
- dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING_AS_STRING, &array);
-
- while (*ptr) {
- const struct ril_slot_info *slot = *ptr++;
- const char *str = fn(slot);
-
- if (!str) str = "";
- dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &str);
- }
-
- dbus_message_iter_close_container(it, &array);
-}
-
-static void ril_plugin_dbus_append_boolean_array(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn value)
-{
- DBusMessageIter array;
- const struct ril_slot_info *const *ptr = dbus->plugin->slots;
-
- dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
- DBUS_TYPE_BOOLEAN_AS_STRING, &array);
-
- while (*ptr) {
- const struct ril_slot_info *slot = *ptr++;
- dbus_bool_t b = value(slot);
-
- dbus_message_iter_append_basic(&array, DBUS_TYPE_BOOLEAN, &b);
- }
-
- dbus_message_iter_close_container(it, &array);
-}
-
-static void ril_plugin_dbus_append_boolean(DBusMessageIter *it, dbus_bool_t b)
-{
- dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &b);
-}
-
-static void ril_plugin_dbus_append_string(DBusMessageIter *it, const char *str)
-{
- if (!str) str = "";
- dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
-}
-
-static void ril_plugin_dbus_append_imsi(DBusMessageIter *it, const char *imsi)
-{
- if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
- dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &imsi);
-}
-
-static void ril_plugin_dbus_append_path(DBusMessageIter *it, const char *path)
-{
- if (!path) path = "";
- /* It's DBUS_TYPE_STRING because DBUS_TYPE_OBJECT_PATH can't be empty */
- dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &path);
-}
-
-static void ril_plugin_dbus_message_append_path_array(DBusMessage *msg,
- struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
-{
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(msg, &iter);
- ril_plugin_dbus_append_path_array(&iter, dbus, fn);
-}
-
-static void ril_plugin_dbus_append_modem_error(DBusMessageIter *it,
- const char *id, dbus_uint32_t count)
-{
- DBusMessageIter sub;
- dbus_message_iter_open_container(it, DBUS_TYPE_STRUCT, NULL, &sub);
- dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id);
- dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &count);
- dbus_message_iter_close_container(it, &sub);
-}
-
-static void ril_plugin_dbus_append_modem_errors(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- DBusMessageIter slots;
- const struct ril_slot_info *const *ptr = dbus->plugin->slots;
-
- dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
- "a(" RIL_DBUS_ERROR_SIGNATURE ")", &slots);
-
- while (*ptr) {
- const struct ril_slot_info *slot = *ptr++;
- DBusMessageIter errors;
-
- dbus_message_iter_open_container(&slots, DBUS_TYPE_ARRAY,
- "(" RIL_DBUS_ERROR_SIGNATURE ")", &errors);
-
- if (g_hash_table_size(slot->errors)) {
- gpointer key, value;
- GHashTableIter iter;
- g_hash_table_iter_init(&iter, slot->errors);
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- ril_plugin_dbus_append_modem_error(&errors,
- key, GPOINTER_TO_INT(value));
- }
- }
-
- dbus_message_iter_close_container(&slots, &errors);
- }
-
- dbus_message_iter_close_container(it, &slots);
-}
-
-static void ril_plugin_dbus_signal_path_array(struct ril_plugin_dbus *dbus,
- const char *name, ril_plugin_dbus_slot_select_fn fn)
-{
- DBusMessage *signal = dbus_message_new_signal(RIL_DBUS_PATH,
- RIL_DBUS_INTERFACE, name);
-
- ril_plugin_dbus_message_append_path_array(signal, dbus, fn);
- g_dbus_send_message(dbus->conn, signal);
-}
-
-static inline void ril_plugin_dbus_signal_imsi(struct ril_plugin_dbus *dbus,
- const char *name, const char *imsi)
-{
- if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
- g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
- name, DBUS_TYPE_STRING, &imsi, DBUS_TYPE_INVALID);
-}
-
-static inline void ril_plugin_dbus_signal_string(struct ril_plugin_dbus *dbus,
- const char *name, const char *str)
-{
- if (!str) str = "";
- g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
- name, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
-}
-
-static inline void ril_plugin_dbus_signal_boolean(struct ril_plugin_dbus *dbus,
- const char *name, dbus_bool_t value)
-{
- g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
- name, DBUS_TYPE_BOOLEAN, &value, DBUS_TYPE_INVALID);
-}
-
-void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask)
-{
- if (dbus) {
- if (mask & RIL_PLUGIN_SIGNAL_VOICE_IMSI) {
- ril_plugin_dbus_signal_imsi(dbus,
- RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
- dbus->plugin->default_voice_imsi);
- }
- if (mask & RIL_PLUGIN_SIGNAL_DATA_IMSI) {
- ril_plugin_dbus_signal_imsi(dbus,
- RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
- dbus->plugin->default_data_imsi);
- }
- if (mask & RIL_PLUGIN_SIGNAL_MMS_IMSI) {
- ril_plugin_dbus_signal_string(dbus,
- RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
- dbus->plugin->mms_imsi);
- }
- if (mask & RIL_PLUGIN_SIGNAL_ENABLED_SLOTS) {
- ril_plugin_dbus_signal_path_array(dbus,
- RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
- ril_plugin_dbus_enabled);
- }
- if (mask & RIL_PLUGIN_SIGNAL_VOICE_PATH) {
- ril_plugin_dbus_signal_string(dbus,
- RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
- dbus->plugin->default_voice_path);
- }
- if (mask & RIL_PLUGIN_SIGNAL_DATA_PATH) {
- ril_plugin_dbus_signal_string(dbus,
- RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
- dbus->plugin->default_data_path);
- }
- if (mask & RIL_PLUGIN_SIGNAL_MMS_PATH) {
- ril_plugin_dbus_signal_string(dbus,
- RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
- dbus->plugin->mms_path);
- }
- if (mask & RIL_PLUGIN_SIGNAL_READY) {
- ril_plugin_dbus_signal_boolean(dbus,
- RIL_DBUS_SIGNAL_READY_CHANGED,
- dbus->plugin->ready);
- }
- }
-}
-
-void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
- gboolean present)
-{
- dbus_bool_t value = present;
- g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
- RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
- DBUS_TYPE_INT32, &index,
- DBUS_TYPE_BOOLEAN, &value,
- DBUS_TYPE_INVALID);
-}
-
-void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
- int index, const char *id, const char *message)
-{
- const char *path = dbus->plugin->slots[index]->path;
- if (!message) message = "";
- g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
- RIL_DBUS_SIGNAL_MODEM_ERROR,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_STRING, &id,
- DBUS_TYPE_STRING, &message,
- DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *ril_plugin_dbus_reply_with_path_array(DBusMessage *msg,
- struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
-{
- DBusMessage *reply = dbus_message_new_method_return(msg);
-
- ril_plugin_dbus_message_append_path_array(reply, dbus, fn);
- return reply;
-}
-
-static DBusMessage *ril_plugin_dbus_reply(DBusMessage *msg,
- struct ril_plugin_dbus *dbus, ril_plugin_dbus_append_fn append)
-{
- DBusMessage *reply = dbus_message_new_method_return(msg);
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(reply, &iter);
- append(&iter, dbus);
- return reply;
-}
-
-static void ril_plugin_dbus_unblock_request(gpointer data, gpointer user_data)
-{
- struct ril_plugin_dbus_request *req = data;
-
- DBG("unblocking IMEI request %p", req);
- __ofono_dbus_pending_reply(&req->msg, ril_plugin_dbus_reply(req->msg,
- (struct ril_plugin_dbus *)user_data, req->fn));
- g_free(req);
-}
-
-static void ril_plugin_dbus_cancel_request(gpointer data)
-{
- struct ril_plugin_dbus_request *req = data;
-
- DBG("canceling IMEI request %p", req);
- __ofono_dbus_pending_reply(&req->msg, __ofono_error_canceled(req->msg));
- g_free(req);
-}
-
-void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
- gboolean block)
-{
- dbus->block_imei_req = block;
- if (!block && dbus->blocked_imei_req) {
- g_slist_foreach(dbus->blocked_imei_req,
- ril_plugin_dbus_unblock_request, dbus);
- g_slist_free(dbus->blocked_imei_req);
- dbus->blocked_imei_req = NULL;
- }
-}
-
-static DBusMessage *ril_plugin_dbus_imei_reply(DBusMessage *msg,
- struct ril_plugin_dbus *dbus, ril_plugin_dbus_append_fn fn)
-{
- if (dbus->block_imei_req) {
- struct ril_plugin_dbus_request *req =
- g_new(struct ril_plugin_dbus_request, 1);
-
- req->msg = dbus_message_ref(msg);
- req->fn = fn;
- dbus->blocked_imei_req = g_slist_append(dbus->blocked_imei_req,
- req);
- DBG("blocking IMEI request %p", req);
- return NULL;
- } else {
- return ril_plugin_dbus_reply(msg, dbus, fn);
- }
-}
-
-static void ril_plugin_dbus_append_version(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- dbus_int32_t version = RIL_DBUS_INTERFACE_VERSION;
-
- dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
-}
-
-static void ril_plugin_dbus_append_all(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- ril_plugin_dbus_append_version(it, dbus);
- ril_plugin_dbus_append_path_array(it, dbus, NULL);
- ril_plugin_dbus_append_path_array(it, dbus, ril_plugin_dbus_enabled);
- ril_plugin_dbus_append_imsi(it, dbus->plugin->default_data_imsi);
- ril_plugin_dbus_append_imsi(it, dbus->plugin->default_voice_imsi);
- ril_plugin_dbus_append_path(it, dbus->plugin->default_data_path);
- ril_plugin_dbus_append_path(it, dbus->plugin->default_voice_path);
-}
-
-static void ril_plugin_dbus_append_all2(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- ril_plugin_dbus_append_all(it, dbus);
- ril_plugin_dbus_append_boolean_array(it, dbus, ril_plugin_dbus_present);
-}
-
-static void ril_plugin_dbus_append_all3(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- ril_plugin_dbus_append_all2(it, dbus);
- ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
-}
-
-static void ril_plugin_dbus_append_all4(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- ril_plugin_dbus_append_all3(it, dbus);
- ril_plugin_dbus_append_string(it, dbus->plugin->mms_imsi);
- ril_plugin_dbus_append_path(it, dbus->plugin->mms_path);
-}
-
-static void ril_plugin_dbus_append_all5(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- ril_plugin_dbus_append_all4(it, dbus);
- ril_plugin_dbus_append_boolean(it, dbus->plugin->ready);
-}
-
-static void ril_plugin_dbus_append_all6(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- ril_plugin_dbus_append_all5(it, dbus);
- ril_plugin_dbus_append_modem_errors(it, dbus);
-}
-
-static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_all);
-}
-
-static DBusMessage *ril_plugin_dbus_get_all2(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_all2);
-}
-
-static DBusMessage *ril_plugin_dbus_get_all3(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_all3);
-}
-
-static DBusMessage *ril_plugin_dbus_get_all4(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_all4);
-}
-
-static DBusMessage *ril_plugin_dbus_get_all5(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_all5);
-}
-
-static DBusMessage *ril_plugin_dbus_get_all6(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_all6);
-}
-
-static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_version);
-}
-
-static DBusMessage *ril_plugin_dbus_get_available_modems(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_reply_with_path_array(msg,
- (struct ril_plugin_dbus *)data, NULL);
-}
-
-static DBusMessage *ril_plugin_dbus_get_enabled_modems(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_reply_with_path_array(msg,
- (struct ril_plugin_dbus *)data, ril_plugin_dbus_enabled);
-}
-
-static void ril_plugin_dbus_append_present_sims(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- ril_plugin_dbus_append_boolean_array(it, dbus, ril_plugin_dbus_present);
-}
-
-static DBusMessage *ril_plugin_dbus_get_present_sims(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_present_sims);
-}
-
-static void ril_plugin_dbus_append_imei_array(DBusMessageIter *it,
- struct ril_plugin_dbus *dbus)
-{
- ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
-}
-
-static DBusMessage *ril_plugin_dbus_get_imei(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_imei_array);
-}
-
-static DBusMessage *ril_plugin_dbus_reply_with_string(DBusMessage *msg,
- const char *str)
-{
- DBusMessage *reply = dbus_message_new_method_return(msg);
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(reply, &iter);
- ril_plugin_dbus_append_string(&iter, str);
- return reply;
-}
-
-static DBusMessage *ril_plugin_dbus_reply_with_imsi(DBusMessage *msg,
- const char *imsi)
-{
- DBusMessage *reply = dbus_message_new_method_return(msg);
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(reply, &iter);
- ril_plugin_dbus_append_imsi(&iter, imsi);
- return reply;
-}
-
-static DBusMessage *ril_plugin_dbus_get_default_data_sim(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
-
- return ril_plugin_dbus_reply_with_imsi(msg,
- dbus->plugin->default_data_imsi);
-}
-
-static DBusMessage *ril_plugin_dbus_get_default_voice_sim(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
-
- return ril_plugin_dbus_reply_with_imsi(msg,
- dbus->plugin->default_voice_imsi);
-}
-
-static DBusMessage *ril_plugin_dbus_get_mms_sim(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
-
- return ril_plugin_dbus_reply_with_string(msg, dbus->plugin->mms_imsi);
-}
-
-static DBusMessage *ril_plugin_dbus_reply_with_path(DBusMessage *msg,
- const char *path)
-{
- DBusMessage *reply = dbus_message_new_method_return(msg);
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(reply, &iter);
- ril_plugin_dbus_append_path(&iter, path);
- return reply;
-}
-
-static DBusMessage *ril_plugin_dbus_get_default_data_modem(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
-
- return ril_plugin_dbus_reply_with_path(msg,
- dbus->plugin->default_data_path);
-}
-
-static DBusMessage *ril_plugin_dbus_get_default_voice_modem(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
-
- return ril_plugin_dbus_reply_with_path(msg,
- dbus->plugin->default_voice_path);
-}
-
-static DBusMessage *ril_plugin_dbus_get_mms_modem(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
-
- return ril_plugin_dbus_reply_with_path(msg, dbus->plugin->mms_path);
-}
-
-static DBusMessage *ril_plugin_dbus_get_ready(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
- DBusMessage *reply = dbus_message_new_method_return(msg);
- DBusMessageIter it;
-
- dbus_message_iter_init_append(reply, &it);
- ril_plugin_dbus_append_boolean(&it, dbus->plugin->ready);
- return reply;
-}
-
-static DBusMessage *ril_plugin_dbus_get_modem_errors(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
- ril_plugin_dbus_append_modem_errors);
-}
-
-static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
- DBusMessageIter iter;
-
- dbus_message_iter_init(msg, &iter);
- if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
- char **paths = NULL;
- DBusMessageIter array;
-
- dbus_message_iter_recurse(&iter, &array);
- while (dbus_message_iter_get_arg_type(&array) ==
- DBUS_TYPE_OBJECT_PATH) {
- DBusBasicValue value;
-
- dbus_message_iter_get_basic(&array, &value);
- paths = gutil_strv_add(paths, value.str);
- dbus_message_iter_next(&array);
- }
-
- ril_plugin_set_enabled_slots(dbus->plugin, paths);
- g_strfreev(paths);
- return dbus_message_new_method_return(msg);
- } else {
- return __ofono_error_invalid_args(msg);
- }
-}
-
-static DBusMessage *ril_plugin_dbus_set_imsi(struct ril_plugin_dbus *dbus,
- DBusMessage *msg, void (*apply)(struct ril_plugin *plugin,
- const char *imsi))
-{
- DBusMessageIter iter;
-
- dbus_message_iter_init(msg, &iter);
- if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
- DBusBasicValue value;
- const char *imsi;
-
- dbus_message_iter_get_basic(&iter, &value);
- imsi = value.str;
- if (!g_strcmp0(imsi, RIL_DBUS_IMSI_AUTO)) imsi = NULL;
- apply(dbus->plugin, imsi);
- return dbus_message_new_method_return(msg);
- } else {
- return __ofono_error_invalid_args(msg);
- }
-}
-
-static DBusMessage *ril_plugin_dbus_set_default_voice_sim(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
-
- GASSERT(conn == dbus->conn);
- return ril_plugin_dbus_set_imsi(dbus, msg,
- ril_plugin_set_default_voice_imsi);
-}
-
-static DBusMessage *ril_plugin_dbus_set_default_data_sim(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
-
- GASSERT(conn == dbus->conn);
- return ril_plugin_dbus_set_imsi(dbus, msg,
- ril_plugin_set_default_data_imsi);
-}
-
-static void ril_plugin_dbus_mms_disconnect(DBusConnection *conn, void *data)
-{
- struct ril_plugin_dbus *dbus = data;
-
- dbus->mms_watch = 0;
- if (dbus->plugin->mms_imsi) {
- DBG("MMS client is gone");
- ril_plugin_set_mms_imsi(dbus->plugin, NULL);
- }
-}
-
-static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessageIter iter;
- struct ril_plugin_dbus *dbus = data;
-
- GASSERT(conn == dbus->conn);
- dbus_message_iter_init(msg, &iter);
- if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
- DBusBasicValue value;
- const char *imsi;
-
- dbus_message_iter_get_basic(&iter, &value);
- imsi = value.str;
-
- /*
- * MMS IMSI is not persistent and has to be eventually
- * reset by the client or cleaned up if the client
- * unexpectedly disappears.
- */
- if (ril_plugin_set_mms_imsi(dbus->plugin, imsi)) {
-
- /*
- * Clear the previous MMS owner
- */
- if (dbus->mms_watch) {
- g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
- dbus->mms_watch = 0;
- }
-
- if (dbus->plugin->mms_imsi &&
- dbus->plugin->mms_imsi[0]) {
- /*
- * This client becomes the owner
- */
- DBG("Owner: %s", dbus_message_get_sender(msg));
- dbus->mms_watch =
- g_dbus_add_disconnect_watch(dbus->conn,
- dbus_message_get_sender(msg),
- ril_plugin_dbus_mms_disconnect,
- dbus, NULL);
- }
-
- return ril_plugin_dbus_reply_with_string(msg,
- dbus->plugin->mms_path);
- } else {
- return __ofono_error_not_available(msg);
- }
- } else {
- return __ofono_error_invalid_args(msg);
- }
-}
-
-/*
- * The client can call GetInterfaceVersion followed by the appropriate
- * GetAllx call to get all settings in two steps. Alternatively, it can
- * call GetAll followed by GetAllx based on the interface version returned
- * by GetAll. In either case, two D-Bus calls are required, unless the
- * client is willing to make the assumption about the ofono version it's
- * talking to.
- */
-
-#define RIL_DBUS_VERSION_ARG {"version", "i"}
-#define RIL_DBUS_AVAILABLE_MODEMS_ARG {"availableModems", "ao"}
-#define RIL_DBUS_ENABLED_MODEMS_ARG {"enabledModems", "ao" }
-#define RIL_DBUS_DEFAULT_DATA_SIM_ARG {"defaultDataSim", "s" }
-#define RIL_DBUS_DEFAULT_VOICE_SIM_ARG {"defaultVoiceSim", "s" }
-#define RIL_DBUS_DEFAULT_DATA_MODEM_ARG {"defaultDataModem", "s" }
-#define RIL_DBUS_DEFAULT_VOICE_MODEM_ARG {"defaultVoiceModem" , "s"}
-#define RIL_DBUS_PRESENT_SIMS_ARG {"presentSims" , "ab"}
-#define RIL_DBUS_IMEI_ARG {"imei" , "as"}
-#define RIL_DBUS_MMS_SIM_ARG {"mmsSim", "s"}
-#define RIL_DBUS_MMS_MODEM_ARG {"mmsModem" , "s"}
-#define RIL_DBUS_READY_ARG {"ready" , "b"}
-#define RIL_DBUS_MODEM_ERRORS_ARG {"errors" , \
- "aa(" RIL_DBUS_ERROR_SIGNATURE ")"}
-#define RIL_DBUS_GET_ALL_ARGS \
- RIL_DBUS_VERSION_ARG, \
- RIL_DBUS_AVAILABLE_MODEMS_ARG, \
- RIL_DBUS_ENABLED_MODEMS_ARG, \
- RIL_DBUS_DEFAULT_DATA_SIM_ARG, \
- RIL_DBUS_DEFAULT_VOICE_SIM_ARG, \
- RIL_DBUS_DEFAULT_DATA_MODEM_ARG, \
- RIL_DBUS_DEFAULT_VOICE_MODEM_ARG
-#define RIL_DBUS_GET_ALL2_ARGS \
- RIL_DBUS_GET_ALL_ARGS, \
- RIL_DBUS_PRESENT_SIMS_ARG
-#define RIL_DBUS_GET_ALL3_ARGS \
- RIL_DBUS_GET_ALL2_ARGS, \
- RIL_DBUS_IMEI_ARG
-#define RIL_DBUS_GET_ALL4_ARGS \
- RIL_DBUS_GET_ALL3_ARGS, \
- RIL_DBUS_MMS_SIM_ARG, \
- RIL_DBUS_MMS_MODEM_ARG
-#define RIL_DBUS_GET_ALL5_ARGS \
- RIL_DBUS_GET_ALL4_ARGS, \
- RIL_DBUS_READY_ARG
-#define RIL_DBUS_GET_ALL6_ARGS \
- RIL_DBUS_GET_ALL5_ARGS, \
- RIL_DBUS_MODEM_ERRORS_ARG
-static const GDBusMethodTable ril_plugin_dbus_methods[] = {
- { GDBUS_METHOD("GetAll",
- NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
- ril_plugin_dbus_get_all) },
- { GDBUS_METHOD("GetAll2",
- NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL2_ARGS),
- ril_plugin_dbus_get_all2) },
- { GDBUS_ASYNC_METHOD("GetAll3",
- NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL3_ARGS),
- ril_plugin_dbus_get_all3) },
- { GDBUS_ASYNC_METHOD("GetAll4",
- NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL4_ARGS),
- ril_plugin_dbus_get_all4) },
- { GDBUS_ASYNC_METHOD("GetAll5",
- NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL5_ARGS),
- ril_plugin_dbus_get_all5) },
- { GDBUS_ASYNC_METHOD("GetAll6",
- NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL6_ARGS),
- ril_plugin_dbus_get_all6) },
- { GDBUS_METHOD("GetInterfaceVersion",
- NULL, GDBUS_ARGS(RIL_DBUS_VERSION_ARG),
- ril_plugin_dbus_get_interface_version) },
- { GDBUS_METHOD("GetAvailableModems",
- NULL, GDBUS_ARGS(RIL_DBUS_AVAILABLE_MODEMS_ARG),
- ril_plugin_dbus_get_available_modems) },
- { GDBUS_METHOD("GetEnabledModems",
- NULL, GDBUS_ARGS(RIL_DBUS_ENABLED_MODEMS_ARG),
- ril_plugin_dbus_get_enabled_modems) },
- { GDBUS_METHOD("GetPresentSims",
- NULL, GDBUS_ARGS(RIL_DBUS_PRESENT_SIMS_ARG),
- ril_plugin_dbus_get_present_sims) },
- { GDBUS_ASYNC_METHOD("GetIMEI",
- NULL, GDBUS_ARGS(RIL_DBUS_IMEI_ARG),
- ril_plugin_dbus_get_imei) },
- { GDBUS_METHOD("GetDefaultDataSim",
- NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG),
- ril_plugin_dbus_get_default_data_sim) },
- { GDBUS_METHOD("GetDefaultVoiceSim",
- NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG),
- ril_plugin_dbus_get_default_voice_sim) },
- { GDBUS_METHOD("GetMmsSim",
- NULL, GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG),
- ril_plugin_dbus_get_mms_sim) },
- { GDBUS_METHOD("GetDefaultDataModem",
- NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG),
- ril_plugin_dbus_get_default_data_modem) },
- { GDBUS_METHOD("GetDefaultVoiceModem",
- NULL, GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG),
- ril_plugin_dbus_get_default_voice_modem) },
- { GDBUS_METHOD("GetMmsModem",
- NULL, GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG),
- ril_plugin_dbus_get_mms_modem) },
- { GDBUS_METHOD("GetReady",
- NULL, GDBUS_ARGS(RIL_DBUS_READY_ARG),
- ril_plugin_dbus_get_ready) },
- { GDBUS_METHOD("GetModemErrors",
- NULL, GDBUS_ARGS(RIL_DBUS_MODEM_ERRORS_ARG),
- ril_plugin_dbus_get_modem_errors) },
- { GDBUS_METHOD("SetEnabledModems",
- GDBUS_ARGS({ "modems", "ao" }), NULL,
- ril_plugin_dbus_set_enabled_modems) },
- { GDBUS_METHOD("SetDefaultDataSim",
- GDBUS_ARGS({ "imsi", "s" }), NULL,
- ril_plugin_dbus_set_default_data_sim) },
- { GDBUS_METHOD("SetDefaultVoiceSim",
- GDBUS_ARGS({ "imsi", "s" }), NULL,
- ril_plugin_dbus_set_default_voice_sim) },
- { GDBUS_METHOD("SetMmsSim",
- GDBUS_ARGS({ "imsi", "s" }), NULL,
- ril_plugin_dbus_set_mms_sim) },
- { }
-};
-
-static const GDBusSignalTable ril_plugin_dbus_signals[] = {
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
- GDBUS_ARGS(RIL_DBUS_ENABLED_MODEMS_ARG)) },
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
- GDBUS_ARGS({"index", "i" },
- {"present" , "b"})) },
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
- GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_SIM_ARG)) },
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
- GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_SIM_ARG)) },
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
- GDBUS_ARGS(RIL_DBUS_DEFAULT_DATA_MODEM_ARG)) },
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
- GDBUS_ARGS(RIL_DBUS_DEFAULT_VOICE_MODEM_ARG)) },
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
- GDBUS_ARGS(RIL_DBUS_MMS_SIM_ARG)) },
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
- GDBUS_ARGS(RIL_DBUS_MMS_MODEM_ARG)) },
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_READY_CHANGED,
- GDBUS_ARGS(RIL_DBUS_READY_ARG)) },
- { GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MODEM_ERROR,
- GDBUS_ARGS({"path","o"},
- {"error_id", "s"},
- {"message", "s"})) },
- { }
-};
-
-struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin)
-{
- struct ril_plugin_dbus *dbus = g_new0(struct ril_plugin_dbus, 1);
-
- dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
- dbus->plugin = plugin;
- if (g_dbus_register_interface(dbus->conn, RIL_DBUS_PATH,
- RIL_DBUS_INTERFACE, ril_plugin_dbus_methods,
- ril_plugin_dbus_signals, NULL, dbus, NULL)) {
- return dbus;
- } else {
- ofono_error("RIL D-Bus register failed");
- ril_plugin_dbus_free(dbus);
- return NULL;
- }
-}
-
-void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus)
-{
- if (dbus) {
- if (dbus->mms_watch) {
- g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
- }
-
- g_slist_free_full(dbus->blocked_imei_req,
- ril_plugin_dbus_cancel_request);
- g_dbus_unregister_interface(dbus->conn, RIL_DBUS_PATH,
- RIL_DBUS_INTERFACE);
- dbus_connection_unref(dbus->conn);
- g_free(dbus);
- }
-}
-
-/*
- * Local Variables:
- * mode: C
- * c-basic-offset: 8
- * indent-tabs-mode: t
- * End:
- */
|
[-]
[+]
|
Deleted |
_service:tar_git:ofono-1.19+git12+optionalmodem.20170515084831.1.g81299a0.tar.bz2/ofono/drivers/ril/ril_sim_info.c
^
|
@@ -1,668 +0,0 @@
-/*
- * oFono - Open Source Telephony - RIL-based devices
- *
- * Copyright (C) 2016 Jolla Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "ril_sim_info.h"
-#include "ril_network.h"
-#include "ril_log.h"
-
-#include <ofono/sim.h>
-
-#include "ofono.h"
-#include "storage.h"
-
-#define RIL_SIM_INFO_STORE "cache"
-#define RIL_SIM_INFO_STORE_GROUP "sim"
-#define RIL_SIM_INFO_STORE_SPN "spn"
-
-/* ICCID -> IMSI map */
-#define RIL_SIM_ICCID_MAP "iccidmap"
-#define RIL_SIM_ICCID_MAP_IMSI "imsi"
-
-#define RIL_SIM_DEFAULT_SPN_BUFSIZE 8
-G_STATIC_ASSERT(RIL_SIM_DEFAULT_SPN_BUFSIZE >= \
- OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1);
-
-typedef GObjectClass RilSimInfoClass;
-typedef struct ril_sim_info RilSimInfo;
-
-typedef void (*ril_sim_info_remove_cb_t)(struct ofono_sim *sim,
- unsigned int id);
-typedef void (*ril_sim_info_set_value_cb_t)(struct ril_sim_info *info,
- const char *value);
-
-struct ril_sim_info_watch {
- ril_sim_info_set_value_cb_t set_value;
- ril_sim_info_remove_cb_t remove;
- struct ril_sim_info *info;
- unsigned int id;
-};
-
-struct ril_sim_info_priv {
- char *log_prefix;
- char *iccid;
- char *imsi;
- char *cached_spn;
- char *sim_spn;
- char *public_spn;
- char default_spn[RIL_SIM_DEFAULT_SPN_BUFSIZE];
- int public_spn_block;
- struct ofono_sim *sim;
- struct ril_sim_info_watch state_watch;
- struct ril_sim_info_watch iccid_watch;
- struct ril_sim_info_watch imsi_watch;
- struct ril_sim_info_watch spn_watch;
- struct ril_network *network;
- gulong network_operator_changed_id;
- gboolean update_imsi_cache;
- gboolean update_iccid_map;
-};
-
-enum ril_sim_info_signal {
- SIGNAL_ICCID_CHANGED,
- SIGNAL_IMSI_CHANGED,
- SIGNAL_SPN_CHANGED,
- SIGNAL_COUNT
-};
-
-#define SIGNAL_ICCID_CHANGED_NAME "ril-sim-info-iccid-changed"
-#define SIGNAL_IMSI_CHANGED_NAME "ril-sim-info-imsi-changed"
-#define SIGNAL_SPN_CHANGED_NAME "ril-sim-info-spn-changed"
-
-static guint ril_sim_info_signals[SIGNAL_COUNT] = { 0 };
-
-G_DEFINE_TYPE(RilSimInfo, ril_sim_info, G_TYPE_OBJECT)
-#define RIL_SIMINFO_TYPE (ril_sim_info_get_type())
-#define RIL_SIMINFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
- RIL_SIMINFO_TYPE, RilSimInfo))
-
-#define NEW_SIGNAL(klass,name) \
- ril_sim_info_signals[SIGNAL_##name##_CHANGED] = \
- g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
- G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
- 0, NULL, NULL, NULL, G_TYPE_NONE, 0)
-
-#define DBG_(info,fmt,args...) DBG("%s" fmt, (info)->priv->log_prefix, ##args)
-
-static void ril_sim_info_signal_emit(struct ril_sim_info *self,
- enum ril_sim_info_signal id)
-{
- g_signal_emit(self, ril_sim_info_signals[id], 0);
-}
-
-static void ril_sim_info_watch_remove(struct ril_sim_info_watch *watch)
-{
- if (watch->id) {
- struct ril_sim_info_priv *priv = watch->info->priv;
-
- GASSERT(priv->sim);
- if (priv->sim) {
- watch->remove(priv->sim, watch->id);
- GASSERT(!watch->id);
- }
-
- watch->id = 0;
- }
-
- if (watch->set_value) {
- watch->set_value(watch->info, NULL);
- }
-}
-
-static void ril_sim_info_remove_spn_watch(struct ofono_sim *sim,
- unsigned int id)
-{
- ofono_sim_remove_spn_watch(sim, &id);
-}
-
-static void ril_sim_info_update_imsi_cache(struct ril_sim_info *self)
-{
- struct ril_sim_info_priv *priv = self->priv;
-
- if (priv->update_imsi_cache && priv->imsi && priv->imsi[0] &&
- priv->cached_spn && priv->cached_spn[0]) {
- gboolean save = FALSE;
- const char *store = RIL_SIM_INFO_STORE;
- GKeyFile *cache = storage_open(priv->imsi, store);
- char *spn = g_key_file_get_string(cache,
- RIL_SIM_INFO_STORE_GROUP,
- RIL_SIM_INFO_STORE_SPN, NULL);
-
- if (g_strcmp0(priv->cached_spn, spn)) {
- save = TRUE;
- g_key_file_set_string(cache, RIL_SIM_INFO_STORE_GROUP,
- RIL_SIM_INFO_STORE_SPN, priv->cached_spn);
- }
-
- /*
- * Since we are most likely running on flash which
- * supports a limited number of writes, don't overwrite
- * the file unless something has actually changed.
- */
- if (save) {
- DBG_(self, "updating " STORAGEDIR "/%s/%s",
- priv->imsi, store);
- storage_close(priv->imsi, store, cache, TRUE);
- } else {
- g_key_file_free(cache);
- }
-
- g_free(spn);
- priv->update_imsi_cache = FALSE;
- }
-}
-
-static void ril_sim_info_update_iccid_map(struct ril_sim_info *self)
-{
- struct ril_sim_info_priv *priv = self->priv;
-
- if (priv->update_iccid_map && priv->iccid && priv->iccid[0] &&
- priv->imsi && priv->imsi[0]) {
- const char *store = RIL_SIM_ICCID_MAP;
- GKeyFile *map = storage_open(NULL, store);
- char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
- priv->iccid, NULL);
-
- /*
- * Since we are most likely running on flash which
- * supports a limited number of writes, don't overwrite
- * the file unless something has actually changed.
- */
- if (g_strcmp0(imsi, priv->imsi)) {
- DBG_(self, "updating " STORAGEDIR "/%s", store);
- g_key_file_set_string(map, RIL_SIM_ICCID_MAP_IMSI,
- priv->iccid, priv->imsi);
- storage_close(NULL, store, map, TRUE);
- } else {
- g_key_file_free(map);
- }
-
- g_free(imsi);
- priv->update_iccid_map = FALSE;
- }
-}
-
-static void ril_sim_info_set_imsi(struct ril_sim_info *self, const char *imsi)
-{
- struct ril_sim_info_priv *priv = self->priv;
-
- if (g_strcmp0(priv->imsi, imsi)) {
- g_free(priv->imsi);
- self->imsi = priv->imsi = g_strdup(imsi);
- priv->update_iccid_map = TRUE;
- ril_sim_info_update_iccid_map(self);
- ril_sim_info_update_imsi_cache(self);
- ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
- }
-}
-
-static void ril_sim_info_update_public_spn(struct ril_sim_info *self)
-{
- struct ril_sim_info_priv *priv = self->priv;
-
- GASSERT(priv->public_spn_block >= 0);
- if (!priv->public_spn_block) {
- const char *spn = priv->sim_spn ? priv->sim_spn :
- priv->cached_spn ? priv->cached_spn :
- priv->default_spn;
-
- if (g_strcmp0(priv->public_spn, spn)) {
- g_free(priv->public_spn);
- self->spn = priv->public_spn = g_strdup(spn);
- ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
- }
- }
-}
-
-static void ril_sim_info_set_cached_spn(struct ril_sim_info *self,
- const char *spn)
-{
- struct ril_sim_info_priv *priv = self->priv;
-
- if (g_strcmp0(priv->cached_spn, spn)) {
- g_free(priv->cached_spn);
- if (spn) {
- DBG_(self, "cached spn \"%s\"", spn);
- priv->cached_spn = g_strdup(spn);
- priv->update_imsi_cache = TRUE;
- ril_sim_info_update_imsi_cache(self);
- } else {
- priv->cached_spn = NULL;
- }
- ril_sim_info_update_public_spn(self);
- }
-}
-
-static void ril_sim_info_set_sim_spn(struct ril_sim_info *self,
- const char *spn)
-{
- struct ril_sim_info_priv *priv = self->priv;
-
- if (g_strcmp0(priv->sim_spn, spn)) {
- g_free(priv->sim_spn);
- priv->sim_spn = g_strdup(spn);
- priv->update_imsi_cache = TRUE;
- ril_sim_info_set_cached_spn(self, spn);
- ril_sim_info_update_imsi_cache(self);
- ril_sim_info_update_public_spn(self);
- }
-}
-
-static void ril_sim_info_update_default_spn(struct ril_sim_info *self)
-{
- struct ril_sim_info_priv *priv = self->priv;
- char buf[RIL_SIM_DEFAULT_SPN_BUFSIZE];
- const char *mcc = NULL;
- const char *mnc = NULL;
-
- if (priv->sim &&
- ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
- mcc = ofono_sim_get_mcc(priv->sim);
- mnc = ofono_sim_get_mnc(priv->sim);
- }
-
- if (mcc && mnc) {
- snprintf(buf, RIL_SIM_DEFAULT_SPN_BUFSIZE, "%s%s", mcc, mnc);
- buf[RIL_SIM_DEFAULT_SPN_BUFSIZE - 1] = 0;
- } else {
- buf[0] = 0;
- }
-
- if (strcmp(buf, priv->default_spn)) {
- strncpy(priv->default_spn, buf, RIL_SIM_DEFAULT_SPN_BUFSIZE);
- DBG_(self, "default spn \"%s\"", priv->default_spn);
- ril_sim_info_update_public_spn(self);
- }
-}
-
-static void ril_sim_info_network_check(struct ril_sim_info *self)
-{
- struct ril_sim_info_priv *priv = self->priv;
-
- if (priv->network && priv->network->operator && priv->sim &&
- ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
- const char *mcc = ofono_sim_get_mcc(priv->sim);
- const char *mnc = ofono_sim_get_mnc(priv->sim);
- const struct ofono_network_operator *op =
- priv->network->operator;
-
- if (mcc && mcc[0] && !strcmp(mcc, op->mcc) &&
- mnc && mnc[0] && !strcmp(mnc, op->mnc)) {
-
- /*
- * If EFspn is present then sim_spn should be set
- * before we get registered with the network.
- */
- DBG_(self, "home network \"%s\"", op->name);
- if (!priv->sim_spn) {
- ril_sim_info_set_cached_spn(self, op->name);
- }
- }
- }
-}
-
-static void ril_sim_info_network_operator_changed(struct ril_network *network,
- void *user_data)
-{
- struct ril_sim_info *self = RIL_SIMINFO(user_data);
-
- DBG_(self, "");
- ril_sim_info_network_check(self);
-}
-
-static void ril_sim_info_load_cache(struct ril_sim_info *self)
-{
- struct ril_sim_info_priv *priv = self->priv;
-
- if (priv->iccid && priv->iccid[0]) {
- GKeyFile *map = storage_open(NULL, RIL_SIM_ICCID_MAP);
- char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
- priv->iccid, NULL);
- g_key_file_free(map);
-
- if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
- if (priv->imsi && priv->imsi[0]) {
- /* Need to update ICCID -> IMSI map */
- DBG_(self, "IMSI changed %s -> %s",
- priv->imsi, imsi);
- priv->update_imsi_cache = TRUE;
- }
- g_free(priv->imsi);
- self->imsi = priv->imsi = imsi;
- DBG_(self, "imsi[%s] = %s", priv->iccid, imsi);
- ril_sim_info_update_iccid_map(self);
- ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
- } else if (imsi) {
- g_free(imsi);
- } else {
- DBG_(self, "no imsi for iccid %s", priv->iccid);
- }
- }
-
- if (priv->imsi && priv->imsi[0]) {
- GKeyFile *cache = storage_open(priv->imsi, RIL_SIM_INFO_STORE);
- char *spn = g_key_file_get_string(cache,
- RIL_SIM_INFO_STORE_GROUP,
- RIL_SIM_INFO_STORE_SPN, NULL);
- g_key_file_free(cache);
-
- if (spn && spn[0] && g_strcmp0(priv->cached_spn, spn)) {
- if (priv->cached_spn && priv->cached_spn[0]) {
- /* Need to update the cache file */
- DBG_(self, "spn changing %s -> %s",
- priv->cached_spn, spn);
- priv->update_imsi_cache = TRUE;
- }
- g_free(priv->cached_spn);
- priv->cached_spn = spn;
- DBG_(self, "spn[%s] = \"%s\"", priv->imsi, spn);
- ril_sim_info_update_imsi_cache(self);
- ril_sim_info_update_public_spn(self);
- } else if (spn) {
- g_free(spn);
- } else {
- DBG_(self, "no spn for imsi %s", priv->imsi);
- }
- }
-}
-
-static void ril_sim_info_set_iccid(struct ril_sim_info *self, const char *iccid)
-{
- struct ril_sim_info_priv *priv = self->priv;
-
- if (g_strcmp0(priv->iccid, iccid)) {
- g_free(priv->iccid);
- self->iccid = priv->iccid = g_strdup(iccid);
- ril_sim_info_signal_emit(self, SIGNAL_ICCID_CHANGED);
- if (iccid) {
- ril_sim_info_load_cache(self);
- }
- }
-}
-
-static void ril_sim_info_imsi_watch_cb(const char *imsi, void *data)
-{
- struct ril_sim_info_watch *watch = data;
-
- DBG_(watch->info, "%s", imsi);
- ril_sim_info_set_imsi(watch->info, imsi);
-}
-
-static void ril_sim_info_spn_watch_cb(const char *spn, const char *dc,
- void *data)
-{
- struct ril_sim_info_watch *watch = data;
-
- DBG_(watch->info, "%s", spn);
- ril_sim_info_set_sim_spn(watch->info, spn);
-}
-
-static void ril_sim_info_iccid_watch_cb(const char *iccid, void *data)
-{
- struct ril_sim_info_watch *watch = data;
-
- DBG_(watch->info, "%s", iccid);
- ril_sim_info_set_iccid(watch->info, iccid);
-}
-
-static void ril_sim_info_watch_done(void *data)
-{
- struct ril_sim_info_watch *watch = data;
-
- GASSERT(watch->id);
- watch->id = 0;
-}
-
-static void ril_sim_info_handle_sim_state(struct ril_sim_info *self,
- enum ofono_sim_state state)
-{
- struct ril_sim_info_priv *priv = self->priv;
- struct ril_sim_info_watch *watch;
-
- DBG_(self, "%d", state);
-
- switch (state) {
- case OFONO_SIM_STATE_READY:
- /* SPN */
- watch = &priv->spn_watch;
- if (!watch->id) {
- ofono_sim_add_spn_watch(priv->sim, &watch->id,
- ril_sim_info_spn_watch_cb, watch,
- ril_sim_info_watch_done);
- GASSERT(priv->spn_watch.id);
- }
- /* IMSI */
- watch = &priv->imsi_watch;
- if (!watch->id) {
- watch->id = ofono_sim_add_imsi_watch(priv->sim,
- ril_sim_info_imsi_watch_cb, watch,
- ril_sim_info_watch_done);
- GASSERT(watch->id);
- }
- /* no break */
- case OFONO_SIM_STATE_INSERTED:
- case OFONO_SIM_STATE_LOCKED_OUT:
- /* ICCID */
- watch = &priv->iccid_watch;
- if (!watch->id) {
- watch->id = ofono_sim_add_iccid_watch(priv->sim,
- ril_sim_info_iccid_watch_cb, watch,
- ril_sim_info_watch_done);
- GASSERT(watch->id);
- }
- break;
- case OFONO_SIM_STATE_NOT_PRESENT:
- case OFONO_SIM_STATE_RESETTING:
- ril_sim_info_watch_remove(&priv->spn_watch);
- ril_sim_info_watch_remove(&priv->imsi_watch);
- ril_sim_info_watch_remove(&priv->iccid_watch);
- break;
- }
-
- ril_sim_info_update_default_spn(self);
- ril_sim_info_network_check(self);
-}
-
-static void ril_sim_info_state_watch_cb(enum ofono_sim_state new_state,
- void *data)
-{
- struct ril_sim_info_watch *watch = data;
- ril_sim_info_handle_sim_state(watch->info, new_state);
-}
-
-struct ril_sim_info *ril_sim_info_new(const char *log_prefix)
-{
- struct ril_sim_info *self = g_object_new(RIL_SIMINFO_TYPE, NULL);
-
- self->priv->log_prefix = (log_prefix && log_prefix[0]) ?
- g_strconcat(log_prefix, " ", NULL) : g_strdup("");
- return self;
-}
-
-struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *self)
-{
- if (G_LIKELY(self)) {
- g_object_ref(RIL_SIMINFO(self));
- return self;
- } else {
- return NULL;
- }
-}
-
-void ril_sim_info_unref(struct ril_sim_info *self)
-{
- if (G_LIKELY(self)) {
- g_object_unref(RIL_SIMINFO(self));
- }
-}
-
-void ril_sim_info_set_ofono_sim(struct ril_sim_info *self,
- struct ofono_sim *sim)
-{
- if (G_LIKELY(self)) {
- struct ril_sim_info_priv *priv = self->priv;
-
- if (priv->sim != sim) {
- priv->public_spn_block++;
- ril_sim_info_watch_remove(&priv->state_watch);
- ril_sim_info_watch_remove(&priv->iccid_watch);
- ril_sim_info_watch_remove(&priv->imsi_watch);
- ril_sim_info_watch_remove(&priv->spn_watch);
-
- priv->update_imsi_cache = FALSE;
- priv->update_iccid_map = FALSE;
- priv->sim = sim;
-
- if (sim) {
- priv->state_watch.id =
- ofono_sim_add_state_watch(sim,
- ril_sim_info_state_watch_cb,
- &priv->state_watch,
- ril_sim_info_watch_done);
- GASSERT(priv->state_watch.id);
- DBG_(self, "attached to sim");
- ril_sim_info_handle_sim_state(self,
- ofono_sim_get_state(sim));
- } else {
- DBG_(self, "detached from sim");
- ril_sim_info_update_default_spn(self);
- ril_sim_info_network_check(self);
- }
-
- priv->public_spn_block--;
- ril_sim_info_update_public_spn(self);
- }
- }
-}
-
-void ril_sim_info_set_network(struct ril_sim_info *self,
- struct ril_network *network)
-{
- if (G_LIKELY(self) && self->priv->network != network) {
- struct ril_sim_info_priv *priv = self->priv;
-
- if (priv->network) {
- ril_network_remove_handlers(priv->network,
- &priv->network_operator_changed_id, 1);
- ril_network_unref(priv->network);
- }
- if (network) {
- priv->network_operator_changed_id =
- ril_network_add_operator_changed_handler(network,
- ril_sim_info_network_operator_changed,
- self);
- priv->network = ril_network_ref(network);
- ril_sim_info_network_check(self);
- } else {
- priv->network = NULL;
- }
- }
-}
-
-gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *self,
- ril_sim_info_cb_t cb, void *arg)
-{
- return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
- SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
-}
-
-gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *self,
- ril_sim_info_cb_t cb, void *arg)
-{
- return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
- SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
-}
-
-gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *self,
- ril_sim_info_cb_t cb, void *arg)
-{
- return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
- SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
-}
-
-void ril_sim_info_remove_handler(struct ril_sim_info *self, gulong id)
-{
- if (G_LIKELY(self) && G_LIKELY(id)) {
- g_signal_handler_disconnect(self, id);
- }
-}
-
-static void ril_sim_info_watch_init(struct ril_sim_info *self,
- struct ril_sim_info_watch *watch,
- ril_sim_info_set_value_cb_t set_value,
- ril_sim_info_remove_cb_t remove)
-{
- watch->info = self;
- watch->set_value = set_value;
- watch->remove = remove;
-}
-
-static void ril_sim_info_init(struct ril_sim_info *self)
-{
- struct ril_sim_info_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
- RIL_SIMINFO_TYPE, struct ril_sim_info_priv);
-
- self->priv = priv;
- ril_sim_info_watch_init(self, &priv->state_watch,
- NULL, ofono_sim_remove_state_watch);
- ril_sim_info_watch_init(self, &priv->iccid_watch,
- ril_sim_info_set_iccid, ofono_sim_remove_iccid_watch);
- ril_sim_info_watch_init(self, &priv->imsi_watch,
- ril_sim_info_set_imsi, ofono_sim_remove_imsi_watch);
- ril_sim_info_watch_init(self, &priv->spn_watch,
- ril_sim_info_set_sim_spn, ril_sim_info_remove_spn_watch);
-}
-
-static void ril_sim_info_dispose(GObject *object)
-{
- struct ril_sim_info *self = RIL_SIMINFO(object);
-
- ril_sim_info_set_ofono_sim(self, NULL);
- ril_sim_info_set_network(self, NULL);
- G_OBJECT_CLASS(ril_sim_info_parent_class)->dispose(object);
-}
-
-static void ril_sim_info_finalize(GObject *object)
-{
- struct ril_sim_info *self = RIL_SIMINFO(object);
- struct ril_sim_info_priv *priv = self->priv;
-
- g_free(priv->log_prefix);
- g_free(priv->cached_spn);
- g_free(priv->public_spn);
- GASSERT(!priv->iccid);
- GASSERT(!priv->imsi);
- GASSERT(!priv->sim_spn);
- G_OBJECT_CLASS(ril_sim_info_parent_class)->finalize(object);
-}
-
-static void ril_sim_info_class_init(RilSimInfoClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
-
- object_class->dispose = ril_sim_info_dispose;
- object_class->finalize = ril_sim_info_finalize;
- g_type_class_add_private(klass, sizeof(struct ril_sim_info_priv));
- NEW_SIGNAL(klass, ICCID);
- NEW_SIGNAL(klass, IMSI);
- NEW_SIGNAL(klass, SPN);
-}
-
-/*
- * Local Variables:
- * mode: C
- * c-basic-offset: 8
- * indent-tabs-mode: t
- * End:
- */
|
[-]
[+]
|
Deleted |
_service:tar_git:ofono-1.19+git12+optionalmodem.20170515084831.1.g81299a0.tar.bz2/ofono/drivers/ril/ril_sim_info_dbus.c
^
|
@@ -1,246 +0,0 @@
-/*
- * oFono - Open Source Telephony - RIL-based devices
- *
- * Copyright (C) 2016-2017 Jolla Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "ril_plugin.h"
-#include "ril_sim_info.h"
-#include "ril_log.h"
-
-#include <gutil_misc.h>
-
-#include <ofono/dbus.h>
-
-#include <gdbus.h>
-
-#include "ofono.h"
-#include "storage.h"
-
-enum sim_info_event_id {
- SIM_INFO_EVENT_ICCID,
- SIM_INFO_EVENT_IMSI,
- SIM_INFO_EVENT_SPN,
- SIM_INFO_EVENT_COUNT
-};
-
-struct ril_sim_info_dbus {
- struct ril_modem *modem;
- struct ril_sim_info *info;
- DBusConnection *conn;
- char *path;
- gulong handler_id[SIM_INFO_EVENT_COUNT];
-};
-
-#define RIL_SIM_INFO_DBUS_INTERFACE "org.nemomobile.ofono.SimInfo"
-#define RIL_SIM_INFO_DBUS_INTERFACE_VERSION (1)
-
-#define RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL "CardIdentifierChanged"
-#define RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL "SubscriberIdentityChanged"
-#define RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL "ServiceProviderNameChanged"
-
-static void ril_sim_info_dbus_append_string(DBusMessageIter *it, const char *s)
-{
- if (!s) s = "";
- dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &s);
-}
-
-static DBusMessage *ril_sim_info_dbus_reply_with_string(DBusMessage *msg,
- const char *str)
-{
- DBusMessage *reply = dbus_message_new_method_return(msg);
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(reply, &iter);
- ril_sim_info_dbus_append_string(&iter, str);
- return reply;
-}
-
-static DBusMessage *ril_sim_info_dbus_get_all(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_sim_info_dbus *dbus = data;
- struct ril_sim_info *info = dbus->info;
- DBusMessage *reply = dbus_message_new_method_return(msg);
- const dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
- ril_sim_info_dbus_append_string(&iter, info->iccid);
- ril_sim_info_dbus_append_string(&iter, info->imsi);
- ril_sim_info_dbus_append_string(&iter, info->spn);
- return reply;
-}
-
-static DBusMessage *ril_sim_info_dbus_get_version(DBusConnection *dc,
- DBusMessage *msg, void *data)
-{
- DBusMessage *reply = dbus_message_new_method_return(msg);
- dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
- return reply;
-}
-
-static DBusMessage *ril_sim_info_dbus_get_iccid(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_sim_info_dbus *dbus = data;
- return ril_sim_info_dbus_reply_with_string(msg, dbus->info->iccid);
-}
-
-static DBusMessage *ril_sim_info_dbus_get_imsi(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_sim_info_dbus *dbus = data;
- return ril_sim_info_dbus_reply_with_string(msg, dbus->info->imsi);
-}
-
-static DBusMessage *ril_sim_info_dbus_get_spn(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct ril_sim_info_dbus *dbus = data;
- return ril_sim_info_dbus_reply_with_string(msg, dbus->info->spn);
-}
-
-#define RIL_SIM_INFO_DBUS_VERSION_ARG {"version", "i"}
-#define RIL_SIM_INFO_DBUS_ICCID_ARG {"iccid", "s"}
-#define RIL_SIM_INFO_DBUS_IMSI_ARG {"imsi", "s"}
-#define RIL_SIM_INFO_DBUS_SPN_ARG {"spn" , "s"}
-
-#define RIL_SIM_INFO_DBUS_GET_ALL_ARGS \
- RIL_SIM_INFO_DBUS_VERSION_ARG, \
- RIL_SIM_INFO_DBUS_ICCID_ARG, \
- RIL_SIM_INFO_DBUS_IMSI_ARG, \
- RIL_SIM_INFO_DBUS_SPN_ARG
-
-static const GDBusMethodTable ril_sim_info_dbus_methods[] = {
- { GDBUS_METHOD("GetAll",
- NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_GET_ALL_ARGS),
- ril_sim_info_dbus_get_all) },
- { GDBUS_METHOD("GetInterfaceVersion",
- NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_VERSION_ARG),
- ril_sim_info_dbus_get_version) },
- { GDBUS_METHOD("GetCardIdentifier",
- NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_ICCID_ARG),
- ril_sim_info_dbus_get_iccid) },
- { GDBUS_METHOD("GetSubscriberIdentity",
- NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_IMSI_ARG),
- ril_sim_info_dbus_get_imsi) },
- { GDBUS_METHOD("GetServiceProviderName",
- NULL, GDBUS_ARGS(RIL_SIM_INFO_DBUS_SPN_ARG),
- ril_sim_info_dbus_get_spn) },
- { }
-};
-
-static const GDBusSignalTable ril_sim_info_dbus_signals[] = {
- { GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
- GDBUS_ARGS(RIL_SIM_INFO_DBUS_ICCID_ARG)) },
- { GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
- GDBUS_ARGS(RIL_SIM_INFO_DBUS_IMSI_ARG)) },
- { GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
- GDBUS_ARGS(RIL_SIM_INFO_DBUS_SPN_ARG)) },
- { }
-};
-
-static void ril_sim_info_dbus_emit(struct ril_sim_info_dbus *dbus,
- const char *signal, const char *value)
-{
- const char *arg = value;
- if (!arg) arg = "";
- g_dbus_emit_signal(dbus->conn, dbus->path, RIL_SIM_INFO_DBUS_INTERFACE,
- signal, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
-}
-
-static void ril_sim_info_dbus_iccid_cb(struct ril_sim_info *info, void *arg)
-{
- ril_sim_info_dbus_emit((struct ril_sim_info_dbus *)arg,
- RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL, info->iccid);
-}
-
-static void ril_sim_info_dbus_imsi_cb(struct ril_sim_info *info, void *arg)
-{
- ril_sim_info_dbus_emit((struct ril_sim_info_dbus *)arg,
- RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL, info->imsi);
-}
-
-static void ril_sim_info_dbus_spn_cb(struct ril_sim_info *info, void *arg)
-{
- ril_sim_info_dbus_emit((struct ril_sim_info_dbus *)arg,
- RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL, info->spn);
-}
-
-struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
- struct ril_sim_info *info)
-{
- struct ril_sim_info_dbus *dbus = g_new0(struct ril_sim_info_dbus, 1);
-
- DBG("%s", ril_modem_get_path(md));
- dbus->modem = md;
- dbus->path = g_strdup(ril_modem_get_path(md));
- dbus->info = ril_sim_info_ref(info);
- dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
-
- /* Register D-Bus interface */
- if (g_dbus_register_interface(dbus->conn, dbus->path,
- RIL_SIM_INFO_DBUS_INTERFACE, ril_sim_info_dbus_methods,
- ril_sim_info_dbus_signals, NULL, dbus, NULL)) {
- ofono_modem_add_interface(md->ofono,
- RIL_SIM_INFO_DBUS_INTERFACE);
-
- dbus->handler_id[SIM_INFO_EVENT_ICCID] =
- ril_sim_info_add_iccid_changed_handler(info,
- ril_sim_info_dbus_iccid_cb, dbus);
- dbus->handler_id[SIM_INFO_EVENT_IMSI] =
- ril_sim_info_add_imsi_changed_handler(info,
- ril_sim_info_dbus_imsi_cb, dbus);
- dbus->handler_id[SIM_INFO_EVENT_SPN] =
- ril_sim_info_add_spn_changed_handler(info,
- ril_sim_info_dbus_spn_cb, dbus);
-
- return dbus;
- } else {
- ofono_error("SimInfo D-Bus register failed");
- ril_sim_info_dbus_free(dbus);
- return NULL;
- }
-}
-
-void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus)
-{
- if (dbus) {
- DBG("%s", dbus->path);
- g_dbus_unregister_interface(dbus->conn, dbus->path,
- RIL_SIM_INFO_DBUS_INTERFACE);
- ofono_modem_remove_interface(dbus->modem->ofono,
- RIL_SIM_INFO_DBUS_INTERFACE);
- dbus_connection_unref(dbus->conn);
-
- gutil_disconnect_handlers(dbus->info, dbus->handler_id,
- G_N_ELEMENTS(dbus->handler_id));
- ril_sim_info_unref(dbus->info);
-
- g_free(dbus->path);
- g_free(dbus);
- }
-}
-
-/*
- * Local Variables:
- * mode: C
- * c-basic-offset: 8
- * indent-tabs-mode: t
- * End:
- */
|
[-]
[+]
|
Deleted |
_service:tar_git:ofono-1.19+git12+optionalmodem.20170515084831.1.g81299a0.tar.bz2/ofono/plugins/push-forwarder.c
^
|
@@ -1,541 +0,0 @@
-/*
- * Copyright (C) 2013-2014 Jolla Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/inotify.h>
-#include <wspcodec.h>
-
-#define OFONO_API_SUBJECT_TO_CHANGE
-#include <ofono.h>
-#include <plugin.h>
-
-/*
- * Push forwarder plugin is looking for configuration files in
- * /etc/ofono/push_forwarder.d directory. Confiration files are
- * glib key files that look like this:
- *
- * [Jolla MMS Handler]
- * ContentType = application/vnd.wap.mms-message
- * Interface = com.jolla.MmsEngine.
- * Service = com.jolla.MmsEngine
- * Method = HandlePush
- * Path = /
- *
- * Only files with .conf suffix are loaded. In addition to the keys
- * from the above example, SourcePort and DestinationPort port keys
- * are supported. All other keys are ignored. One file may describe
- * several push handlers. See pf_parse_config() function for details.
- *
- * When push fowarder receives a WAP push, it goes through the list
- * of registered handlers and invokes all of them that match content
- * type and/or port numbers. The rest is up to the D-Bus service
- * handling the call.
- */
-
-#define PF_CONFIG_DIR CONFIGDIR "/push_forwarder.d"
-
-struct pf_modem {
- struct ofono_modem *modem;
- struct ofono_sms *sms;
- struct ofono_sim *sim;
- unsigned int sim_watch_id;
- unsigned int sms_watch_id;
- unsigned int push_watch_id;
-};
-
-struct push_datagram_handler {
- char *name;
- char *content_type;
- char *interface;
- char *service;
- char *method;
- char *path;
- int dst_port;
- int src_port;
-};
-
-static GSList *handlers;
-static GSList *modems;
-static unsigned int modem_watch_id;
-static int inotify_fd = -1;
-static int inotify_watch_id = -1;
-static guint inotify_watch_source_id;
-static GIOChannel *inotify_watch_channel;
-
-static void pf_notify_handler(struct push_datagram_handler *h,
- const char *imsi, const char *from, const struct tm *remote,
- const struct tm *local, int dst, int src,
- const char *ct, const void *data, unsigned int len)
-{
- struct tm remote_tm = *remote;
- struct tm local_tm = *local;
- dbus_uint32_t remote_time_arg = mktime(&remote_tm);
- dbus_uint32_t local_time_arg = mktime(&local_tm);
- dbus_int32_t dst_arg = dst;
- dbus_int32_t src_arg = src;
- DBusMessageIter iter, array;
- DBusMessage *msg = dbus_message_new_method_call(h->service,
- h->path, h->interface, h->method);
-
- dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &imsi,
- DBUS_TYPE_STRING, &from,
- DBUS_TYPE_UINT32, &remote_time_arg,
- DBUS_TYPE_UINT32, &local_time_arg,
- DBUS_TYPE_INT32, &dst_arg,
- DBUS_TYPE_INT32, &src_arg,
- DBUS_TYPE_STRING, &ct,
- DBUS_TYPE_INVALID);
- dbus_message_iter_init_append(msg, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_BYTE_AS_STRING, &array);
- dbus_message_iter_append_fixed_array(&array,
- DBUS_TYPE_BYTE, &data, len);
- dbus_message_iter_close_container(&iter, &array);
- dbus_message_set_no_reply(msg, TRUE);
- dbus_connection_send(ofono_dbus_get_connection(), msg, NULL);
- dbus_message_unref(msg);
-}
-
-static gboolean pf_match_port(int port, int expected_port)
-{
- if (expected_port < 0)
- return TRUE;
-
- if (expected_port == port)
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean pf_match_handler(struct push_datagram_handler *h,
- const char *ct, int dst, int src)
-{
- if (pf_match_port(dst, h->dst_port) == FALSE)
- return FALSE;
-
- if (pf_match_port(src, h->src_port) == FALSE)
- return FALSE;
-
- if (h->content_type == NULL)
- return TRUE;
-
- if (strcmp(h->content_type, ct) == 0)
- return TRUE;
-
- return FALSE;
-}
-
-static void pf_handle_datagram(const char *from,
- const struct tm *remote, const struct tm *local, int dst,
- int src, const unsigned char *buffer, unsigned int len,
- void *userdata)
-{
- struct pf_modem *pm = userdata;
- guint remain;
- const guint8 *data;
- unsigned int hdrlen;
- unsigned int off;
- const void *ct;
- const char *imsi;
- GSList *link;
-
- DBG("received push of size: %u", len);
-
- if (pm->sim == NULL)
- return;
-
- imsi = ofono_sim_get_imsi(pm->sim);
- if (len < 3)
- return;
-
- if (buffer[1] != 6)
- return;
-
- remain = len - 2;
- data = buffer + 2;
-
- if (wsp_decode_uintvar(data, remain, &hdrlen, &off) == FALSE)
- return;
-
- if ((off + hdrlen) > remain)
- return;
-
- data += off;
- remain -= off;
-
- DBG(" WAP header %u bytes", hdrlen);
-
- if (wsp_decode_content_type(data, hdrlen, &ct, &off, NULL) == FALSE)
- return;
-
- data += hdrlen;
- remain -= hdrlen;
-
- DBG(" content type %s", (char *)ct);
- DBG(" imsi %s", imsi);
- DBG(" data size %u", remain);
-
- link = handlers;
-
- while (link) {
- struct push_datagram_handler *h = link->data;
-
- if (pf_match_handler(h, ct, dst, src) != FALSE) {
- DBG("notifying %s", h->name);
- pf_notify_handler(h, imsi, from, remote, local, dst,
- src, ct, data, remain);
- }
- link = link->next;
- }
-}
-
-static void pf_sms_watch(struct ofono_atom *atom,
- enum ofono_atom_watch_condition cond, void *userdata)
-{
- struct pf_modem *pm = userdata;
-
- if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
- DBG("registered");
- pm->sms = __ofono_atom_get_data(atom);
- pm->push_watch_id = __ofono_sms_datagram_watch_add(pm->sms,
- pf_handle_datagram, -1, -1, pm, NULL);
- } else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
- DBG("unregistered");
- pm->sms = NULL;
- pm->push_watch_id = 0;
- }
-}
-
-static void pf_sms_watch_done(void *userdata)
-{
- struct pf_modem *pm = userdata;
-
- pm->sms_watch_id = 0;
-}
-
-static void pf_sim_watch(struct ofono_atom *atom,
- enum ofono_atom_watch_condition cond, void *userdata)
-{
- struct pf_modem *pm = userdata;
-
- if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
- DBG("registered");
- pm->sim = __ofono_atom_get_data(atom);
- } else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
- DBG("unregistered");
- pm->sim = NULL;
- }
-}
-
-static void pf_sim_watch_done(void *userdata)
-{
- struct pf_modem *pm = userdata;
-
- pm->sim_watch_id = 0;
-}
-
-static void pf_free_modem(struct pf_modem *pm)
-{
- if (pm == NULL)
- return;
-
- if (pm->push_watch_id != 0)
- __ofono_sms_datagram_watch_remove(pm->sms, pm->push_watch_id);
-
- if (pm->sim_watch_id != 0)
- __ofono_modem_remove_atom_watch(pm->modem, pm->sim_watch_id);
-
- if (pm->sms_watch_id != 0)
- __ofono_modem_remove_atom_watch(pm->modem, pm->sms_watch_id);
-
- g_free(pm);
-}
-
-static void pf_modem_watch(struct ofono_modem *modem,
- gboolean added, void *userdata)
-{
- DBG("modem: %p, added: %d", modem, added);
- if (added != FALSE) {
- struct pf_modem *pm;
-
- pm = g_try_new0(struct pf_modem, 1);
- if (pm == NULL)
- return;
-
- pm->modem = modem;
- pm->sms_watch_id = __ofono_modem_add_atom_watch(modem,
- OFONO_ATOM_TYPE_SMS, pf_sms_watch, pm,
- pf_sms_watch_done);
- pm->sim_watch_id = __ofono_modem_add_atom_watch(modem,
- OFONO_ATOM_TYPE_SIM, pf_sim_watch, pm,
- pf_sim_watch_done);
- modems = g_slist_append(modems, pm);
- } else {
- GSList *link = modems;
-
- while (link) {
- struct pf_modem *pm = link->data;
-
- if (pm->modem == modem) {
- modems = g_slist_delete_link(modems, link);
- pf_free_modem(pm);
- break;
- }
- link = link->next;
- }
- }
-}
-
-static void pf_modem_init(struct ofono_modem *modem,
- void *userdata)
-{
- pf_modem_watch(modem, TRUE, NULL);
-}
-
-static void pf_free_handler(void *data)
-{
- struct push_datagram_handler *h = data;
-
- g_free(h->content_type);
- g_free(h->interface);
- g_free(h->service);
- g_free(h->method);
- g_free(h->path);
- g_free(h->name);
- g_free(h);
-}
-
-static void pf_parse_handler(GKeyFile *conf, const char *g)
-{
- GError *err = NULL;
- struct push_datagram_handler *h;
- char *interface;
- char *service;
- char *method;
- char *path;
-
- interface = g_key_file_get_string(conf, g, "Interface", NULL);
- if (interface == NULL)
- goto no_interface;
-
- service = g_key_file_get_string(conf, g, "Service", NULL);
- if (service == NULL)
- goto no_service;
-
- method = g_key_file_get_string(conf, g, "Method", NULL);
- if (method == NULL)
- goto no_method;
-
- path = g_key_file_get_string(conf, g, "Path", NULL);
- if (path == NULL)
- goto no_path;
-
- h = g_try_new0(struct push_datagram_handler, 1);
- if (h == NULL)
- goto no_memory;
-
- h->name = g_strdup(g);
- h->interface = interface;
- h->service = service;
- h->method = method;
- h->path = path;
- h->content_type = g_key_file_get_string(conf, g, "ContentType", NULL);
- h->dst_port = g_key_file_get_integer(conf, g, "DestinationPort", &err);
- if (h->dst_port == 0 && err != NULL) {
- h->dst_port = -1;
- g_error_free(err);
- err = NULL;
- }
- h->src_port = g_key_file_get_integer(conf, g, "SourcePort", &err);
- if (h->src_port == 0 && err != NULL) {
- h->src_port = -1;
- g_error_free(err);
- err = NULL;
- }
- DBG("registered %s", h->name);
- if (h->content_type != NULL)
- DBG(" ContentType: %s", h->content_type);
- if (h->dst_port >= 0)
- DBG(" DestinationPort: %d", h->dst_port);
- if (h->src_port >= 0)
- DBG(" SourcePort: %d", h->src_port);
- DBG(" Interface: %s", interface);
- DBG(" Service: %s", service);
- DBG(" Method: %s", method);
- DBG(" Path: %s", path);
- handlers = g_slist_append(handlers, h);
- return;
-
-no_memory:
- g_free(path);
-
-no_path:
- g_free(method);
-
-no_method:
- g_free(service);
-
-no_service:
- g_free(interface);
-
-no_interface:
- return;
-}
-
-static void pf_parse_config(void)
-{
- GDir *dir;
- const gchar *file;
-
- g_slist_free_full(handlers, pf_free_handler);
- handlers = NULL;
-
- dir = g_dir_open(PF_CONFIG_DIR, 0, NULL);
- if (dir == NULL) {
- DBG(PF_CONFIG_DIR " not found.");
- return;
- }
-
- DBG("loading configuration from " PF_CONFIG_DIR);
- while ((file = g_dir_read_name(dir)) != NULL) {
- GError *err;
- GKeyFile *conf;
- char *path;
-
- if (g_str_has_suffix(file, ".conf") == FALSE)
- continue;
-
- err = NULL;
- conf = g_key_file_new();
- path = g_strconcat(PF_CONFIG_DIR "/", file, NULL);
- DBG("reading %s", file);
-
- if (g_key_file_load_from_file(conf, path, 0, &err) != FALSE) {
- gsize i, n;
- char **names = g_key_file_get_groups(conf, &n);
-
- for (i = 0; i < n; i++)
- pf_parse_handler(conf, names[i]);
- g_strfreev(names);
- } else {
- ofono_warn("%s", err->message);
- g_error_free(err);
- }
-
- g_key_file_free(conf);
- g_free(path);
- }
-
- g_dir_close(dir);
-}
-
-static gboolean pf_inotify(GIOChannel *gio, GIOCondition c, gpointer data)
-{
- int avail;
- gsize len;
- void *buf;
- GError *error;
-
- if (ioctl(inotify_fd, FIONREAD, &avail) < 0)
- return FALSE;
-
- buf = g_try_malloc(avail);
- if (buf == NULL)
- return FALSE;
-
- error = NULL;
- if (g_io_channel_read_chars(gio, buf, avail, &len, &error) !=
- G_IO_STATUS_NORMAL) {
- g_free(buf);
- return FALSE;
- }
-
- pf_parse_config();
- g_free(buf);
- return TRUE;
-}
-
-static int pf_plugin_init(void)
-{
- DBG("");
- pf_parse_config();
- modem_watch_id = __ofono_modemwatch_add(pf_modem_watch, NULL, NULL);
- __ofono_modem_foreach(pf_modem_init, NULL);
- inotify_fd = inotify_init();
- if (inotify_fd < 0)
- return 0;
-
- inotify_watch_id = inotify_add_watch(inotify_fd,
- PF_CONFIG_DIR,
- IN_CLOSE_WRITE | IN_DELETE | IN_MOVE);
- if (inotify_watch_id < 0)
- goto no_inotify_watch_id;
-
- inotify_watch_channel = g_io_channel_unix_new(inotify_fd);
- if (inotify_watch_channel == NULL)
- goto no_inotify_watch_channel;
-
- g_io_channel_set_encoding(inotify_watch_channel, NULL, NULL);
- g_io_channel_set_buffered(inotify_watch_channel, FALSE);
- inotify_watch_source_id = g_io_add_watch(inotify_watch_channel,
- G_IO_IN, pf_inotify, NULL);
- if (inotify_watch_source_id != 0)
- return 0;
-
- g_io_channel_unref(inotify_watch_channel);
- inotify_watch_channel = NULL;
-
-no_inotify_watch_channel:
- inotify_rm_watch(inotify_fd, inotify_watch_id);
- inotify_watch_id = -1;
-
-no_inotify_watch_id:
- close(inotify_fd);
- inotify_fd = -1;
- return 0;
-}
-
-static void pf_plugin_exit(void)
-{
- DBG("");
- __ofono_modemwatch_remove(modem_watch_id);
- modem_watch_id = 0;
- g_slist_free_full(modems, (GDestroyNotify)pf_free_modem);
- modems = NULL;
- g_slist_free_full(handlers, pf_free_handler);
- handlers = NULL;
- if (inotify_watch_source_id == 0)
- return;
-
- g_source_remove(inotify_watch_source_id);
- inotify_watch_source_id = 0;
- g_io_channel_unref(inotify_watch_channel);
- inotify_watch_channel = NULL;
- inotify_rm_watch(inotify_fd, inotify_watch_id);
- inotify_watch_id = -1;
- close(inotify_fd);
- inotify_fd = -1;
-}
-
-OFONO_PLUGIN_DEFINE(push_forwarder, "Push Forwarder Plugin", VERSION,
- OFONO_PLUGIN_PRIORITY_DEFAULT, pf_plugin_init,
- pf_plugin_exit)
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/.gitignore
^
|
@@ -49,6 +49,19 @@
unit/test-*.log
unit/test-*.trs
+unit/test-grilreply
+unit/test-grilrequest
+unit/test-grilunsol
+unit/test-provision
+unit/html
+
+drivers/*/*.gcda
+drivers/*/*.gcno
+drivers/*/*.gcov
+*/*.gcda
+*/*.gcno
+*/*.gcov
+
tools/huawei-audio
tools/auto-enable
tools/get-location
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/Makefile.am
^
|
@@ -27,6 +27,11 @@
nodist_pkginclude_HEADERS = include/version.h
+if SAILFISH_MANAGER
+nodist_pkginclude_HEADERS += include/sailfish_manager.h \
+ include/sailfish_watch.h
+endif
+
local_headers = $(foreach file,$(pkginclude_HEADERS) \
$(nodist_pkginclude_HEADERS), \
include/ofono/$(notdir $(file)))
@@ -116,8 +121,17 @@
builtin_sources += plugins/udevng.c
endif
+if SAILFISH_MANAGER
+builtin_modules += sailfish_manager
+builtin_sources += plugins/sailfish_manager/sailfish_manager.c \
+ plugins/sailfish_manager/sailfish_manager_dbus.c \
+ plugins/sailfish_manager/sailfish_sim_info.c \
+ plugins/sailfish_manager/sailfish_sim_info_dbus.c \
+ plugins/sailfish_manager/sailfish_watch.c
+endif
+
if RILMODEM
-if JOLLA_RILMODEM
+if SAILFISH_RILMODEM
builtin_modules += ril
builtin_sources += drivers/ril/ril_call_barring.c \
@@ -134,20 +148,17 @@
drivers/ril/ril_gprs.c \
drivers/ril/ril_gprs_context.c \
drivers/ril/ril_modem.c \
- drivers/ril/ril_mtu.c \
drivers/ril/ril_netmon.c \
drivers/ril/ril_netreg.c \
drivers/ril/ril_network.c \
drivers/ril/ril_oem_raw.c \
drivers/ril/ril_phonebook.c \
drivers/ril/ril_plugin.c \
- drivers/ril/ril_plugin_dbus.c \
drivers/ril/ril_radio.c \
+ drivers/ril/ril_radio_caps.c \
drivers/ril/ril_radio_settings.c \
drivers/ril/ril_sim.c \
drivers/ril/ril_sim_card.c \
- drivers/ril/ril_sim_info.c \
- drivers/ril/ril_sim_info_dbus.c \
drivers/ril/ril_sim_settings.c \
drivers/ril/ril_sms.c \
drivers/ril/ril_stk.c \
@@ -576,9 +587,9 @@
builtin_modules += hfp_ag_bluez5
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
-if SAILFISHFOS
+if SAILFISH_BT
builtin_modules += sfos_bt
-builtin_sources += plugins/sfos_bt.c
+builtin_sources += plugins/sailfish_bt.c
endif
endif
@@ -593,11 +604,25 @@
builtin_sources += plugins/nettime.c
endif
+if SAILFISH_DEBUGLOG
+builtin_modules += debuglog
+builtin_sources += plugins/sailfish_debuglog.c
+endif
+
+if SAILFISH_PROVISION
+builtin_sources += plugins/sailfish_provision.c
+PROVISION = 1
+else
+if PROVISION
+builtin_sources += plugins/provision.c
+endif
+endif
+
if PROVISION
builtin_sources += plugins/mbpi.h plugins/mbpi.c
builtin_modules += provision
-builtin_sources += plugins/provision.h plugins/provision.c
+builtin_sources += plugins/provision.h
builtin_modules += cdma_provision
builtin_sources += plugins/cdma-provision.c
@@ -635,16 +660,9 @@
builtin_modules += push_notification
builtin_sources += plugins/push-notification.c
-if PUSHFORWARDER
-builtin_modules += push_forwarder
-builtin_sources += plugins/push-forwarder.c
-builtin_cflags += @WSPCODEC_CFLAGS@
-builtin_libadd += @WSPCODEC_LIBS@
-endif
-
-if DEBUGLOG
-builtin_modules += debuglog
-builtin_sources += plugins/debuglog.c
+if SAILFISH_PUSHFORWARDER
+builtin_modules += pushforwarder
+builtin_sources += plugins/sailfish_pushforwarder.c
endif
builtin_modules += sms_history
@@ -656,6 +674,7 @@
sbin_PROGRAMS = src/ofonod
src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
+ src/mtu-watch.c \
src/main.c src/ofono.h src/log.c src/plugin.c \
src/modem.c src/common.h src/common.c \
src/manager.c src/dbus.c src/util.h src/util.c \
@@ -849,6 +868,9 @@
dist_man_MANS = doc/ofonod.8
+if TEST_COVERAGE
+COVERAGE_OPT = --coverage
+endif
unit_objects =
@@ -857,8 +879,33 @@
unit/test-sms unit/test-cdmasms \
unit/test-provision
+if SAILFISH_MANAGER
+
+unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
+ unit/fake_sailfish_watch.c \
+ plugins/sailfish_manager/sailfish_sim_info.c \
+ src/storage.c src/watch.c src/log.c
+unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
+ -DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
+unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
+unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
+unit_tests += unit/test-sailfish_sim_info
+
+unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
+ unit/fake_sailfish_watch.c \
+ plugins/sailfish_manager/sailfish_manager.c \
+ plugins/sailfish_manager/sailfish_sim_info.c \
+ src/storage.c src/log.c
+unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
+ -DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
+unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
+unit_objects += $(unit_test_sailfish_manager_OBJECTS)
+unit_tests += unit/test-sailfish_manager
+
+endif
+
if RILMODEM
-if JOLLA_RILMODEM
+if SAILFISH_RILMODEM
unit_tests += unit/test-rilmodem-cs \
unit/test-rilmodem-cs \
@@ -873,19 +920,23 @@
unit/test-sms-root unit/test-mux unit/test-caif
unit_test_common_SOURCES = unit/test-common.c src/common.c src/util.c
+unit_test_common_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_common_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_common_OBJECTS)
unit_test_util_SOURCES = unit/test-util.c src/util.c
+unit_test_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_util_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_utils_OBJECTS)
unit_test_idmap_SOURCES = unit/test-idmap.c src/idmap.c
+unit_test_idmap_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_idmap_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_idmap_OBJECTS)
unit_test_simutil_SOURCES = unit/test-simutil.c src/util.c \
src/simutil.c src/smsutil.c src/storage.c
+unit_test_simutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_simutil_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_simutil_OBJECTS)
@@ -893,19 +944,23 @@
src/util.c \
src/storage.c src/smsutil.c \
src/simutil.c src/stkutil.c
+unit_test_stkutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_stkutil_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_stkutil_OBJECTS)
unit_test_sms_SOURCES = unit/test-sms.c src/util.c src/smsutil.c src/storage.c
+unit_test_sms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_sms_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_sms_OBJECTS)
unit_test_cdmasms_SOURCES = unit/test-cdmasms.c src/cdma-smsutil.c
+unit_test_cdmasms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_cdmasms_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_cdmasms_OBJECTS)
unit_test_sms_root_SOURCES = unit/test-sms-root.c \
src/util.c src/smsutil.c src/storage.c
+unit_test_sms_root_CFLAGS = -DSTORAGEDIR='"/tmp/ofono"' $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_sms_root_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_sms_root_OBJECTS)
@@ -916,13 +971,15 @@
unit_test_caif_SOURCES = unit/test-caif.c $(gatchat_sources) \
drivers/stemodem/caif_socket.h \
drivers/stemodem/if_caif.h
+unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_caif_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_caif_OBJECTS)
unit_test_provision_SOURCES = unit/test-provision.c \
- plugins/provision.h plugins/provision.c \
- plugins/mbpi.c src/gprs-provision.c \
- src/log.c
+ plugins/provision.h plugins/mbpi.c \
+ plugins/sailfish_provision.c \
+ src/gprs-provision.c src/log.c
+unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_provision_OBJECTS)
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/configure.ac
^
|
@@ -69,6 +69,16 @@
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
+PKG_CHECK_MODULES(GOBJECT, gobject-2.0, dummy=yes,
+ AC_MSG_ERROR(GObject is required))
+GLIB_CFLAGS="$GLIB_CFLAGS $GOBJECT_CFLAGS"
+GLIB_LIBS="$GLIB_LIBS $GOBJECT_LIBS"
+
+PKG_CHECK_MODULES(GIO, gio-2.0, dummy=yes,
+ AC_MSG_ERROR(GIO is required))
+GLIB_CFLAGS="$GLIB_CFLAGS $GIO_CFLAGS"
+GLIB_LIBS="$GLIB_LIBS $GIO_LIBS"
+
if (test "${enable_threads}" = "yes"); then
AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
@@ -167,22 +177,31 @@
[enable_rilmodem=${enableval}])
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
-AC_ARG_ENABLE(jolla-rilmodem,
- AC_HELP_STRING([--enable-jolla-rilmodem], [enable Jolla RIL modem]),
- [enable_jolla_rilmodem=${enableval}], [enable_jolla_rilmodem="no"])
-AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_rilmodem}" != "no")
-
-if (test "${enable_jolla_rilmodem}" = "yes"); then
- PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.6, dummy=yes,
- AC_MSG_ERROR(libgrilio >= 1.0.6 is required))
- PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.5, dummy=yes,
- AC_MSG_ERROR(libglibutil >= 1.0.5 is required))
+AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
+ [enable Sailfish RIL modem]),
+ [enable_sailfish_rilmodem=${enableval}],
+ [enable_sailfish_rilmodem="no"])
+AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
+
+if (test "${enable_sailfish_rilmodem}" = "yes"); then
+ PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.16, dummy=yes,
+ AC_MSG_ERROR(libgrilio >= 1.0.16 is required))
+ PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
+ AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
PKG_CHECK_MODULES(LIBMCE, libmce-glib, dummy=yes,
AC_MSG_ERROR(libmce-glib is required))
- CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS $LIBMCE_CFLAGS"
- LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS $LIBMCE_LIBS"
+ CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
+ LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
+ enable_sailfish_manager=yes
+ need_glibutil=yes
fi
+AC_ARG_ENABLE(sailfish-manager,
+ AC_HELP_STRING([--enable-sailfish-manager],
+ [enable Sailfish OS modem manager plugin]),
+ [enable_sailfish_manager=${enableval}])
+AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
+
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
[don't allow to add or remove connection context over D-Bus]), [
if (test "${enableval}" = "no"); then
@@ -190,6 +209,12 @@
fi
])
+AC_ARG_ENABLE(test-coverage,
+ AC_HELP_STRING([--enable-test-coverage], [enable test code coverage]),
+ [enable_test_coverage=${enableval}],
+ [enable_test_coverage="no"])
+AM_CONDITIONAL(TEST_COVERAGE, test "${enable_test_coverage}" != "no")
+
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
[disable Qualcomm QMI modem support]),
[enable_qmimodem=${enableval}])
@@ -213,9 +238,15 @@
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
-AC_ARG_ENABLE(sailfishos, AC_HELP_STRING([--enable-sailfishos],
- [enable sailfishos plugin]), [enable_sailfishos=${enableval}])
-AM_CONDITIONAL(SAILFISHFOS, test "${enable_sailfishos}" = "yes")
+AC_ARG_ENABLE(sailfish-bt, AC_HELP_STRING([--enable-sailfish-bt],
+ [enable Sailfish OS Bluetooth plugin]),
+ [enable_sailfish_bt=${enableval}])
+AM_CONDITIONAL(SAILFISH_BT, test "${enable_sailfish_bt}" = "yes")
+
+AC_ARG_ENABLE(sailfish-provision, AC_HELP_STRING([--enable-sailfish-provision],
+ [enable Sailfish OS provisioning plugin]),
+ [enable_sailfish_provision=${enableval}])
+AM_CONDITIONAL(SAILFISH_PROVISION, test "${enable_sailfish_provision=$}" = "yes")
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
[disable Nettime plugin]),
@@ -259,28 +290,38 @@
[enable_datafiles=${enableval}])
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
-AC_ARG_ENABLE(pushforwarder, AC_HELP_STRING([--disable-pushforwarder],
- [disable Push Forwarder plugin]),
- [enable_pushforwarder=${enableval}])
-AM_CONDITIONAL(PUSHFORWARDER, test "${enable_pushforwarder}" != "no")
-if (test "${enable_pushforwarder}" != "no"); then
+AC_ARG_ENABLE(sailfish-pushforwarder, AC_HELP_STRING([--enable-sailfish-pushforwarder],
+ [enable Sailfish OS push forwarder plugin]),
+ [enable_sailfish_pushforwarder=${enableval}],
+ [enable_sailfish_pushforwarder="no"])
+AM_CONDITIONAL(SAILFISH_PUSHFORWARDER, test "${enable_sailfish_pushforwarder}" != "no")
+if (test "${enable_sailfish_pushforwarder}" != "no"); then
+ PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.15, dummy=yes,
+ AC_MSG_ERROR(libglibutil >= 1.0.15 is required))
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
- AC_MSG_ERROR(WSP decoder is required))
- AC_SUBST(WSPCODEC_CFLAGS)
- AC_SUBST(WSPCODEC_LIBS)
+ AC_MSG_ERROR(WSP decoder is required))
+ CFLAGS="$CFLAGS $WSPCODEC_CFLAGS"
+ LIBS="$LIBS $WSPCODEC_LIBS"
+ need_glibutil=yes
fi
-AC_ARG_ENABLE(debuglog,
- AC_HELP_STRING([--enable-debuglog], [enable log control plugin]),
- [enable_debuglog=${enableval}], [enable_debuglog="no"])
-AM_CONDITIONAL(DEBUGLOG, test "${enable_debuglog}" != "no")
-if (test "${enable_debuglog}" = "yes"); then
+AC_ARG_ENABLE(sailfish-debuglog, AC_HELP_STRING([--enable-sailfish-debuglog],
+ [enable Sailfish OS debug log plugin]),
+ [enable_sailfish_debuglog=${enableval}],
+ [enable_sailfish_debuglog="no"])
+AM_CONDITIONAL(SAILFISH_DEBUGLOG, test "${enable_sailfish_debuglog}" != "no")
+if (test "${enable_sailfish_debuglog}" = "yes"); then
PKG_CHECK_MODULES(DBUSLOG, libdbuslogserver-dbus, dummy=yes,
AC_MSG_ERROR(libdbuslogserver-dbus is required))
CFLAGS="$CFLAGS $DBUSLOG_CFLAGS"
LIBS="$LIBS $DBUSLOG_LIBS"
fi
+if (test "${need_glibutil}" = "yes"); then
+ CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
+ LIBS="$LIBS $GLIBUTIL_LIBS"
+fi
+
if (test "${prefix}" = "NONE"); then
dnl no prefix and no localstatedir, so default to /var
if (test "$localstatedir" = '${prefix}/var'); then
@@ -295,7 +336,7 @@
else
storagedir="${localstatedir}/lib/ofono"
fi
-AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}",
+AC_DEFINE_UNQUOTED(DEFAULT_STORAGEDIR, "${storagedir}",
[Directory for the storage files])
if (test "$sysconfdir" = '${prefix}/etc'); then
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/atmodem/gprs-context.c
^
|
@@ -247,6 +247,8 @@
/* We only support CHAP and PAP */
switch (ctx->auth_method) {
+ case OFONO_GPRS_AUTH_METHOD_ANY:
+ case OFONO_GPRS_AUTH_METHOD_NONE:
case OFONO_GPRS_AUTH_METHOD_CHAP:
gcd->auth_method = G_AT_PPP_AUTH_METHOD_CHAP;
break;
@@ -294,6 +296,8 @@
* prefix, this is the least invasive place to set it.
*/
switch (ctx->auth_method) {
+ case OFONO_GPRS_AUTH_METHOD_ANY:
+ case OFONO_GPRS_AUTH_METHOD_NONE:
case OFONO_GPRS_AUTH_METHOD_CHAP:
snprintf(buf + len, sizeof(buf) - len - 3,
",\"CHAP:%s\"", ctx->apn);
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_call_barring.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
-#include "ril_constants.h"
#include "common.h"
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_call_forward.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015-2016 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
-#include "ril_constants.h"
#include "common.h"
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_call_settings.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
-#include "ril_constants.h"
#include "common.h"
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_call_volume.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
-#include "ril_constants.h"
struct ril_call_volume {
struct ofono_call_volume *v;
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_cbs.c
^
|
@@ -184,11 +184,14 @@
cd->q = grilio_queue_new(cd->io);
/*
- * RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup.
- * We may have to retry a few times.
+ * RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup
+ * especially if other RIL requests are running in parallel. We may
+ * have to retry a few times. Also, make it blocking in order to
+ * improve the chance of success.
*/
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
RIL_CBS_CHECK_RETRY_COUNT);
+ grilio_request_set_blocking(req, TRUE);
grilio_queue_send_request_full(cd->q, req,
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
ril_cbs_probe_done_cb, NULL, cd);
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_cell_info_dbus.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2016 Jolla Ltd.
+ * Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -28,7 +28,6 @@
};
struct ril_cell_info_dbus {
- struct ril_modem *md;
struct ril_cell_info *info;
DBusConnection *conn;
char *path;
@@ -523,7 +522,6 @@
struct ril_cell_info_dbus *dbus = g_new0(struct ril_cell_info_dbus, 1);
DBG("%s", ril_modem_get_path(md));
- dbus->md = md;
dbus->path = g_strdup(ril_modem_get_path(md));
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
dbus->info = ril_cell_info_ref(info);
@@ -553,8 +551,6 @@
DBG("%s", dbus->path);
g_dbus_unregister_interface(dbus->conn, dbus->path,
RIL_CELL_INFO_DBUS_INTERFACE);
- ofono_modem_remove_interface(dbus->md->ofono,
- RIL_CELL_INFO_DBUS_INTERFACE);
/* Unregister cells */
l = dbus->entries;
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_config.c
^
|
@@ -14,6 +14,7 @@
*/
#include "ril_config.h"
+#include "ril_log.h"
#include <gutil_intarray.h>
#include <gutil_ints.h>
@@ -134,6 +135,50 @@
}
}
+gboolean ril_config_get_enum(GKeyFile *file, const char *group,
+ const char *key, int *result,
+ const char *name, int value, ...)
+{
+ char *str = ril_config_get_string(file, group, key);
+
+ if (str) {
+ /*
+ * Some people are thinking that # is a comment
+ * anywhere on the line, not just at the beginning
+ */
+ char *comment = strchr(str, '#');
+
+ if (comment) *comment = 0;
+ g_strstrip(str);
+ if (strcasecmp(str, name)) {
+ va_list args;
+ va_start(args, value);
+ while ((name = va_arg(args, char*)) != NULL) {
+ value = va_arg(args, int);
+ if (!strcasecmp(str, name)) {
+ break;
+ }
+ }
+ va_end(args);
+ }
+
+ if (!name) {
+ ofono_error("Invalid %s config value (%s)", key, str);
+ }
+
+ g_free(str);
+
+ if (name) {
+ if (result) {
+ *result = value;
+ }
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key)
{
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_config.h
^
|
@@ -32,6 +32,9 @@
const char *key, gboolean *value);
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
const char *key, int flag, int *flags);
+gboolean ril_config_get_enum(GKeyFile *file, const char *group,
+ const char *key, int *result,
+ const char *name, int value, ...);
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key);
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_constants.h
^
|
@@ -19,37 +19,70 @@
#ifndef __RIL_CONSTANTS_H
#define __RIL_CONSTANTS_H 1
+#define RIL_MAX_UUID_LENGTH 64
+
/* Error Codes */
-#define RIL_E_SUCCESS 0
-#define RIL_E_RADIO_NOT_AVAILABLE 1
-#define RIL_E_GENERIC_FAILURE 2
-#define RIL_E_PASSWORD_INCORRECT 3
-#define RIL_E_SIM_PIN2 4
-#define RIL_E_SIM_PUK2 5
-#define RIL_E_REQUEST_NOT_SUPPORTED 6
-#define RIL_E_CANCELLED 7
-#define RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL 8
-#define RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW 9
-#define RIL_E_SMS_SEND_FAIL_RETRY 10
-#define RIL_E_SIM_ABSENT 11
-#define RIL_E_SUBSCRIPTION_NOT_AVAILABLE 12
-#define RIL_E_MODE_NOT_SUPPORTED 13
-#define RIL_E_FDN_CHECK_FAILURE 14
-#define RIL_E_ILLEGAL_SIM_OR_ME 15
-#define RIL_E_UNUSED 16
-#define RIL_E_DIAL_MODIFIED_TO_USSD 17
-#define RIL_E_DIAL_MODIFIED_TO_SS 18
-#define RIL_E_DIAL_MODIFIED_TO_DIAL 19
-#define RIL_E_USSD_MODIFIED_TO_DIAL 20
-#define RIL_E_USSD_MODIFIED_TO_SS 21
-#define RIL_E_USSD_MODIFIED_TO_USSD 22
-#define RIL_E_SS_MODIFIED_TO_DIAL 23
-#define RIL_E_SS_MODIFIED_TO_USSD 24
-#define RIL_E_SS_MODIFIED_TO_SS 25
-#define RIL_E_SUBSCRIPTION_NOT_SUPPORTED 26
-#define RIL_E_MISSING_RESOURCE 27
-#define RIL_E_NO_SUCH_ELEMENT 28
-#define RIL_E_INVALID_PARAMETER 29
+enum ril_status {
+ RIL_E_SUCCESS = 0,
+ RIL_E_RADIO_NOT_AVAILABLE = 1,
+ RIL_E_GENERIC_FAILURE = 2,
+ RIL_E_PASSWORD_INCORRECT = 3,
+ RIL_E_SIM_PIN2 = 4,
+ RIL_E_SIM_PUK2 = 5,
+ RIL_E_REQUEST_NOT_SUPPORTED = 6,
+ RIL_E_CANCELLED = 7,
+ RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
+ RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
+ RIL_E_SMS_SEND_FAIL_RETRY = 10,
+ RIL_E_SIM_ABSENT = 11,
+ RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
+ RIL_E_MODE_NOT_SUPPORTED = 13,
+ RIL_E_FDN_CHECK_FAILURE = 14,
+ RIL_E_ILLEGAL_SIM_OR_ME = 15,
+ RIL_E_MISSING_RESOURCE = 16,
+ RIL_E_NO_SUCH_ELEMENT = 17,
+ RIL_E_DIAL_MODIFIED_TO_USSD = 18,
+ RIL_E_DIAL_MODIFIED_TO_SS = 19,
+ RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
+ RIL_E_USSD_MODIFIED_TO_DIAL = 21,
+ RIL_E_USSD_MODIFIED_TO_SS = 22,
+ RIL_E_USSD_MODIFIED_TO_USSD = 23,
+ RIL_E_SS_MODIFIED_TO_DIAL = 24,
+ RIL_E_SS_MODIFIED_TO_USSD = 25,
+ RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
+ RIL_E_SS_MODIFIED_TO_SS = 27,
+ RIL_E_LCE_NOT_SUPPORTED = 36,
+ RIL_E_NO_MEMORY = 37,
+ RIL_E_INTERNAL_ERR = 38,
+ RIL_E_SYSTEM_ERR = 39,
+ RIL_E_MODEM_ERR = 40,
+ RIL_E_INVALID_STATE = 41,
+ RIL_E_NO_RESOURCES = 42,
+ RIL_E_SIM_ERR = 43,
+ RIL_E_INVALID_ARGUMENTS = 44,
+ RIL_E_INVALID_SIM_STATE = 45,
+ RIL_E_INVALID_MODEM_STATE = 46,
+ RIL_E_INVALID_CALL_ID = 47,
+ RIL_E_NO_SMS_TO_ACK = 48,
+ RIL_E_NETWORK_ERR = 49,
+ RIL_E_REQUEST_RATE_LIMITED = 50,
+ RIL_E_SIM_BUSY = 51,
+ RIL_E_SIM_FULL = 52,
+ RIL_E_NETWORK_REJECT = 53,
+ RIL_E_OPERATION_NOT_ALLOWED = 54,
+ RIL_E_EMPTY_RECORD = 55,
+ RIL_E_INVALID_SMS_FORMAT = 56,
+ RIL_E_ENCODING_ERR = 57,
+ RIL_E_INVALID_SMSC_ADDRESS = 58,
+ RIL_E_NO_SUCH_ENTRY = 59,
+ RIL_E_NETWORK_NOT_READY = 60,
+ RIL_E_NOT_PROVISIONED = 61,
+ RIL_E_NO_SUBSCRIPTION = 62,
+ RIL_E_NO_NETWORK_FOUND = 63,
+ RIL_E_DEVICE_IN_USE = 64,
+ RIL_E_ABORTED = 65,
+ RIL_E_INVALID_RESPONSE = 66
+};
/* call states */
enum ril_call_state {
@@ -113,7 +146,60 @@
RADIO_TECH_HSPAP = 15,
RADIO_TECH_GSM = 16,
RADIO_TECH_TD_SCDMA = 17,
- RADIO_TECH_IWLAN = 18
+ RADIO_TECH_IWLAN = 18,
+ RADIO_TECH_LTE_CA = 19
+};
+
+/* Radio capabilities */
+enum ril_radio_access_family {
+ RAF_GPRS = (1 << RADIO_TECH_GPRS),
+ RAF_EDGE = (1 << RADIO_TECH_EDGE),
+ RAF_UMTS = (1 << RADIO_TECH_UMTS),
+ RAF_IS95A = (1 << RADIO_TECH_IS95A),
+ RAF_IS95B = (1 << RADIO_TECH_IS95B),
+ RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
+ RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
+ RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
+ RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
+ RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
+ RAF_HSPA = (1 << RADIO_TECH_HSPA),
+ RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
+ RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
+ RAF_LTE = (1 << RADIO_TECH_LTE),
+ RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
+ RAF_GSM = (1 << RADIO_TECH_GSM),
+ RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
+ RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
+};
+
+enum ril_radio_capability_phase {
+ RC_PHASE_CONFIGURED = 0,
+ RC_PHASE_START = 1,
+ RC_PHASE_APPLY = 2,
+ RC_PHASE_UNSOL_RSP = 3,
+ RC_PHASE_FINISH = 4
+};
+
+enum ril_radio_capability_status {
+ RC_STATUS_NONE = 0,
+ RC_STATUS_SUCCESS = 1,
+ RC_STATUS_FAIL = 2
+};
+
+#define RIL_RADIO_CAPABILITY_VERSION 1
+
+struct ril_radio_capability {
+ int version;
+ int session;
+ enum ril_radio_capability_phase phase;
+ enum ril_radio_access_family rat;
+ char logicalModemUuid[RIL_MAX_UUID_LENGTH];
+ int status;
+};
+
+enum ril_uicc_subscription_action {
+ RIL_UICC_SUBSCRIPTION_DEACTIVATE = 0,
+ RIL_UICC_SUBSCRIPTION_ACTIVATE = 1
};
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_data.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2016 Jolla Ltd.
+ * Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -27,9 +27,7 @@
#include <grilio_parser.h>
#include <grilio_request.h>
-#define SETUP_DATA_CALL_PARAMS 7
#define DATA_PROFILE_DEFAULT_STR "0"
-#define DEACTIVATE_DATA_CALL_PARAMS 2
#define PROTO_IP_STR "IP"
#define PROTO_IPV6_STR "IPV6"
@@ -170,9 +168,9 @@
int cid;
};
-struct ril_data_request_2g {
+struct ril_data_request_allow_data {
struct ril_data_request req;
- gulong handler_id;
+ gboolean allow;
};
static void ril_data_manager_check_data(struct ril_data_manager *dm);
@@ -185,6 +183,26 @@
}
/*==========================================================================*
+ * RIL requests
+ *==========================================================================*/
+
+GRilIoRequest *ril_request_allow_data_new(gboolean allow)
+{
+ return grilio_request_array_int32_new(1, allow);
+}
+
+GRilIoRequest *ril_request_deactivate_data_call_new(int cid)
+{
+ GRilIoRequest *req = grilio_request_new();
+
+ grilio_request_append_int32(req, 2 /* Parameter count */);
+ grilio_request_append_format(req, "%d", cid);
+ grilio_request_append_format(req, "%d",
+ RIL_DEACTIVATE_DATA_CALL_NO_REASON);
+ return req;
+}
+
+/*==========================================================================*
* ril_data_call
*==========================================================================*/
@@ -787,8 +805,8 @@
G_CAST(req, struct ril_data_request_setup, req);
struct ril_data_priv *priv = req->data->priv;
const char *proto_str = ril_data_ofono_protocol_to_ril(setup->proto);
- GRilIoRequest* ioreq;
- int tech, auth;
+ GRilIoRequest *ioreq;
+ int tech, auth = RIL_AUTH_NONE;
GASSERT(proto_str);
@@ -811,21 +829,29 @@
tech = RADIO_TECH_HSPA;
}
- /*
- * We do the same as in $AOSP/frameworks/opt/telephony/src/java/com/
- * android/internal/telephony/dataconnection/DataConnection.java,
- * onConnect(), and use authentication or not depending on whether
- * the user field is empty or not.
- */
- auth = (setup->username && setup->username[0]) ?
- RIL_AUTH_BOTH : RIL_AUTH_NONE;
+ if (setup->username && setup->username[0]) {
+ switch (setup->auth_method) {
+ case OFONO_GPRS_AUTH_METHOD_ANY:
+ auth = RIL_AUTH_BOTH;
+ break;
+ case OFONO_GPRS_AUTH_METHOD_NONE:
+ auth = RIL_AUTH_NONE;
+ break;
+ case OFONO_GPRS_AUTH_METHOD_CHAP:
+ auth = RIL_AUTH_CHAP;
+ break;
+ case OFONO_GPRS_AUTH_METHOD_PAP:
+ auth = RIL_AUTH_PAP;
+ break;
+ }
+ }
/*
* TODO: add comments about tethering, other non-public
* profiles...
*/
ioreq = grilio_request_new();
- grilio_request_append_int32(ioreq, SETUP_DATA_CALL_PARAMS);
+ grilio_request_append_int32(ioreq, 7 /* Parameter count */);
grilio_request_append_format(ioreq, "%d", tech);
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
grilio_request_append_utf8(ioreq, setup->apn);
@@ -924,6 +950,10 @@
ril_data_call_free(call);
ril_data_signal_emit(data, SIGNAL_CALLS_CHANGED);
}
+ } else {
+ /* Something seems to be slightly broken, request the
+ * current state */
+ ril_data_poll_call_state(data);
}
if (req->cb.deact) {
@@ -938,12 +968,8 @@
struct ril_data_request_deact *deact =
G_CAST(req, struct ril_data_request_deact, req);
struct ril_data_priv *priv = req->data->priv;
- GRilIoRequest* ioreq = grilio_request_new();
-
- grilio_request_append_int32(ioreq, DEACTIVATE_DATA_CALL_PARAMS);
- grilio_request_append_format(ioreq, "%d", deact->cid);
- grilio_request_append_format(ioreq, "%d",
- RIL_DEACTIVATE_DATA_CALL_NO_REASON);
+ GRilIoRequest *ioreq =
+ ril_request_deactivate_data_call_new(deact->cid);
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
RIL_REQUEST_DEACTIVATE_DATA_CALL,
@@ -975,15 +1001,6 @@
* ril_data_allow_request
*==========================================================================*/
-static GRilIoRequest *ril_data_allow_req(gboolean allow)
-{
- GRilIoRequest *req = grilio_request_sized_new(8);
-
- grilio_request_append_int32(req, 1);
- grilio_request_append_int32(req, allow != FALSE);
- return req;
-}
-
static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
const void *req_data, guint len, void *user_data)
{
@@ -993,13 +1010,22 @@
ril_data_request_completed(req);
- if (ril_status == RIL_E_SUCCESS &&
- (priv->flags & RIL_DATA_FLAG_ALLOWED)) {
- GASSERT(!ril_data_allowed(data));
- priv->flags |= RIL_DATA_FLAG_ON;
- GASSERT(ril_data_allowed(data));
- DBG_(data, "data on");
- ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
+ if (ril_status == RIL_E_SUCCESS) {
+ const gboolean was_allowed = ril_data_allowed(data);
+ struct ril_data_request_allow_data *ad =
+ G_CAST(req, struct ril_data_request_allow_data, req);
+
+ if (ad->allow) {
+ priv->flags |= RIL_DATA_FLAG_ON;
+ DBG_(data, "data on");
+ } else {
+ priv->flags &= ~RIL_DATA_FLAG_ON;
+ DBG_(data, "data off");
+ }
+
+ if (ril_data_allowed(data) != was_allowed) {
+ ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
+ }
}
ril_data_request_finish(req);
@@ -1007,25 +1033,32 @@
static gboolean ril_data_allow_submit(struct ril_data_request *req)
{
- GRilIoRequest *ioreq = ril_data_allow_req(TRUE);
+ struct ril_data_request_allow_data *ad =
+ G_CAST(req, struct ril_data_request_allow_data, req);
+ GRilIoRequest *ioreq = ril_request_allow_data_new(ad->allow);
struct ril_data_priv *priv = req->data->priv;
grilio_request_set_retry(ioreq, RIL_RETRY_SECS*1000, -1);
+ grilio_request_set_blocking(ioreq, TRUE);
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
RIL_REQUEST_ALLOW_DATA, ril_data_allow_cb, NULL, req);
grilio_request_unref(ioreq);
return TRUE;
}
-static struct ril_data_request *ril_data_allow_new(struct ril_data *data)
+static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
+ gboolean allow)
{
- struct ril_data_request *req = g_new0(struct ril_data_request, 1);
+ struct ril_data_request_allow_data *ad =
+ g_new0(struct ril_data_request_allow_data, 1);
+ struct ril_data_request *req = &ad->req;
req->name = "ALLOW_DATA";
req->data = data;
req->submit = ril_data_allow_submit;
req->cancel = ril_data_request_cancel_io;
req->flags = DATA_REQUEST_FLAG_CANCEL_WHEN_DISALLOWED;
+ ad->allow = allow;
return req;
}
@@ -1080,12 +1113,11 @@
struct ril_data *self = g_object_new(RIL_DATA_TYPE, NULL);
struct ril_data_priv *priv = self->priv;
struct ril_sim_settings *settings = network->settings;
- GRilIoRequest *req = grilio_request_new();
priv->options = *options;
switch (priv->options.allow_data) {
- case RIL_ALLOW_DATA_ON:
- case RIL_ALLOW_DATA_OFF:
+ case RIL_ALLOW_DATA_ENABLED:
+ case RIL_ALLOW_DATA_DISABLED:
break;
default:
/*
@@ -1093,7 +1125,8 @@
* RIL_VERSION was 10
*/
priv->options.allow_data = (io->ril_version > 10) ?
- RIL_ALLOW_DATA_ON : RIL_ALLOW_DATA_OFF;
+ RIL_ALLOW_DATA_ENABLED :
+ RIL_ALLOW_DATA_DISABLED;
break;
}
@@ -1118,12 +1151,7 @@
ril_data_settings_changed, self);
/* Request the current state */
- grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
- priv->query_id = grilio_queue_send_request_full(priv->q, req,
- RIL_REQUEST_DATA_CALL_LIST,
- ril_data_query_data_calls_cb,
- NULL, self);
- grilio_request_unref(req);
+ ril_data_poll_call_state(self);
/* Order data contexts according to slot numbers */
dm->data_list = g_slist_insert_sorted(dm->data_list, self,
@@ -1134,6 +1162,25 @@
return NULL;
}
+void ril_data_poll_call_state(struct ril_data *self)
+{
+ if (G_LIKELY(self)) {
+ struct ril_data_priv *priv = self->priv;
+
+ if (!priv->query_id) {
+ GRilIoRequest *req = grilio_request_new();
+
+ grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
+ priv->query_id =
+ grilio_queue_send_request_full(priv->q, req,
+ RIL_REQUEST_DATA_CALL_LIST,
+ ril_data_query_data_calls_cb,
+ NULL, self);
+ grilio_request_unref(req);
+ }
+ }
+}
+
struct ril_data *ril_data_ref(struct ril_data *self)
{
if (G_LIKELY(self)) {
@@ -1211,10 +1258,11 @@
static void ril_data_disallow(struct ril_data *self)
{
struct ril_data_priv *priv = self->priv;
+ const gboolean was_allowed = ril_data_allowed(self);
DBG_(self, "disallowed");
GASSERT(priv->flags & RIL_DATA_FLAG_ALLOWED);
- priv->flags &= ~(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
+ priv->flags &= ~RIL_DATA_FLAG_ALLOWED;
/*
* Cancel all requests that can be canceled.
@@ -1227,7 +1275,20 @@
* requests are already pending? That's quite unlikely though)
*/
ril_data_deactivate_all(self);
- ril_data_power_update(self);
+
+ if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
+ /* Tell rild that the data is now disabled */
+ ril_data_request_queue(ril_data_allow_new(self, FALSE));
+ } else {
+ priv->flags &= ~RIL_DATA_FLAG_ON;
+ GASSERT(!ril_data_allowed(self));
+ DBG_(self, "data off");
+ ril_data_power_update(self);
+ }
+
+ if (ril_data_allowed(self) != was_allowed) {
+ ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
+ }
}
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
@@ -1244,12 +1305,7 @@
struct ril_data *data = data_ptr;
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
- const gboolean was_allowed = ril_data_allowed(data);
ril_data_disallow(data);
- if (was_allowed) {
- ril_data_signal_emit(data,
- SIGNAL_ALLOW_CHANGED);
- }
}
}
}
@@ -1303,13 +1359,7 @@
}
} else {
if (priv->flags & RIL_DATA_FLAG_ALLOWED) {
- gboolean was_allowed = ril_data_allowed(self);
-
ril_data_disallow(self);
- if (was_allowed) {
- ril_data_signal_emit(self,
- SIGNAL_ALLOW_CHANGED);
- }
ril_data_manager_check_data(dm);
}
}
@@ -1538,9 +1588,8 @@
OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
}
-
- if (priv->options.allow_data == RIL_ALLOW_DATA_ON) {
- ril_data_request_queue(ril_data_allow_new(data));
+ if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
+ ril_data_request_queue(ril_data_allow_new(data, TRUE));
} else {
priv->flags |= RIL_DATA_FLAG_ON;
GASSERT(ril_data_allowed(data));
@@ -1562,6 +1611,16 @@
}
}
}
+
+void ril_data_manager_assert_data_on(struct ril_data_manager *self)
+{
+ if (self) {
+ struct ril_data *data = ril_data_manager_allowed(self);
+ if (data) {
+ ril_data_request_queue(ril_data_allow_new(data, TRUE));
+ }
+ }
+}
/*
* Local Variables:
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_data.h
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2016 Jolla Ltd.
+ * Copyright (C) 2016-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -56,8 +56,8 @@
enum ril_data_allow_data_opt {
RIL_ALLOW_DATA_AUTO,
- RIL_ALLOW_DATA_ON,
- RIL_ALLOW_DATA_OFF
+ RIL_ALLOW_DATA_ENABLED,
+ RIL_ALLOW_DATA_DISABLED
};
enum ril_data_call_format {
@@ -84,6 +84,7 @@
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
void ril_data_manager_unref(struct ril_data_manager *dm);
+void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
@@ -99,6 +100,7 @@
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
gboolean ril_data_allowed(struct ril_data *data);
+void ril_data_poll_call_state(struct ril_data *data);
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
ril_data_cb_t cb, void *arg);
@@ -122,6 +124,10 @@
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
int cid);
+/* Constructors of various kinds of RIL requests */
+GRilIoRequest *ril_request_allow_data_new(gboolean allow);
+GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
+
#endif /* RIL_DATA_H */
/*
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_gprs_context.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015-2016 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,6 @@
#include "ril_network.h"
#include "ril_data.h"
#include "ril_util.h"
-#include "ril_mtu.h"
#include "ril_log.h"
#include <gutil_strv.h>
@@ -25,6 +24,7 @@
#include <arpa/inet.h>
#include "common.h"
+#include "mtu-watch.h"
#define CTX_ID_NONE ((unsigned int)(-1))
@@ -43,7 +43,7 @@
struct ril_data *data;
guint active_ctx_cid;
gulong calls_changed_id;
- struct ril_mtu_watch *mtu_watch;
+ struct mtu_watch *mtu_watch;
struct ril_data_call *active_call;
struct ril_gprs_context_call activate;
struct ril_gprs_context_call deactivate;
@@ -95,7 +95,7 @@
gcd->calls_changed_id = 0;
}
if (gcd->mtu_watch) {
- ril_mtu_watch_free(gcd->mtu_watch);
+ mtu_watch_free(gcd->mtu_watch);
gcd->mtu_watch = NULL;
}
}
@@ -107,9 +107,9 @@
ril_data_call_free(gcd->active_call);
gcd->active_call = ril_data_call_dup(call);
if (!gcd->mtu_watch) {
- gcd->mtu_watch = ril_mtu_watch_new(MAX_MTU);
+ gcd->mtu_watch = mtu_watch_new(MAX_MTU);
}
- ril_mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
+ mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
} else {
ril_gprs_context_free_active_call(gcd);
}
@@ -575,7 +575,7 @@
ril_data_unref(gcd->data);
ril_network_unref(gcd->network);
ril_data_call_free(gcd->active_call);
- ril_mtu_watch_free(gcd->mtu_watch);
+ mtu_watch_free(gcd->mtu_watch);
g_free(gcd);
}
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_modem.c
^
|
@@ -25,6 +25,8 @@
#include "ofono.h"
+#include "sailfish_watch.h"
+
#define MAX_PDP_CONTEXTS (2)
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
@@ -50,6 +52,7 @@
struct ril_modem_data {
struct ril_modem modem;
+ struct sailfish_watch *watch;
GRilIoQueue *q;
char *log_prefix;
char *imeisv;
@@ -57,18 +60,12 @@
char *ecclist_file;
gboolean pre_sim_done;
gboolean allow_data;
- gulong sim_imsi_event_id;
+ gulong imsi_event_id;
guint online_check_id;
enum ril_modem_power_state power_state;
gulong radio_state_event_id;
- ril_modem_cb_t removed_cb;
- void *removed_cb_data;
-
- ril_modem_online_cb_t online_cb;
- void *online_cb_data;
-
struct ril_modem_online_request set_online;
struct ril_modem_online_request set_offline;
};
@@ -84,11 +81,6 @@
return md;
}
-static struct ril_modem_data *ril_modem_data_from_modem(struct ril_modem *m)
-{
- return m ? G_CAST(m, struct ril_modem_data, modem) : NULL;
-}
-
static void *ril_modem_get_atom_data(struct ril_modem *modem,
enum ofono_atom_type type)
{
@@ -132,24 +124,6 @@
}
}
-void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
- void *data)
-{
- struct ril_modem_data *md = ril_modem_data_from_modem(modem);
-
- md->removed_cb = cb;
- md->removed_cb_data = data;
-}
-
-void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
- void *data)
-{
- struct ril_modem_data *md = ril_modem_data_from_modem(modem);
-
- md->online_cb = cb;
- md->online_cb_data = data;
-}
-
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
{
if (req->timeout_id) {
@@ -234,7 +208,7 @@
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
{
struct ril_modem *m = &md->modem;
- if (m->radio->state == RADIO_STATE_ON && m->sim_settings->imsi) {
+ if (m->radio->state == RADIO_STATE_ON && md->watch->imsi) {
/* radio-settings.c assumes that IMSI is available */
if (!ril_modem_radio_settings(m)) {
DBG_(md, "initializing radio settings interface");
@@ -262,11 +236,11 @@
ril_modem_update_online_state(md);
}
-static void ril_modem_imsi_cb(struct ril_sim_settings *settings, void *data)
+static void ril_modem_imsi_cb(struct sailfish_watch *watch, void *data)
{
struct ril_modem_data *md = data;
- GASSERT(md->modem.sim_settings == settings);
+ GASSERT(md->watch == watch);
ril_modem_update_radio_settings(md);
}
@@ -278,7 +252,9 @@
md->pre_sim_done = TRUE;
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
- ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
+ if (md->modem.config.enable_voicecall) {
+ ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
+ }
if (!md->radio_state_event_id) {
md->radio_state_event_id =
ril_radio_add_state_changed_handler(md->modem.radio,
@@ -337,10 +313,6 @@
DBG("%s going %sline", ofono_modem_get_path(modem),
online ? "on" : "off");
- if (md->online_cb) {
- md->online_cb(&md->modem, online, md->online_cb_data);
- }
-
if (online) {
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
req = &md->set_online;
@@ -394,25 +366,16 @@
struct ril_modem *modem = &md->modem;
DBG("%s", ril_modem_get_path(modem));
- if (md->removed_cb) {
- ril_modem_cb_t cb = md->removed_cb;
- void *data = md->removed_cb_data;
-
- md->removed_cb = NULL;
- md->removed_cb_data = NULL;
- cb(modem, data);
- }
-
ofono_modem_set_data(ofono, NULL);
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
ril_radio_unref(modem->radio);
-
- ril_sim_settings_remove_handler(modem->sim_settings,
- md->sim_imsi_event_id);
ril_sim_settings_unref(modem->sim_settings);
+ sailfish_watch_remove_handler(md->watch, md->imsi_event_id);
+ sailfish_watch_unref(md->watch);
+
if (md->online_check_id) {
g_source_remove(md->online_check_id);
}
@@ -440,13 +403,15 @@
}
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
- const struct ril_slot_info *slot, struct ril_radio *radio,
- struct ril_network *network, struct ril_sim_card *card,
- struct ril_data *data, struct ril_sim_settings *settings,
+ const char *path, const char *imei, const char *imeisv,
+ const char *ecclist_file, const struct ril_slot_config *config,
+ struct ril_radio *radio, struct ril_network *network,
+ struct ril_sim_card *card, struct ril_data *data,
+ struct ril_sim_settings *settings,
struct ril_cell_info *cell_info)
{
/* Skip the slash from the path, it looks like "/ril_0" */
- struct ofono_modem *ofono = ofono_modem_create(slot->path + 1,
+ struct ofono_modem *ofono = ofono_modem_create(path + 1,
RILMODEM_DRIVER);
if (ofono) {
int err;
@@ -457,15 +422,14 @@
* ril_plugin.c must wait until IMEI becomes known before
* creating the modem
*/
- GASSERT(slot->imei);
+ GASSERT(imei);
/* Copy config */
- modem->config = *slot->config;
- modem->imei = md->imei = g_strdup(slot->imei);
- modem->imeisv = md->imeisv = g_strdup(slot->imeisv);
- modem->log_prefix = log_prefix;
- modem->ecclist_file =
- md->ecclist_file = g_strdup(slot->ecclist_file);
+ modem->config = *config;
+ modem->imei = md->imei = g_strdup(imei);
+ modem->imeisv = md->imeisv = g_strdup(imeisv);
+ modem->log_prefix = log_prefix; /* No need to strdup */
+ modem->ecclist_file = ecclist_file; /* No need to strdup */
md->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
@@ -478,14 +442,10 @@
modem->data = ril_data_ref(data);
modem->io = grilio_channel_ref(io);
md->q = grilio_queue_new(io);
+ md->watch = sailfish_watch_new(path);
- /*
- * modem->sim_settings->imsi follows IMSI known to the ofono
- * core, unlike ril_sim_info->imsi which may point to the
- * cached IMSI even before the PIN code is entered.
- */
- md->sim_imsi_event_id =
- ril_sim_settings_add_imsi_changed_handler(settings,
+ md->imsi_event_id =
+ sailfish_watch_add_imsi_changed_handler(md->watch,
ril_modem_imsi_cb, md);
md->set_online.md = md;
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_network.c
^
|
@@ -20,6 +20,8 @@
#include "ril_util.h"
#include "ril_log.h"
+#include "sailfish_watch.h"
+
#include <grilio_queue.h>
#include <grilio_request.h>
#include <grilio_parser.h>
@@ -41,18 +43,30 @@
TIMER_COUNT
};
+enum ril_network_watch_events {
+ WATCH_EVENT_ONLINE,
+ WATCH_EVENT_COUNT
+};
+
enum ril_network_radio_event {
RADIO_EVENT_STATE_CHANGED,
RADIO_EVENT_ONLINE_CHANGED,
RADIO_EVENT_COUNT
};
+enum ril_network_unsol_event {
+ UNSOL_EVENT_NETWORK_STATE,
+ UNSOL_EVENT_RADIO_CAPABILITY,
+ UNSOL_EVENT_COUNT
+};
+
struct ril_network_priv {
GRilIoChannel *io;
GRilIoQueue *q;
struct ril_radio *radio;
struct ril_sim_card *sim_card;
- enum ofono_radio_access_mode max_pref_mode;
+ struct sailfish_watch *watch;
+ gulong watch_event_id[WATCH_EVENT_COUNT];
int rat;
char *log_prefix;
guint operator_poll_id;
@@ -61,11 +75,12 @@
guint timer[TIMER_COUNT];
gulong query_rat_id;
gulong set_rat_id;
- gulong ril_event_id;
+ gulong unsol_event_id[UNSOL_EVENT_COUNT];
gulong settings_event_id;
gulong sim_status_event_id;
gulong radio_event_id[RADIO_EVENT_COUNT];
struct ofono_network_operator operator;
+ gboolean assert_rat;
};
enum ril_network_signal {
@@ -73,13 +88,15 @@
SIGNAL_VOICE_STATE_CHANGED,
SIGNAL_DATA_STATE_CHANGED,
SIGNAL_PREF_MODE_CHANGED,
+ SIGNAL_MAX_PREF_MODE_CHANGED,
SIGNAL_COUNT
};
-#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
-#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
-#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
-#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
+#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
+#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
+#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
+#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
+#define SIGNAL_MAX_PREF_MODE_CHANGED_NAME "ril-network-max-pref-mode-changed"
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
@@ -450,7 +467,7 @@
* it becomes necessary.
*/
const enum ofono_radio_access_mode max_pref_mode =
- (priv->radio->state == RADIO_STATE_ON) ? priv->max_pref_mode :
+ (priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
OFONO_RADIO_ACCESS_MODE_GSM;
/*
@@ -470,7 +487,7 @@
{
struct ril_network_priv *priv = self->priv;
- return priv->radio->online && ril_sim_card_ready(priv->sim_card);
+ return priv->watch->online && ril_sim_card_ready(priv->sim_card);
}
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
@@ -489,7 +506,7 @@
* and SIM card state change callbacks will schedule a new check
* when it's appropriate.
*/
- if (priv->rat != rat) {
+ if (priv->rat != rat || priv->assert_rat) {
if (ril_network_can_set_pref_mode(self)) {
ril_network_set_pref_mode(self, rat);
} else {
@@ -530,6 +547,9 @@
ril_network_set_pref_mode_cb, NULL, self);
grilio_request_unref(req);
+ /* We have submitted the request, clear the assertion flag */
+ priv->assert_rat = FALSE;
+
/* Don't do it too often */
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
priv->timer[TIMER_SET_RAT_HOLDOFF] =
@@ -557,8 +577,7 @@
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
}
- if (priv->rat != rat) {
- /* Something isn't right, we need to fix it */
+ if (priv->rat != rat || priv->assert_rat) {
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
ril_network_set_pref_mode(self, rat);
} else {
@@ -647,17 +666,25 @@
enum ofono_radio_access_mode max_mode,
gboolean force_check)
{
- if (G_LIKELY(self)) {
- struct ril_network_priv *priv = self->priv;
- if (priv->max_pref_mode != max_mode || force_check) {
+ if (self && (self->max_pref_mode != max_mode || force_check)) {
+ if (self->max_pref_mode != max_mode) {
DBG_(self, "rat mode %d (%s)", max_mode,
ofono_radio_access_mode_to_string(max_mode));
- priv->max_pref_mode = max_mode;
- ril_network_check_pref_mode(self, TRUE);
+ self->max_pref_mode = max_mode;
+ ril_network_emit(self, SIGNAL_MAX_PREF_MODE_CHANGED);
}
+ ril_network_check_pref_mode(self, TRUE);
}
}
+void ril_network_assert_pref_mode(struct ril_network *self, gboolean immediate)
+{
+ struct ril_network_priv *priv = self->priv;
+
+ priv->assert_rat = TRUE;
+ ril_network_check_pref_mode(self, immediate);
+}
+
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
ril_network_cb_t cb, void *arg)
{
@@ -686,6 +713,13 @@
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
+gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *self,
+ ril_network_cb_t cb, void *arg)
+{
+ return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
+ SIGNAL_MAX_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
+}
+
void ril_network_remove_handler(struct ril_network *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
@@ -698,7 +732,7 @@
gutil_disconnect_handlers(self, ids, n);
}
-static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
+static void ril_network_state_changed_cb(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
struct ril_network *self = RIL_NETWORK(user_data);
@@ -708,6 +742,16 @@
ril_network_poll_state(self);
}
+static void ril_network_radio_capability_changed_cb(GRilIoChannel *io,
+ guint code, const void *data, guint len, void *user_data)
+{
+ struct ril_network *self = RIL_NETWORK(user_data);
+
+ DBG_(self, "");
+ GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
+ ril_network_assert_pref_mode(self, FALSE);
+}
+
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
{
struct ril_network *self = RIL_NETWORK(data);
@@ -718,7 +762,7 @@
}
}
-static void ril_network_radio_online_cb(struct ril_radio *radio, void *data)
+static void ril_network_online_cb(struct sailfish_watch *watch, void *data)
{
struct ril_network *self = RIL_NETWORK(data);
@@ -770,8 +814,9 @@
}
}
-struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
- struct ril_radio *radio, struct ril_sim_card *sim_card,
+struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
+ const char *log_prefix, struct ril_radio *radio,
+ struct ril_sim_card *sim_card,
struct ril_sim_settings *settings)
{
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
@@ -780,20 +825,26 @@
self->settings = ril_sim_settings_ref(settings);
priv->io = grilio_channel_ref(io);
priv->q = grilio_queue_new(priv->io);
+ priv->watch = sailfish_watch_new(path);
priv->radio = ril_radio_ref(radio);
priv->sim_card = ril_sim_card_ref(sim_card);
priv->log_prefix = (log_prefix && log_prefix[0]) ?
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
DBG_(self, "");
- priv->ril_event_id = grilio_channel_add_unsol_event_handler(priv->io,
- ril_network_voice_state_changed_cb,
+ priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
+ grilio_channel_add_unsol_event_handler(priv->io,
+ ril_network_state_changed_cb,
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
+ priv->unsol_event_id[UNSOL_EVENT_RADIO_CAPABILITY] =
+ grilio_channel_add_unsol_event_handler(priv->io,
+ ril_network_radio_capability_changed_cb,
+ RIL_UNSOL_RADIO_CAPABILITY, self);
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
ril_radio_add_state_changed_handler(priv->radio,
ril_network_radio_state_cb, self);
- priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
- ril_radio_add_online_changed_handler(priv->radio,
- ril_network_radio_online_cb, self);
+ priv->watch_event_id[WATCH_EVENT_ONLINE] =
+ sailfish_watch_add_modem_changed_handler(priv->watch,
+ ril_network_online_cb, self);
priv->settings_event_id =
ril_sim_settings_add_pref_mode_changed_handler(settings,
ril_network_pref_mode_changed_cb, self);
@@ -843,57 +894,46 @@
priv->rat = -1;
}
-static void ril_network_dispose(GObject *object)
+static void ril_network_finalize(GObject *object)
{
struct ril_network *self = RIL_NETWORK(object);
struct ril_network_priv *priv = self->priv;
enum ril_network_timer tid;
- grilio_channel_remove_handlers(priv->io, &priv->ril_event_id, 1);
- ril_radio_remove_handlers(priv->radio, priv->radio_event_id,
- G_N_ELEMENTS(priv->radio_event_id));
- ril_sim_settings_remove_handlers(self->settings,
- &priv->settings_event_id, 1);
- ril_sim_card_remove_handlers(priv->sim_card,
- &priv->sim_status_event_id, 1);
-
+ DBG_(self, "");
for (tid=0; tid<TIMER_COUNT; tid++) {
ril_network_stop_timer(self, tid);
}
grilio_queue_cancel_all(priv->q, FALSE);
- priv->set_rat_id = 0;
- priv->query_rat_id = 0;
-
- G_OBJECT_CLASS(ril_network_parent_class)->dispose(object);
-}
-
-static void ril_network_finalize(GObject *object)
-{
- struct ril_network *self = RIL_NETWORK(object);
- struct ril_network_priv *priv = self->priv;
+ grilio_channel_remove_handlers(priv->io, priv->unsol_event_id,
+ G_N_ELEMENTS(priv->unsol_event_id));
- DBG_(self, "");
- g_free(priv->log_prefix);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
+ sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
+ sailfish_watch_unref(priv->watch);
+ ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
ril_radio_unref(priv->radio);
+ ril_sim_card_remove_handler(priv->sim_card,
+ priv->sim_status_event_id);
ril_sim_card_unref(priv->sim_card);
+ ril_sim_settings_remove_handler(self->settings,
+ priv->settings_event_id);
ril_sim_settings_unref(self->settings);
+ g_free(priv->log_prefix);
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
}
static void ril_network_class_init(RilNetworkClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
-
- object_class->dispose = ril_network_dispose;
- object_class->finalize = ril_network_finalize;
+ G_OBJECT_CLASS(klass)->finalize = ril_network_finalize;
g_type_class_add_private(klass, sizeof(struct ril_network_priv));
RIL_NETWORK_SIGNAL(klass, OPERATOR);
RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
RIL_NETWORK_SIGNAL(klass, DATA_STATE);
RIL_NETWORK_SIGNAL(klass, PREF_MODE);
+ RIL_NETWORK_SIGNAL(klass, MAX_PREF_MODE);
}
/*
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_network.h
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015-2016 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,8 +18,6 @@
#include "ril_types.h"
-#include <ofono/radio-settings.h>
-
struct ofono_network_operator;
struct ril_registration_state {
@@ -38,14 +36,16 @@
struct ril_registration_state data;
const struct ofono_network_operator *operator;
enum ofono_radio_access_mode pref_mode;
+ enum ofono_radio_access_mode max_pref_mode;
struct ril_sim_settings *settings;
};
struct ofono_sim;
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
-struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
- struct ril_radio *radio, struct ril_sim_card *sim_card,
+struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
+ const char *log_prefix, struct ril_radio *radio,
+ struct ril_sim_card *sim_card,
struct ril_sim_settings *settings);
struct ril_network *ril_network_ref(struct ril_network *net);
void ril_network_unref(struct ril_network *net);
@@ -53,6 +53,7 @@
void ril_network_set_max_pref_mode(struct ril_network *net,
enum ofono_radio_access_mode max_pref_mode,
gboolean force_check);
+void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
@@ -61,6 +62,8 @@
ril_network_cb_t cb, void *arg);
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
+gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
+ ril_network_cb_t cb, void *arg);
void ril_network_remove_handler(struct ril_network *net, gulong id);
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_oem_raw.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015-2016 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,7 +24,6 @@
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
struct ril_oem_raw {
- struct ril_modem *modem;
GRilIoQueue *q;
DBusConnection *conn;
char *path;
@@ -118,7 +117,6 @@
struct ril_oem_raw *oem = g_new0(struct ril_oem_raw, 1);
DBG("%s", ril_modem_get_path(modem));
- oem->modem = modem;
oem->path = g_strdup(ril_modem_get_path(modem));
oem->conn = dbus_connection_ref(ofono_dbus_get_connection());
oem->q = grilio_queue_new(ril_modem_io(modem));
@@ -144,8 +142,6 @@
DBG("%s", oem->path);
g_dbus_unregister_interface(oem->conn, oem->path,
RIL_OEM_RAW_INTERFACE);
- ofono_modem_remove_interface(oem->modem->ofono,
- RIL_OEM_RAW_INTERFACE);
dbus_connection_unref(oem->conn);
grilio_queue_cancel_all(oem->q, TRUE);
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_plugin.c
^
|
@@ -16,21 +16,24 @@
#include "ril_plugin.h"
#include "ril_config.h"
#include "ril_sim_card.h"
-#include "ril_sim_info.h"
#include "ril_sim_settings.h"
#include "ril_cell_info.h"
#include "ril_network.h"
#include "ril_radio.h"
+#include "ril_radio_caps.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
-#include <gdbus.h>
+#include <sailfish_manager.h>
+#include <sailfish_watch.h>
+
#include <gutil_ints.h>
-#include <gutil_strv.h>
-#include <gutil_misc.h>
+#include <gutil_macros.h>
+
#include <mce_display.h>
#include <mce_log.h>
+
#include <linux/capability.h>
#include <sys/types.h>
#include <sys/syscall.h>
@@ -39,13 +42,13 @@
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include "ofono.h"
-#include "storage.h"
#define OFONO_RADIO_ACCESS_MODE_ALL (OFONO_RADIO_ACCESS_MODE_GSM |\
OFONO_RADIO_ACCESS_MODE_UMTS |\
OFONO_RADIO_ACCESS_MODE_LTE)
#define RIL_DEVICE_IDENTITY_RETRIES_LAST 2
+#define RIL_START_TIMEOUT_SEC 20 /* seconds */
#define RADIO_GID 1001
#define RADIO_UID 1001
@@ -56,9 +59,9 @@
#define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2"
#define RILMODEM_DEFAULT_SUB "SUB1"
#define RILMODEM_DEFAULT_TECHS OFONO_RADIO_ACCESS_MODE_ALL
+#define RILMODEM_DEFAULT_ENABLE_VOICECALL TRUE
#define RILMODEM_DEFAULT_SLOT 0xffffffff
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
-#define RILMODEM_DEFAULT_OPTIONAL FALSE
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
#define RILMODEM_DEFAULT_DATA_OPT RIL_ALLOW_DATA_AUTO
#define RILMODEM_DEFAULT_DM_FLAGS RIL_DATA_MANAGER_3GLTE_HANDOVER
@@ -69,6 +72,7 @@
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
+#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
#define RILCONF_DEV_PREFIX "ril_"
#define RILCONF_PATH_PREFIX "/" RILCONF_DEV_PREFIX
@@ -77,8 +81,8 @@
#define RILCONF_SLOT "slot"
#define RILCONF_SUB "sub"
#define RILCONF_TIMEOUT "timeout"
-#define RILCONF_OPTIONAL "optional"
#define RILCONF_4G "enable4G" /* Deprecated */
+#define RILCONF_ENABLE_VOICECALL "enableVoicecall"
#define RILCONF_TECHS "technologies"
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
#define RILCONF_ECCLIST_FILE "ecclistFile"
@@ -90,18 +94,9 @@
#define RILCONF_LOCAL_HANGUP_REASONS "localHangupReasons"
#define RILCONF_REMOTE_HANGUP_REASONS "remoteHangupReasons"
-#define RIL_STORE "ril"
-#define RIL_STORE_GROUP "Settings"
-#define RIL_STORE_ENABLED_SLOTS "EnabledSlots"
-#define RIL_STORE_DEFAULT_VOICE_SIM "DefaultVoiceSim"
-#define RIL_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
-#define RIL_STORE_SLOTS_SEP ","
-
-/* The file where error statistics is stored */
-#define RIL_ERROR_STORAGE "rilerror"
-
-/* Modem error ids, must be static strings (only one is defined for now) */
-static const char RIL_ERROR_ID_RILD_RESTART[] = "rild-restart";
+/* Modem error ids */
+#define RIL_ERROR_ID_RILD_RESTART "rild-restart"
+#define RIL_ERROR_ID_CAPS_SWITCH_ABORTED "ril-caps-switch-aborted"
enum ril_plugin_io_events {
IO_EVENT_CONNECTED,
@@ -117,26 +112,37 @@
DISPLAY_EVENT_COUNT
};
-struct ril_plugin_priv {
- struct ril_plugin pub;
- struct ril_plugin_dbus *dbus;
+enum ril_plugin_watch_events {
+ WATCH_EVENT_MODEM,
+ WATCH_EVENT_COUNT
+};
+
+enum ril_set_radio_cap_opt {
+ RIL_SET_RADIO_CAP_AUTO,
+ RIL_SET_RADIO_CAP_ENABLED,
+ RIL_SET_RADIO_CAP_DISABLED
+};
+
+struct ril_plugin_settings {
+ int dm_flags;
+ enum ril_set_radio_cap_opt set_radio_cap;
+};
+
+typedef struct sailfish_slot_manager_impl {
+ struct sailfish_slot_manager *handle;
struct ril_data_manager *data_manager;
- MceDisplay *display;
- gboolean display_on;
- gulong display_event_id[DISPLAY_EVENT_COUNT];
+ struct ril_radio_caps_manager *caps_manager;
+ struct ril_plugin_settings settings;
+ gulong caps_manager_event_id;
+ guint start_timeout_id;
GSList *slots;
- ril_slot_info_ptr *slots_info;
- struct ril_slot *voice_slot;
- struct ril_slot *data_slot;
- struct ril_slot *mms_slot;
- char *default_voice_imsi;
- char *default_data_imsi;
- char *mms_imsi;
- GKeyFile *storage;
-};
+} ril_plugin;
-struct ril_slot {
- struct ril_slot_info pub;
+typedef struct sailfish_slot_impl {
+ ril_plugin* plugin;
+ struct sailfish_slot *handle;
+ struct sailfish_watch *watch;
+ gulong watch_event_id[WATCH_EVENT_COUNT];
char *path;
char *imei;
char *imeisv;
@@ -149,44 +155,41 @@
int sim_flags;
struct ril_data_options data_opt;
struct ril_slot_config config;
- struct ril_plugin_priv *plugin;
struct ril_modem *modem;
- struct ofono_sim *sim;
struct ril_radio *radio;
+ struct ril_radio_caps *caps;
struct ril_network *network;
struct ril_sim_card *sim_card;
- struct ril_sim_info *sim_info;
- struct ril_sim_info_dbus *sim_info_dbus;
struct ril_sim_settings *sim_settings;
struct ril_cell_info *cell_info;
struct ril_cell_info_dbus *cell_info_dbus;
struct ril_oem_raw *oem_raw;
struct ril_data *data;
MceDisplay *display;
+ gboolean display_on;
+ gulong display_event_id[DISPLAY_EVENT_COUNT];
GRilIoChannel *io;
gulong io_event_id[IO_EVENT_COUNT];
- gulong imei_req_id;
gulong sim_card_state_event_id;
gboolean received_sim_status;
+ guint serialize_id;
+ guint caps_check_id;
+ guint imei_req_id;
guint trace_id;
guint dump_id;
guint retry_id;
- guint sim_watch_id;
- guint sim_state_watch_id;
- enum ofono_sim_state sim_state;
-};
+} ril_slot;
-struct ril_plugin_settings {
- int dm_flags;
-};
+typedef void (*ril_plugin_slot_cb_t)(ril_slot *slot);
+typedef void (*ril_plugin_slot_param_cb_t)(ril_slot *slot, void *param);
static void ril_debug_trace_notify(struct ofono_debug_desc *desc);
static void ril_debug_dump_notify(struct ofono_debug_desc *desc);
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc);
static void ril_debug_mce_notify(struct ofono_debug_desc *desc);
static void ril_plugin_debug_notify(struct ofono_debug_desc *desc);
-static void ril_plugin_retry_init_io(struct ril_slot *slot);
-static void ril_plugin_check_modem(struct ril_slot *slot);
+static void ril_plugin_retry_init_io(ril_slot *slot);
+static void ril_plugin_check_modem(ril_slot *slot);
GLOG_MODULE_DEFINE("rilmodem");
@@ -229,42 +232,66 @@
.notify = ril_plugin_debug_notify
};
-static inline const char *ril_slot_debug_prefix(const struct ril_slot *slot)
+static inline const char *ril_slot_debug_prefix(const ril_slot *slot)
{
/* slot->path always starts with a slash, skip it */
return slot->path + 1;
}
-static struct ril_plugin_priv *ril_plugin_cast(struct ril_plugin *pub)
+static gboolean ril_plugin_multisim(ril_plugin *plugin)
{
- return G_CAST(pub, struct ril_plugin_priv, pub);
+ return plugin->slots && plugin->slots->next;
}
-static gboolean ril_plugin_multisim(struct ril_plugin_priv *plugin)
+static void ril_plugin_foreach_slot_param(ril_plugin *plugin,
+ ril_plugin_slot_param_cb_t fn, void *param)
{
- return plugin->slots && plugin->slots->next;
+ GSList *l = plugin->slots;
+
+ while (l) {
+ GSList *next = l->next;
+
+ fn((ril_slot *)l->data, param);
+ l = next;
+ }
}
static void ril_plugin_foreach_slot_proc(gpointer data, gpointer user_data)
{
- void (*fn)(struct ril_slot *) = user_data;
- fn((struct ril_slot *)data);
+ ((ril_plugin_slot_cb_t)user_data)(data);
}
-static void ril_plugin_foreach_slot(struct ril_plugin_priv *plugin,
- void (*fn)(struct ril_slot *))
+static void ril_plugin_foreach_slot(ril_plugin *plugin, ril_plugin_slot_cb_t fn)
{
g_slist_foreach(plugin->slots, ril_plugin_foreach_slot_proc, fn);
}
-static void ril_plugin_send_screen_state(struct ril_slot *slot)
+static void ril_plugin_foreach_slot_manager_proc(ril_plugin *plugin, void *data)
+{
+ ril_plugin_foreach_slot(plugin, (ril_plugin_slot_cb_t)data);
+}
+
+static void ril_plugin_foreach_slot_manager(struct sailfish_slot_driver_reg *r,
+ ril_plugin_slot_cb_t fn)
+{
+ sailfish_manager_foreach_slot_manager(r,
+ ril_plugin_foreach_slot_manager_proc, fn);
+}
+
+static void ril_plugin_send_screen_state(ril_slot *slot)
{
if (slot->io && slot->io->connected) {
- GRilIoRequest *req = grilio_request_sized_new(8);
- grilio_request_append_int32(req, 1); /* Number of params */
- grilio_request_append_int32(req, slot->plugin->display_on);
+ /**
+ * RIL_REQUEST_SCREEN_STATE (deprecated on 2017-01-10)
+ *
+ * ((int *)data)[0] is == 1 for "Screen On"
+ * ((int *)data)[0] is == 0 for "Screen Off"
+ */
+ GRilIoRequest *req = grilio_request_array_int32_new(1,
+ slot->display_on);
+
grilio_channel_send_request(slot->io, req,
- RIL_REQUEST_SCREEN_STATE);
+ RIL_REQUEST_SCREEN_STATE);
grilio_request_unref(req);
}
}
@@ -277,16 +304,16 @@
static void ril_plugin_display_cb(MceDisplay *display, void *user_data)
{
- struct ril_plugin_priv *plugin = user_data;
- const gboolean display_was_on = plugin->display_on;
+ ril_slot *slot = user_data;
+ const gboolean display_was_on = slot->display_on;
- plugin->display_on = ril_plugin_display_on(display);
- if (plugin->display_on != display_was_on) {
- ril_plugin_foreach_slot(plugin, ril_plugin_send_screen_state);
+ slot->display_on = ril_plugin_display_on(display);
+ if (slot->display_on != display_was_on) {
+ ril_plugin_send_screen_state(slot);
}
}
-static void ril_plugin_remove_slot_handler(struct ril_slot *slot, int id)
+static void ril_plugin_remove_slot_handler(ril_slot *slot, int id)
{
GASSERT(id >= 0 && id<IO_EVENT_COUNT);
if (slot->io_event_id[id]) {
@@ -295,31 +322,9 @@
}
}
-static void ril_plugin_update_ofono_sim(struct ril_slot *slot)
+static void ril_plugin_shutdown_slot(ril_slot *slot, gboolean kill_io)
{
- ril_sim_settings_set_ofono_sim(slot->sim_settings, slot->sim);
- ril_sim_info_set_ofono_sim(slot->sim_info, slot->sim);
-}
-
-static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
-{
- if (slot->sim) {
- if (slot->sim_state_watch_id) {
- ofono_sim_remove_state_watch(slot->sim,
- slot->sim_state_watch_id);
- GASSERT(!slot->sim_state_watch_id);
- }
- slot->sim = NULL;
- ril_plugin_update_ofono_sim(slot);
- }
-
if (slot->modem) {
- struct ofono_modem *m = slot->modem->ofono;
-
- if (m && slot->sim_watch_id) {
- __ofono_modem_remove_atom_watch(m, slot->sim_watch_id);
- }
-
ril_modem_delete(slot->modem);
/* The above call is expected to result in
* ril_plugin_modem_removed getting called
@@ -327,10 +332,6 @@
GASSERT(!slot->modem);
}
- /* All watches have to be unregistered by now */
- GASSERT(!slot->sim_state_watch_id);
- GASSERT(!slot->sim_watch_id);
-
if (kill_io) {
if (slot->retry_id) {
g_source_remove(slot->retry_id);
@@ -342,6 +343,11 @@
slot->cell_info = NULL;
}
+ if (slot->caps) {
+ ril_radio_caps_unref(slot->caps);
+ slot->caps = NULL;
+ }
+
if (slot->data) {
ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
ril_data_unref(slot->data);
@@ -354,7 +360,6 @@
}
if (slot->network) {
- ril_sim_info_set_network(slot->sim_info, slot->network);
ril_network_unref(slot->network);
slot->network = NULL;
}
@@ -376,9 +381,23 @@
slot->trace_id = 0;
slot->dump_id = 0;
- grilio_channel_cancel_request(slot->io,
+ if (slot->caps_check_id) {
+ grilio_channel_cancel_request(slot->io,
+ slot->caps_check_id, FALSE);
+ slot->caps_check_id = 0;
+ }
+
+ if (slot->imei_req_id) {
+ grilio_channel_cancel_request(slot->io,
slot->imei_req_id, FALSE);
- slot->imei_req_id = 0;
+ slot->imei_req_id = 0;
+ }
+
+ if (slot->serialize_id) {
+ grilio_channel_deserialize(slot->io,
+ slot->serialize_id);
+ slot->serialize_id = 0;
+ }
for (i=0; i<IO_EVENT_COUNT; i++) {
ril_plugin_remove_slot_handler(slot, i);
@@ -391,215 +410,10 @@
}
}
-static void ril_plugin_set_config_string(struct ril_plugin_priv *plugin,
- const char *key, const char *value, gboolean sync)
-{
- if (value) {
- g_key_file_set_string(plugin->storage, RIL_STORE_GROUP, key,
- value);
- } else {
- g_key_file_remove_key(plugin->storage, RIL_STORE_GROUP, key,
- NULL);
- }
- if (sync) {
- storage_sync(NULL, RIL_STORE, plugin->storage);
- }
-}
-
-static struct ril_slot *ril_plugin_find_slot_imsi(GSList *slots,
- const char *imsi)
-{
- struct ril_slot *default_slot = NULL;
-
- while (slots) {
- struct ril_slot *slot = slots->data;
- const char *slot_imsi = ofono_sim_get_imsi(slot->sim);
- if (slot_imsi) {
- if (imsi) {
- /* We are looking for the specific sim */
- if (!strcmp(imsi, slot_imsi)) {
- return slot;
- }
- } else {
- /* We are looking for any slot with a sim */
- if (!default_slot) {
- default_slot = slot;
- }
- }
- }
- slots = slots->next;
- }
-
- return default_slot;
-}
-
-static struct ril_slot *ril_plugin_find_slot_number(GSList *slots, guint number)
-{
- while (slots) {
- struct ril_slot *slot = slots->data;
- if (slot->config.slot == number) {
- return slot;
- }
- slots = slots->next;
- }
-
- return NULL;
-}
-
-/* Returns the event mask to be passed to ril_plugin_dbus_signal.
- * The caller has a chance to OR it with other bits */
-static int ril_plugin_update_modem_paths(struct ril_plugin_priv *plugin)
-{
- int mask = 0;
- struct ril_slot *slot = NULL;
- struct ril_slot *mms_slot = NULL;
- struct ril_slot *old_data_slot = NULL;
- struct ril_slot *new_data_slot = NULL;
-
- /* Voice */
- if (plugin->default_voice_imsi) {
- slot = ril_plugin_find_slot_imsi(plugin->slots,
- plugin->default_voice_imsi);
- } else if (plugin->voice_slot) {
- /* Make sure that the slot is enabled and SIM is in */
- slot = ril_plugin_find_slot_imsi(plugin->slots,
- plugin->voice_slot->modem ?
- ofono_sim_get_imsi(plugin->voice_slot->sim) :
- NULL);
- }
-
- /*
- * If there's no default voice SIM, we will find any SIM instead.
- * One should always be able to make and receive a phone call
- * if there's a working SIM in the phone. However if the
- * previously selected voice SIM is inserted, we will switch
- * back to it.
- *
- * There is no such fallback for the data.
- */
- if (!slot) {
- slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
- }
-
- if (plugin->voice_slot != slot) {
- mask |= RIL_PLUGIN_SIGNAL_VOICE_PATH;
- plugin->voice_slot = slot;
- if (slot) {
- DBG("Default voice SIM at %s", slot->path);
- plugin->pub.default_voice_path = slot->path;
- } else {
- DBG("No default voice SIM");
- plugin->pub.default_voice_path = NULL;
- }
- }
-
- /* Data */
- if (plugin->default_data_imsi) {
- slot = ril_plugin_find_slot_imsi(plugin->slots,
- plugin->default_data_imsi);
- } else if (plugin->data_slot) {
- /* Make sure that the slot is enabled and SIM is in */
- slot = ril_plugin_find_slot_imsi(plugin->slots,
- plugin->data_slot->modem ?
- ofono_sim_get_imsi(plugin->data_slot->sim) :
- NULL);
- } else {
- slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
- }
-
- if (slot && !slot->radio->online) {
- slot = NULL;
- }
-
- if (plugin->mms_imsi) {
- mms_slot = ril_plugin_find_slot_imsi(plugin->slots,
- plugin->mms_imsi);
- }
-
- if (mms_slot && mms_slot != slot) {
- /*
- * Reset default data SIM if another SIM is
- * temporarily selected for MMS.
- */
- slot = NULL;
- }
-
- /* Are we actually switching data SIMs? */
- old_data_slot = plugin->mms_slot ? plugin->mms_slot : plugin->data_slot;
- new_data_slot = mms_slot ? mms_slot : slot;
-
- if (plugin->data_slot != slot) {
- mask |= RIL_PLUGIN_SIGNAL_DATA_PATH;
- plugin->data_slot = slot;
- if (slot) {
- DBG("Default data SIM at %s", slot->path);
- plugin->pub.default_data_path = slot->path;
- } else {
- DBG("No default data SIM");
- plugin->pub.default_data_path = NULL;
- }
- }
-
- if (plugin->mms_slot != mms_slot) {
- mask |= RIL_PLUGIN_SIGNAL_MMS_PATH;
- plugin->mms_slot = mms_slot;
- if (mms_slot) {
- DBG("MMS data SIM at %s", mms_slot->path);
- plugin->pub.mms_path = mms_slot->path;
- } else {
- DBG("No MMS data SIM");
- plugin->pub.mms_path = NULL;
- }
- }
-
- if (old_data_slot != new_data_slot) {
- /* Yes we are switching data SIMs */
- if (old_data_slot) {
- ril_data_allow(old_data_slot->data, RIL_DATA_ROLE_NONE);
- }
- if (new_data_slot) {
- ril_data_allow(new_data_slot->data,
- (new_data_slot == plugin->data_slot) ?
- RIL_DATA_ROLE_INTERNET : RIL_DATA_ROLE_MMS);
- }
- }
-
- return mask;
-}
-
-/* Update modem paths and emit D-Bus signal if necessary */
-static void ril_plugin_update_modem_paths_full(struct ril_plugin_priv *plugin)
-{
- ril_plugin_dbus_signal(plugin->dbus,
- ril_plugin_update_modem_paths(plugin));
-}
-
-static void ril_plugin_update_ready(struct ril_plugin_priv *plugin)
-{
- GSList *link;
- gboolean ready = TRUE;
-
- for (link = plugin->slots; link; link = link->next) {
- struct ril_slot *slot = link->data;
-
- if (!slot->imei || !slot->sim_card || !slot->sim_card->status) {
- ready = FALSE;
- break;
- }
- }
-
- if (plugin->pub.ready != ready) {
- plugin->pub.ready = ready;
- ril_plugin_dbus_block_imei_requests(plugin->dbus, !ready);
- DBG("%sready", ready ? "" : "not ");
- ril_plugin_dbus_signal(plugin->dbus, RIL_PLUGIN_SIGNAL_READY);
- }
-}
-
static void ril_plugin_device_identity_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
- struct ril_slot *slot = user_data;
+ ril_slot *slot = user_data;
char *imei = NULL;
char *imeisv = NULL;
@@ -646,37 +460,56 @@
/* We assume that IMEI never changes */
g_free(imei);
} else {
- slot->pub.imei =
slot->imei = imei ? imei : g_strdup_printf("%d", slot->index);
+ sailfish_manager_imei_obtained(slot->handle, slot->imei);
}
if (slot->imeisv) {
g_free(imeisv);
} else {
- slot->pub.imeisv =
slot->imeisv = (imeisv ? imeisv : g_strdup(""));
+ sailfish_manager_imeisv_obtained(slot->handle, slot->imeisv);
}
ril_plugin_check_modem(slot);
- ril_plugin_update_ready(slot->plugin);
}
-static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
+static enum sailfish_sim_state ril_plugin_sim_state(ril_slot *slot)
{
- struct ril_slot *slot = data;
- struct ril_plugin_priv *plugin = slot->plugin;
- const struct ril_sim_card_status *status = card->status;
- gboolean present;
-
- if (status && status->card_state == RIL_CARDSTATE_PRESENT) {
- DBG("SIM found in slot %u", slot->config.slot);
- present = TRUE;
- } else {
- DBG("No SIM in slot %u", slot->config.slot);
- present = FALSE;
- }
+ const struct ril_sim_card_status *status = slot->sim_card->status;
if (status) {
+ switch (status->card_state) {
+ case RIL_CARDSTATE_PRESENT:
+ return SAILFISH_SIM_STATE_PRESENT;
+ case RIL_CARDSTATE_ABSENT:
+ return SAILFISH_SIM_STATE_ABSENT;
+ case RIL_CARDSTATE_ERROR:
+ return SAILFISH_SIM_STATE_ERROR;
+ default:
+ break;
+ }
+ }
+
+ return SAILFISH_SIM_STATE_UNKNOWN;
+}
+
+static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
+{
+ ril_slot *slot = data;
+ const enum sailfish_sim_state sim_state = ril_plugin_sim_state(slot);
+
+ if (card->status) {
+ switch (sim_state) {
+ case SAILFISH_SIM_STATE_PRESENT:
+ DBG("SIM found in slot %u", slot->config.slot);
+ break;
+ case SAILFISH_SIM_STATE_ABSENT:
+ DBG("No SIM in slot %u", slot->config.slot);
+ break;
+ default:
+ break;
+ }
if (!slot->received_sim_status && slot->imei_req_id) {
/*
* We have received the SIM status but haven't yet
@@ -689,7 +522,7 @@
* Some RILs fail RIL_REQUEST_DEVICE_IDENTITY until
* the modem hasn't been properly initialized.
*/
- GRilIoRequest* req = grilio_request_new();
+ GRilIoRequest *req = grilio_request_new();
DBG("Giving slot %u last chance", slot->config.slot);
grilio_request_set_retry(req, RIL_RETRY_MS,
@@ -706,192 +539,43 @@
slot->received_sim_status = TRUE;
}
- if (slot->pub.sim_present != present) {
- slot->pub.sim_present = present;
- ril_plugin_dbus_signal_sim(plugin->dbus, slot->index, present);
- }
-
- ril_plugin_update_ready(plugin);
-}
-
-static void ril_plugin_sim_watch_done(void *data)
-{
- struct ril_slot *slot = data;
-
- slot->sim_watch_id = 0;
-}
-
-static void ril_plugin_sim_state_watch_done(void *data)
-{
- struct ril_slot *slot = data;
-
- slot->sim_state_watch_id = 0;
-}
-
-static void ril_plugin_sim_state_watch(enum ofono_sim_state new_state,
- void *data)
-{
- struct ril_slot *slot = data;
- struct ril_plugin_priv *plugin = slot->plugin;
-
- DBG("%s sim state %d", ril_slot_debug_prefix(slot), new_state);
- slot->sim_state = new_state;
- if (new_state == OFONO_SIM_STATE_READY) {
- struct ril_slot *voice_slot = plugin->voice_slot;
- struct ril_slot *data_slot = plugin->data_slot;
- int signal_mask;
-
- /*
- * OFONO_SIM_STATE_READY means that pin code has been
- * entered (if necessary) and IMSI has been obtained.
- *
- * We want the first slot to be selected by default.
- * However, things may become available in pretty much
- * any order, so reset the slot pointers to NULL and let
- * ril_plugin_update_modem_paths() to pick them again.
- *
- * Only affects the very first boot and first boot after
- * the default voice SIM has been removed.
- */
- plugin->voice_slot = NULL;
- plugin->data_slot = NULL;
- signal_mask = ril_plugin_update_modem_paths(plugin);
- if (voice_slot != plugin->voice_slot) {
- DBG("Voice slot changed");
- signal_mask |= RIL_PLUGIN_SIGNAL_VOICE_PATH;
- }
- if (data_slot != plugin->data_slot) {
- DBG("Data slot changed");
- signal_mask |= RIL_PLUGIN_SIGNAL_DATA_PATH;
- }
- ril_plugin_dbus_signal(plugin->dbus, signal_mask);
- } else {
- ril_plugin_update_modem_paths_full(plugin);
- }
-}
-
-static void ril_plugin_register_sim(struct ril_slot *slot, struct ofono_sim *sim)
-{
- GASSERT(sim);
- GASSERT(!slot->sim);
- GASSERT(slot->sim_watch_id);
- GASSERT(!slot->sim_state_watch_id);
-
- slot->sim = sim;
- slot->sim_state = ofono_sim_get_state(sim);
- slot->sim_state_watch_id = ofono_sim_add_state_watch(sim,
- ril_plugin_sim_state_watch, slot,
- ril_plugin_sim_state_watch_done);
-}
-
-static void ril_plugin_sim_watch(struct ofono_atom *atom,
- enum ofono_atom_watch_condition cond, void *data)
-{
- struct ril_slot *slot = data;
-
- if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
- DBG("%s sim registered", ril_slot_debug_prefix(slot));
- ril_plugin_register_sim(slot, __ofono_atom_get_data(atom));
- } else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
- DBG("%s sim unregistered", ril_slot_debug_prefix(slot));
- slot->sim = NULL;
- }
-
- ril_plugin_update_ofono_sim(slot);
- ril_plugin_update_modem_paths_full(slot->plugin);
-}
-
-static void ril_plugin_count_error(struct ril_slot *slot, const char *key,
- const char *message)
-{
- GHashTable *errors = slot->pub.errors;
- GKeyFile *storage = storage_open(NULL, RIL_ERROR_STORAGE);
-
- /* Update life-time statistics */
- if (storage) {
- /* slot->path always starts with a slash, skip it */
- const char *group = slot->path + 1;
- g_key_file_set_integer(storage, group, key,
- g_key_file_get_integer(storage, group, key, NULL) + 1);
- storage_close(NULL, RIL_ERROR_STORAGE, storage, TRUE);
- }
-
- /* Update run-time error counts. The key is the error id which
- * is always a static string */
- g_hash_table_insert(errors, (void*)key, GINT_TO_POINTER(
- GPOINTER_TO_INT(g_hash_table_lookup(errors, key)) + 1));
-
- /* Issue the D-Bus signal */
- ril_plugin_dbus_signal_modem_error(slot->plugin->dbus,
- slot->index, key, message);
+ sailfish_manager_set_sim_state(slot->handle, sim_state);
}
-static void ril_plugin_handle_error(struct ril_slot *slot, const char *msg)
+static void ril_plugin_handle_error(ril_slot *slot, const char *message)
{
- ofono_error("%s %s", ril_slot_debug_prefix(slot), msg);
- ril_plugin_count_error(slot, RIL_ERROR_ID_RILD_RESTART, msg);
+ ofono_error("%s %s", ril_slot_debug_prefix(slot), message);
+ sailfish_manager_slot_error(slot->handle, RIL_ERROR_ID_RILD_RESTART,
+ message);
ril_plugin_shutdown_slot(slot, TRUE);
- ril_plugin_update_modem_paths_full(slot->plugin);
ril_plugin_retry_init_io(slot);
}
static void ril_plugin_slot_error(GRilIoChannel *io, const GError *error,
void *data)
{
- ril_plugin_handle_error((struct ril_slot *)data, GERRMSG(error));
+ ril_plugin_handle_error((ril_slot *)data, GERRMSG(error));
}
static void ril_plugin_slot_disconnected(GRilIoChannel *io, void *data)
{
- ril_plugin_handle_error((struct ril_slot *)data, "disconnected");
+ ril_plugin_handle_error((ril_slot *)data, "disconnected");
}
-static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
+static void ril_plugin_caps_switch_aborted(struct ril_radio_caps_manager *mgr,
void *data)
{
- struct ril_slot *slot = data;
-
- DBG("%s %d", ril_slot_debug_prefix(slot), online);
- GASSERT(slot->modem);
- GASSERT(slot->modem == modem);
-
- ril_radio_set_online(slot->radio, online);
- ril_plugin_update_modem_paths_full(slot->plugin);
-}
-
-static void ril_plugin_modem_removed(struct ril_modem *modem, void *data)
-{
- struct ril_slot *slot = data;
-
- DBG("");
- GASSERT(slot->modem);
- GASSERT(slot->modem == modem);
-
- if (slot->oem_raw) {
- ril_oem_raw_free(slot->oem_raw);
- slot->oem_raw = NULL;
- }
-
- if (slot->sim_info_dbus) {
- ril_sim_info_dbus_free(slot->sim_info_dbus);
- slot->sim_info_dbus = NULL;
- }
-
- if (slot->cell_info_dbus) {
- ril_cell_info_dbus_free(slot->cell_info_dbus);
- slot->cell_info_dbus = NULL;
- }
-
- slot->modem = NULL;
- ril_radio_set_online(slot->radio, FALSE);
- ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
- ril_plugin_update_modem_paths_full(slot->plugin);
+ ril_plugin *plugin = data;
+ DBG("radio caps switch aborted");
+ sailfish_manager_error(plugin->handle,
+ RIL_ERROR_ID_CAPS_SWITCH_ABORTED,
+ "Capability switch transaction aborted");
}
static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
guint id, guint code, const void *data, guint data_len, void *user_data)
{
- static const GLogModule* log_module = &ril_debug_trace_module;
+ static const GLogModule *log_module = &ril_debug_trace_module;
const char *prefix = io->name ? io->name : "";
const char dir = (type == GRILIO_PACKET_REQ) ? '<' : '>';
const char *scode;
@@ -918,7 +602,7 @@
}
}
-static void ril_debug_dump_update(struct ril_slot *slot)
+static void ril_debug_dump_update(ril_slot *slot)
{
if (slot->io) {
if (ril_debug_dump.flags & OFONO_DEBUG_FLAG_PRINT) {
@@ -934,7 +618,7 @@
}
}
-static void ril_debug_trace_update(struct ril_slot *slot)
+static void ril_debug_trace_update(ril_slot *slot)
{
if (slot->io) {
if (ril_debug_trace.flags & OFONO_DEBUG_FLAG_PRINT) {
@@ -961,59 +645,42 @@
}
}
-static const char *ril_plugin_log_prefix(struct ril_slot *slot)
+static const char *ril_plugin_log_prefix(ril_slot *slot)
{
return ril_plugin_multisim(slot->plugin) ?
ril_slot_debug_prefix(slot) : "";
}
-static void ril_plugin_create_modem(struct ril_slot *slot)
+static void ril_plugin_create_modem(ril_slot *slot)
{
struct ril_modem *modem;
+ const char *log_prefix = ril_plugin_log_prefix(slot);
DBG("%s", ril_slot_debug_prefix(slot));
GASSERT(slot->io && slot->io->connected);
GASSERT(!slot->modem);
- modem = ril_modem_create(slot->io, ril_plugin_log_prefix(slot),
- &slot->pub, slot->radio, slot->network, slot->sim_card,
- slot->data, slot->sim_settings, slot->cell_info);
+ modem = ril_modem_create(slot->io, log_prefix, slot->path, slot->imei,
+ slot->imeisv, slot->ecclist_file, &slot->config, slot->radio,
+ slot->network, slot->sim_card, slot->data, slot->sim_settings,
+ slot->cell_info);
if (modem) {
- struct ofono_sim *sim = ril_modem_ofono_sim(modem);
-
slot->modem = modem;
- slot->sim_watch_id = __ofono_modem_add_atom_watch(modem->ofono,
- OFONO_ATOM_TYPE_SIM, ril_plugin_sim_watch,
- slot, ril_plugin_sim_watch_done);
- if (sim) {
- ril_plugin_register_sim(slot, sim);
- ril_plugin_update_ofono_sim(slot);
- }
-
- slot->sim_info_dbus = ril_sim_info_dbus_new(slot->modem,
- slot->sim_info);
if (slot->cell_info) {
- slot->cell_info_dbus =
- ril_cell_info_dbus_new(slot->modem,
+#pragma message("Cell info interfaces need to be moved to the common Sailfish OS area")
+ slot->cell_info_dbus = ril_cell_info_dbus_new(modem,
slot->cell_info);
}
-
- slot->oem_raw = ril_oem_raw_new(slot->modem,
- ril_plugin_log_prefix(slot));
-
- ril_modem_set_removed_cb(modem, ril_plugin_modem_removed, slot);
- ril_modem_set_online_cb(modem, ril_plugin_modem_online, slot);
+ slot->oem_raw = ril_oem_raw_new(modem, log_prefix);
} else {
ril_plugin_shutdown_slot(slot, TRUE);
}
-
- ril_plugin_update_modem_paths_full(slot->plugin);
}
-static void ril_plugin_check_modem(struct ril_slot *slot)
+static void ril_plugin_check_modem(ril_slot *slot)
{
- if (!slot->modem && slot->pub.enabled &&
+ if (!slot->modem && slot->handle->enabled &&
slot->io && slot->io->connected &&
!slot->imei_req_id && slot->imei) {
ril_plugin_create_modem(slot);
@@ -1026,7 +693,7 @@
* Otherwise bad things may happen (like the modem never registering
* on the network).
*/
-static void ril_plugin_power_check(struct ril_slot *slot)
+static void ril_plugin_power_check(ril_slot *slot)
{
ril_radio_confirm_power_on(slot->radio);
}
@@ -1035,18 +702,56 @@
const void *data, guint len, void *user_data)
{
if (ril_radio_state_parse(data, len) == RADIO_STATE_OFF) {
- struct ril_slot *slot = user_data;
+ ril_slot *slot = user_data;
DBG("power off for slot %u", slot->config.slot);
ril_plugin_foreach_slot(slot->plugin, ril_plugin_power_check);
}
}
-static void ril_plugin_slot_connected(struct ril_slot *slot)
+static void ril_plugin_radio_caps_cb(const struct ril_radio_capability *cap,
+ void *user_data)
+{
+ ril_slot *slot = user_data;
+
+ DBG("radio caps %s", cap ? "ok" : "NOT supported");
+ GASSERT(slot->caps_check_id);
+ slot->caps_check_id = 0;
+
+ if (cap) {
+ ril_plugin *plugin = slot->plugin;
+
+ if (!plugin->caps_manager) {
+ plugin->caps_manager = ril_radio_caps_manager_new
+ (plugin->data_manager);
+ plugin->caps_manager_event_id =
+ ril_radio_caps_manager_add_aborted_handler(
+ plugin->caps_manager,
+ ril_plugin_caps_switch_aborted,
+ plugin);
+ }
+
+ GASSERT(!slot->caps);
+ slot->caps = ril_radio_caps_new(plugin->caps_manager,
+ ril_plugin_log_prefix(slot), slot->io, slot->data,
+ slot->radio, slot->sim_card, slot->network,
+ &slot->config, cap);
+ }
+}
+
+static void ril_plugin_slot_connected_all(ril_slot *slot, void *param)
{
- struct ril_plugin_priv *plugin = slot->plugin;
+ if (!slot->handle) {
+ (*((gboolean*)param)) = FALSE; /* Not all */
+ }
+}
+
+static void ril_plugin_slot_connected(ril_slot *slot)
+{
+ ril_plugin *plugin = slot->plugin;
+ const struct ril_plugin_settings *ps = &plugin->settings;
const char *log_prefix = ril_plugin_log_prefix(slot);
- GRilIoRequest* req;
+ GRilIoRequest *req;
ofono_debug("%s version %u", (slot->name && slot->name[0]) ?
slot->name : "RIL", slot->io->ril_version);
@@ -1064,6 +769,8 @@
*/
GASSERT(!slot->imei_req_id);
req = grilio_request_new();
+ /* Don't allow any other requests while this one is pending */
+ grilio_request_set_blocking(req, TRUE);
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
slot->imei_req_id = grilio_channel_send_request_full(slot->io,
req, RIL_REQUEST_DEVICE_IDENTITY,
@@ -1090,35 +797,62 @@
GASSERT(!slot->received_sim_status);
GASSERT(!slot->network);
- slot->network = ril_network_new(slot->io, log_prefix, slot->radio,
- slot->sim_card, slot->sim_settings);
- ril_sim_info_set_network(slot->sim_info, slot->network);
+ slot->network = ril_network_new(slot->path, slot->io, log_prefix,
+ slot->radio, slot->sim_card, slot->sim_settings);
GASSERT(!slot->data);
- slot->data = ril_data_new(slot->plugin->data_manager, log_prefix,
+ slot->data = ril_data_new(plugin->data_manager, log_prefix,
slot->radio, slot->network, slot->io, &slot->data_opt,
&slot->config);
GASSERT(!slot->cell_info);
- if (slot->io->ril_version > 8) {
+ if (slot->io->ril_version >= 9) {
slot->cell_info = ril_cell_info_new(slot->io, log_prefix,
- plugin->display, slot->radio, slot->sim_card);
+ slot->display, slot->radio, slot->sim_card);
+ }
+
+ GASSERT(!slot->caps);
+ GASSERT(!slot->caps_check_id);
+ if (ril_plugin_multisim(plugin) &&
+ (ps->set_radio_cap == RIL_SET_RADIO_CAP_ENABLED ||
+ (ps->set_radio_cap == RIL_SET_RADIO_CAP_AUTO &&
+ slot->io->ril_version >= 11))) {
+ /* Check if RIL really support radio capability management */
+ slot->caps_check_id = ril_radio_caps_check(slot->io,
+ ril_plugin_radio_caps_cb, slot);
+ }
+
+ if (!slot->handle) {
+ gboolean all = TRUE;
+
+ GASSERT(plugin->start_timeout_id);
+ slot->handle = sailfish_manager_slot_add(plugin->handle, slot,
+ slot->path, slot->config.techs, slot->imei,
+ slot->imeisv, ril_plugin_sim_state(slot));
+
+ ril_plugin_foreach_slot_param(plugin,
+ ril_plugin_slot_connected_all, &all);
+ if (all && plugin->start_timeout_id) {
+ DBG("Startup done!");
+ g_source_remove(plugin->start_timeout_id);
+ GASSERT(!plugin->start_timeout_id);
+ sailfish_slot_manager_started(plugin->handle);
+ }
}
ril_plugin_send_screen_state(slot);
ril_plugin_check_modem(slot);
- ril_plugin_update_ready(plugin);
}
static void ril_plugin_slot_connected_cb(GRilIoChannel *io, void *user_data)
{
- struct ril_slot *slot = user_data;
+ ril_slot *slot = user_data;
ril_plugin_remove_slot_handler(slot, IO_EVENT_CONNECTED);
ril_plugin_slot_connected(slot);
}
-static void ril_plugin_init_io(struct ril_slot *slot)
+static void ril_plugin_init_io(ril_slot *slot)
{
if (!slot->io) {
DBG("%s %s", slot->sockpath, slot->sub);
@@ -1136,8 +870,13 @@
grilio_channel_add_error_handler(slot->io,
ril_plugin_slot_error, slot);
slot->io_event_id[IO_EVENT_EOF] =
- grilio_channel_add_disconnected_handler(slot->io,
- ril_plugin_slot_disconnected, slot);
+ grilio_channel_add_disconnected_handler(
+ slot->io,
+ ril_plugin_slot_disconnected,
+ slot);
+
+ /* Serialize requests at startup */
+ slot->serialize_id = grilio_channel_serialize(slot->io);
if (slot->io->connected) {
ril_plugin_slot_connected(slot);
@@ -1158,7 +897,7 @@
static gboolean ril_plugin_retry_init_io_cb(gpointer data)
{
- struct ril_slot *slot = data;
+ ril_slot *slot = data;
GASSERT(slot->retry_id);
slot->retry_id = 0;
@@ -1167,7 +906,7 @@
return G_SOURCE_REMOVE;
}
-static void ril_plugin_retry_init_io(struct ril_slot *slot)
+static void ril_plugin_retry_init_io(ril_slot *slot)
{
if (slot->retry_id) {
g_source_remove(slot->retry_id);
@@ -1178,17 +917,42 @@
ril_plugin_retry_init_io_cb, slot);
}
-static struct ril_slot *ril_plugin_slot_new(const char *sockpath,
- const char *path, const char *name, guint slot_index)
+static void ril_plugin_slot_modem_changed(struct sailfish_watch *w,
+ void *user_data)
+{
+ ril_slot *slot = user_data;
+
+ DBG("%s", slot->path);
+ if (!w->modem) {
+ GASSERT(slot->modem);
+
+ if (slot->oem_raw) {
+ ril_oem_raw_free(slot->oem_raw);
+ slot->oem_raw = NULL;
+ }
+
+ if (slot->cell_info_dbus) {
+ ril_cell_info_dbus_free(slot->cell_info_dbus);
+ slot->cell_info_dbus = NULL;
+ }
+
+ slot->modem = NULL;
+ ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
+ }
+}
+
+static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *path,
+ char *name, guint slot_index)
{
- struct ril_slot *slot = g_new0(struct ril_slot, 1);
+ ril_slot *slot = g_new0(ril_slot, 1);
- slot->sockpath = g_strdup(sockpath);
- slot->path = g_strdup(path);
- slot->name = g_strdup(name);
+ slot->sockpath = sockpath;
+ slot->path = path;
+ slot->name = name;
slot->config.slot = slot_index;
slot->config.techs = RILMODEM_DEFAULT_TECHS;
slot->config.empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
+ slot->config.enable_voicecall = RILMODEM_DEFAULT_ENABLE_VOICECALL;
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
slot->data_opt.allow_data = RILMODEM_DEFAULT_DATA_OPT;
@@ -1197,10 +961,30 @@
RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT;
slot->data_opt.data_call_retry_delay_ms =
RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY;
- slot->pub.errors = g_hash_table_new(g_str_hash, g_str_equal);
+
+ slot->display = mce_display_new();
+ slot->display_on = ril_plugin_display_on(slot->display);
+ slot->display_event_id[DISPLAY_EVENT_VALID] =
+ mce_display_add_valid_changed_handler(slot->display,
+ ril_plugin_display_cb, slot);
+ slot->display_event_id[DISPLAY_EVENT_STATE] =
+ mce_display_add_state_changed_handler(slot->display,
+ ril_plugin_display_cb, slot);
+
+ slot->watch = sailfish_watch_new(path);
+ slot->watch_event_id[WATCH_EVENT_MODEM] =
+ sailfish_watch_add_modem_changed_handler(slot->watch,
+ ril_plugin_slot_modem_changed, slot);
return slot;
}
+static ril_slot *ril_plugin_slot_new(const char *sockpath, const char *path,
+ const char *name, guint slot_index)
+{
+ return ril_plugin_slot_new_take(g_strdup(sockpath), g_strdup(path),
+ g_strdup(name), slot_index);
+}
+
static GSList *ril_plugin_create_default_config()
{
GSList *list = NULL;
@@ -1215,7 +999,7 @@
ril_plugin_slot_new(RILMODEM_DEFAULT_SOCK2,
RILCONF_PATH_PREFIX "1", "RIL2", 1));
} else {
- struct ril_slot * slot =
+ ril_slot *slot =
ril_plugin_slot_new(RILMODEM_DEFAULT_SOCK,
RILCONF_PATH_PREFIX "0", "RIL", 0);
@@ -1230,220 +1014,193 @@
return list;
}
-static struct ril_slot *ril_plugin_slot_from_config_group(GKeyFile *file,
+static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
const char *group)
{
- gboolean optional = RILMODEM_DEFAULT_OPTIONAL;
+ ril_slot *slot = NULL;
char *sock = g_key_file_get_string(file, group, RILCONF_SOCKET, NULL);
+ if (sock) {
+ int value;
+ char *strval;
+ char **strv;
+ char *sub = ril_config_get_string(file, group, RILCONF_SUB);
+
+ slot = ril_plugin_slot_new_take(sock,
+ g_strconcat("/", group, NULL),
+ ril_config_get_string(file, group, RILCONF_NAME),
+ RILMODEM_DEFAULT_SLOT);
+
+ if (sub && strlen(sub) == RIL_SUB_SIZE) {
+ DBG("%s: %s:%s", group, sock, sub);
+ slot->sub = sub;
+ } else {
+ DBG("%s: %s", group, sock);
+ g_free(sub);
+ }
- if (!sock) {
- ofono_warn("no socket path for %s", group);
- } else if (ril_config_get_boolean(file, group, RILCONF_OPTIONAL,
- &optional) && optional &&
- !g_file_test(sock, G_FILE_TEST_EXISTS)) {
- ofono_info("%s does not exist, ignoring %s", sock, group);
- } else {
- struct ril_slot *slot = ril_plugin_slot_new(NULL, NULL, NULL,
- RILMODEM_DEFAULT_SLOT);
-
- slot->sockpath = sock;
- slot->path = g_strconcat("/", group, NULL);
- return slot;
- }
- g_free(sock);
- return NULL;
-}
-
-static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
- const char *group)
-{
- int value;
- char *str;
- char **strv;
- struct ril_slot_config *config;
- struct ril_slot *slot = ril_plugin_slot_from_config_group(file, group);
-
- if (!slot) {
- return NULL;
- }
-
- config = &slot->config;
- slot->name = ril_config_get_string(file, group, RILCONF_NAME);
-
- str = ril_config_get_string(file, group, RILCONF_SUB);
- if (str && strlen(str) == RIL_SUB_SIZE) {
- DBG("%s: %s:%s", group, slot->sockpath, str);
- slot->sub = str;
- } else {
- DBG("%s: %s", group, slot->sockpath);
- g_free(str);
- }
-
- if (ril_config_get_integer(file, group, RILCONF_SLOT, &value) &&
+ if (ril_config_get_integer(file, group, RILCONF_SLOT, &value) &&
value >= 0) {
- config->slot = value;
- DBG("%s: slot %u", group, config->slot);
- }
+ slot->config.slot = value;
+ DBG("%s: slot %u", group, slot->config.slot);
+ }
- if (ril_config_get_integer(file, group, RILCONF_TIMEOUT,
+ if (ril_config_get_integer(file, group, RILCONF_TIMEOUT,
&slot->timeout)) {
- DBG("%s: timeout %d", group, slot->timeout);
- }
+ DBG("%s: timeout %d", group, slot->timeout);
+ }
- strv = ril_config_get_strings(file, group, RILCONF_TECHS, ',');
- if (strv) {
- char **p;
+ if (ril_config_get_boolean(file, group,
+ RILCONF_ENABLE_VOICECALL,
+ &slot->config.enable_voicecall)) {
+ DBG("%s: %s %s", group, RILCONF_ENABLE_VOICECALL,
+ slot->config.enable_voicecall ? "yes" : "no");
+ }
- config->techs = 0;
- for (p = strv; *p; p++) {
- const char *s = *p;
- enum ofono_radio_access_mode mode;
+ strv = ril_config_get_strings(file, group, RILCONF_TECHS, ',');
+ if (strv) {
+ char **p;
- if (!s[0]) {
- continue;
- }
+ slot->config.techs = 0;
+ for (p = strv; *p; p++) {
+ const char *s = *p;
+ enum ofono_radio_access_mode m;
- if (!strcmp(s, "all")) {
- config->techs = OFONO_RADIO_ACCESS_MODE_ALL;
- break;
- }
+ if (!s[0]) {
+ continue;
+ }
- if (!ofono_radio_access_mode_from_string(s, &mode)) {
- ofono_warn("Unknown technology %s "
+ if (!strcmp(s, "all")) {
+ slot->config.techs =
+ OFONO_RADIO_ACCESS_MODE_ALL;
+ break;
+ }
+
+ if (!ofono_radio_access_mode_from_string(s,
+ &m)) {
+ ofono_warn("Unknown technology %s "
"in [%s] section of %s", s,
group, RILMODEM_CONF_FILE);
- continue;
- }
+ continue;
+ }
- if (mode == OFONO_RADIO_ACCESS_MODE_ANY) {
- config->techs = OFONO_RADIO_ACCESS_MODE_ALL;
- break;
- }
+ if (m == OFONO_RADIO_ACCESS_MODE_ANY) {
+ slot->config.techs =
+ OFONO_RADIO_ACCESS_MODE_ALL;
+ break;
+ }
- config->techs |= mode;
+ slot->config.techs |= m;
+ }
+ g_strfreev(strv);
}
- g_strfreev(strv);
- }
- /* "enable4G" is deprecated */
- value = config->techs;
- if (ril_config_get_flag(file, group, RILCONF_4G,
+ /* "enable4G" is deprecated */
+ value = slot->config.techs;
+ if (ril_config_get_flag(file, group, RILCONF_4G,
OFONO_RADIO_ACCESS_MODE_LTE, &value)) {
- config->techs = value;
- }
+ slot->config.techs = value;
+ }
- DBG("%s: technologies 0x%02x", group, config->techs);
+ DBG("%s: technologies 0x%02x", group, slot->config.techs);
- if (ril_config_get_boolean(file, group, RILCONF_EMPTY_PIN_QUERY,
- &config->empty_pin_query)) {
- DBG("%s: %s %s", group, RILCONF_EMPTY_PIN_QUERY,
- config->empty_pin_query ? "on" : "off");
- }
+ if (ril_config_get_boolean(file, group, RILCONF_EMPTY_PIN_QUERY,
+ &slot->config.empty_pin_query)) {
+ DBG("%s: %s %s", group, RILCONF_EMPTY_PIN_QUERY,
+ slot->config.empty_pin_query ? "on" : "off");
+ }
- if (ril_config_get_flag(file, group, RILCONF_UICC_WORKAROUND,
+ if (ril_config_get_flag(file, group, RILCONF_UICC_WORKAROUND,
RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND,
&slot->sim_flags)) {
- DBG("%s: %s %s", group, RILCONF_UICC_WORKAROUND,
+ DBG("%s: %s %s", group, RILCONF_UICC_WORKAROUND,
(slot->sim_flags &
RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND) ?
"on" : "off");
- }
-
- str = ril_config_get_string(file, group, RILCONF_ALLOW_DATA_REQ);
- if (str) {
- /*
- * Some people are thinking that # is a comment
- * anywhere on the line, not just at the beginning
- */
- char *comment = strchr(str, '#');
- if (comment) *comment = 0;
- g_strstrip(str);
- slot->data_opt.allow_data =
- !strcasecmp(str, "on") ? RIL_ALLOW_DATA_ON :
- !strcasecmp(str, "off")? RIL_ALLOW_DATA_OFF :
- RIL_ALLOW_DATA_AUTO;
- DBG("%s: %s %s", group, RILCONF_ALLOW_DATA_REQ,
- slot->data_opt.allow_data == RIL_ALLOW_DATA_ON ? "on":
- slot->data_opt.allow_data == RIL_ALLOW_DATA_OFF ?
- "off": "auto");
- g_free(str);
- }
+ }
- str = ril_config_get_string(file, group, RILCONF_DATA_CALL_FORMAT);
- if (str) {
- /*
- * Some people are thinking that # is a comment
- * anywhere on the line, not just at the beginning
- */
- char *comment = strchr(str, '#');
- if (comment) *comment = 0;
- g_strstrip(str);
- slot->data_opt.data_call_format =
- !strcmp(str, "6") ? RIL_DATA_CALL_FORMAT_6:
- !strcmp(str, "9") ? RIL_DATA_CALL_FORMAT_9:
- !strcmp(str, "11")? RIL_DATA_CALL_FORMAT_11:
- RIL_DATA_CALL_FORMAT_AUTO;
- if (slot->data_opt.data_call_format ==
- RIL_DATA_CALL_FORMAT_AUTO) {
- DBG("%s: %s auto", group, RILCONF_DATA_CALL_FORMAT);
- } else {
- DBG("%s: %s %d", group, RILCONF_DATA_CALL_FORMAT,
- slot->data_opt.data_call_format);
+ if (ril_config_get_enum(file, group, RILCONF_ALLOW_DATA_REQ,
+ &value, "auto", RIL_ALLOW_DATA_AUTO,
+ "on", RIL_ALLOW_DATA_ENABLED,
+ "off", RIL_ALLOW_DATA_DISABLED, NULL)) {
+ DBG("%s: %s %s", group, RILCONF_ALLOW_DATA_REQ,
+ value == RIL_ALLOW_DATA_ENABLED ? "enabled":
+ value == RIL_ALLOW_DATA_DISABLED ? "disabled":
+ "auto");
+ slot->data_opt.allow_data = value;
+ }
+
+ if (ril_config_get_enum(file, group, RILCONF_DATA_CALL_FORMAT,
+ &value, "auto", RIL_DATA_CALL_FORMAT_AUTO,
+ "6", RIL_DATA_CALL_FORMAT_6,
+ "9", RIL_DATA_CALL_FORMAT_9,
+ "11", RIL_DATA_CALL_FORMAT_11, NULL)) {
+ if (value == RIL_DATA_CALL_FORMAT_AUTO) {
+ DBG("%s: %s auto", group,
+ RILCONF_DATA_CALL_FORMAT);
+ } else {
+ DBG("%s: %s %d", group,
+ RILCONF_DATA_CALL_FORMAT, value);
+ }
+ slot->data_opt.data_call_format = value;
}
- g_free(str);
- }
- if (ril_config_get_integer(file, group, RILCONF_DATA_CALL_RETRY_LIMIT,
- &value) && value >= 0) {
- DBG("%s: %s %d", group, RILCONF_DATA_CALL_RETRY_LIMIT, value);
- slot->data_opt.data_call_retry_limit = value;
- }
+ if (ril_config_get_integer(file, group,
+ RILCONF_DATA_CALL_RETRY_LIMIT, &value) && value >= 0) {
+ DBG("%s: %s %d", group,
+ RILCONF_DATA_CALL_RETRY_LIMIT, value);
+ slot->data_opt.data_call_retry_limit = value;
+ }
- if (ril_config_get_integer(file, group, RILCONF_DATA_CALL_RETRY_DELAY,
- &value) && value >= 0) {
- DBG("%s: %s %d ms", group, RILCONF_DATA_CALL_RETRY_DELAY,
- value);
- slot->data_opt.data_call_retry_delay_ms = value;
- }
+ if (ril_config_get_integer(file, group,
+ RILCONF_DATA_CALL_RETRY_DELAY, &value) && value >= 0) {
+ DBG("%s: %s %d ms", group,
+ RILCONF_DATA_CALL_RETRY_DELAY, value);
+ slot->data_opt.data_call_retry_delay_ms = value;
+ }
- slot->ecclist_file = ril_config_get_string(file, group,
+ slot->ecclist_file = ril_config_get_string(file, group,
RILCONF_ECCLIST_FILE);
- if (slot->ecclist_file && slot->ecclist_file[0]) {
- DBG("%s: %s %s", group, RILCONF_ECCLIST_FILE,
+ if (slot->ecclist_file && slot->ecclist_file[0]) {
+ DBG("%s: %s %s", group, RILCONF_ECCLIST_FILE,
slot->ecclist_file);
- slot->pub.ecclist_file = slot->ecclist_file;
- } else {
- g_free(slot->ecclist_file);
- slot->ecclist_file = NULL;
- }
+ } else {
+ g_free(slot->ecclist_file);
+ slot->ecclist_file = NULL;
+ }
- config->local_hangup_reasons = ril_config_get_ints(file, group,
- RILCONF_LOCAL_HANGUP_REASONS);
- str = ril_config_ints_to_string(config->local_hangup_reasons, ',');
- if (str) {
- DBG("%s: %s %s", group, RILCONF_LOCAL_HANGUP_REASONS, str);
- g_free(str);
- }
-
- config->remote_hangup_reasons = ril_config_get_ints(file, group,
- RILCONF_REMOTE_HANGUP_REASONS);
- str = ril_config_ints_to_string(config->remote_hangup_reasons, ',');
- if (str) {
- DBG("%s: %s %s", group, RILCONF_REMOTE_HANGUP_REASONS, str);
- g_free(str);
+ slot->config.local_hangup_reasons = ril_config_get_ints(file,
+ group, RILCONF_LOCAL_HANGUP_REASONS);
+ strval = ril_config_ints_to_string(
+ slot->config.local_hangup_reasons, ',');
+ if (strval) {
+ DBG("%s: %s %s", group, RILCONF_LOCAL_HANGUP_REASONS,
+ strval);
+ g_free(strval);
+ }
+
+ slot->config.remote_hangup_reasons = ril_config_get_ints(file,
+ group, RILCONF_REMOTE_HANGUP_REASONS);
+ strval = ril_config_ints_to_string(
+ slot->config.remote_hangup_reasons, ',');
+ if (strval) {
+ DBG("%s: %s %s", group, RILCONF_REMOTE_HANGUP_REASONS,
+ strval);
+ g_free(strval);
+ }
+
+ } else {
+ DBG("no socket path in %s", group);
}
return slot;
}
-static void ril_plugin_delete_slot(struct ril_slot *slot)
+static void ril_plugin_delete_slot(ril_slot *slot)
{
ril_plugin_shutdown_slot(slot, TRUE);
- ril_sim_info_unref(slot->sim_info);
ril_sim_settings_unref(slot->sim_settings);
gutil_ints_unref(slot->config.local_hangup_reasons);
gutil_ints_unref(slot->config.remote_hangup_reasons);
- g_hash_table_destroy(slot->pub.errors);
g_free(slot->path);
g_free(slot->imei);
g_free(slot->imeisv);
@@ -1454,14 +1211,14 @@
g_free(slot);
}
-static GSList *ril_plugin_add_slot(GSList *slots, struct ril_slot *new_slot)
+static GSList *ril_plugin_add_slot(GSList *slots, ril_slot *new_slot)
{
GSList *link = slots;
/* Slot numbers and paths must be unique */
while (link) {
GSList *next = link->next;
- struct ril_slot *slot = link->data;
+ ril_slot *slot = link->data;
gboolean delete_this_slot = FALSE;
if (!strcmp(slot->path, new_slot->path)) {
@@ -1484,11 +1241,24 @@
return g_slist_append(slots, new_slot);
}
+static ril_slot *ril_plugin_find_slot_number(GSList *slots, guint number)
+{
+ while (slots) {
+ ril_slot *slot = slots->data;
+
+ if (slot->config.slot == number) {
+ return slot;
+ }
+ slots = slots->next;
+ }
+ return NULL;
+}
+
static guint ril_plugin_find_unused_slot(GSList *slots)
{
- guint number;
+ guint number = 0;
- for (number = 0; ril_plugin_find_slot_number(slots, number); number++);
+ while (ril_plugin_find_slot_number(slots, number)); number++;
return number;
}
@@ -1504,25 +1274,35 @@
const char *group = groups[i];
if (g_str_has_prefix(group, RILCONF_DEV_PREFIX)) {
/* Modem configuration */
- struct ril_slot *slot =
- ril_plugin_parse_config_group(file, group);
+ ril_slot *slot = ril_plugin_parse_config_group(file,
+ group);
if (slot) {
list = ril_plugin_add_slot(list, slot);
}
} else if (!strcmp(group, RILCONF_SETTINGS_GROUP)) {
/* Plugin configuration */
+ int value;
+
ril_config_get_flag(file, group,
RILCONF_SETTINGS_3GHANDOVER,
RIL_DATA_MANAGER_3GLTE_HANDOVER,
&ps->dm_flags);
+
+ if (ril_config_get_enum(file, group,
+ RILCONF_SETTINGS_SET_RADIO_CAP, &value,
+ "auto", RIL_SET_RADIO_CAP_AUTO,
+ "on", RIL_SET_RADIO_CAP_ENABLED,
+ "off", RIL_SET_RADIO_CAP_DISABLED, NULL)) {
+ ps->set_radio_cap = value;
+ }
}
}
/* Automatically assign slot numbers */
link = list;
while (link) {
- struct ril_slot *slot = link->data;
+ ril_slot *slot = link->data;
if (slot->config.slot == RILMODEM_DEFAULT_SLOT) {
slot->config.slot = ril_plugin_find_unused_slot(list);
}
@@ -1562,11 +1342,6 @@
return list;
}
-static void ril_plugin_destroy_slot(gpointer data)
-{
- ril_plugin_delete_slot((struct ril_slot *)data);
-}
-
/* RIL expects user radio */
static void ril_plugin_switch_user()
{
@@ -1597,225 +1372,180 @@
}
}
-static void ril_plugin_update_enabled_slot(struct ril_slot *slot)
+static void ril_plugin_init_slots(ril_plugin *plugin)
{
- if (slot->pub.enabled) {
- DBG("%s enabled", ril_slot_debug_prefix(slot));
- ril_plugin_check_modem(slot);
- }
-}
+ int i;
+ GSList *link;
-static void ril_plugin_update_disabled_slot(struct ril_slot *slot)
-{
- if (!slot->pub.enabled) {
- DBG("%s disabled", ril_slot_debug_prefix(slot));
- ril_plugin_shutdown_slot(slot, FALSE);
- ril_plugin_update_modem_paths_full(slot->plugin);
+ for (i = 0, link = plugin->slots; link; link = link->next, i++) {
+ ril_slot *slot = link->data;
+
+ slot->index = i;
+ slot->plugin = plugin;
+ slot->sim_settings = ril_sim_settings_new(slot->path,
+ slot->config.techs);
+ slot->retry_id = g_idle_add(ril_plugin_retry_init_io_cb, slot);
}
}
-static void ril_plugin_update_slots(struct ril_plugin_priv *plugin)
+static void ril_plugin_drop_orphan_slots(ril_plugin *plugin)
{
- ril_plugin_foreach_slot(plugin, ril_plugin_update_disabled_slot);
- ril_plugin_foreach_slot(plugin, ril_plugin_update_enabled_slot);
- ril_plugin_update_modem_paths_full(plugin);
-}
+ GSList *l = plugin->slots;
-struct ril_plugin_set_enabled_slots_data {
- gchar * const * enabled;
- gboolean all_enabled;
- gboolean changed;
-};
+ while (l) {
+ GSList *next = l->next;
+ ril_slot *slot = l->data;
-static void ril_plugin_enabled_slots_proc(gpointer data, gpointer user_data)
-{
- struct ril_slot *slot = data;
- if (slot->pub.enabled) {
- char ***list = user_data;
- *list = gutil_strv_add(*list, slot->path);
+ if (!slot->handle) {
+ ril_plugin_delete_slot(slot);
+ plugin->slots = g_slist_delete_link(plugin->slots, l);
+ }
+ l = next;
}
}
-static void ril_plugin_set_enabled_slots_proc(gpointer data, gpointer user_data)
+static gboolean ril_plugin_manager_start_timeout(gpointer user_data)
{
- struct ril_slot *slot = data;
- struct ril_plugin_set_enabled_slots_data *context = user_data;
- const gboolean was_enabled = slot->pub.enabled;
+ ril_plugin *plugin = user_data;
- slot->pub.enabled = gutil_strv_contains(context->enabled, slot->path);
+ DBG("");
+ plugin->start_timeout_id = 0;
+ ril_plugin_drop_orphan_slots(plugin);
+ sailfish_slot_manager_started(plugin->handle);
+ return G_SOURCE_REMOVE;
+}
- if ((was_enabled && !slot->pub.enabled) ||
- (!was_enabled && slot->pub.enabled)) {
- context->changed = TRUE;
- }
+static void ril_plugin_manager_start_done(gpointer user_data)
+{
+ ril_plugin *plugin = user_data;
- if (!slot->pub.enabled) {
- context->all_enabled = FALSE;
- }
+ DBG("");
+ plugin->start_timeout_id = 0;
+ ril_plugin_drop_orphan_slots(plugin);
}
-void ril_plugin_set_enabled_slots(struct ril_plugin *pub, gchar **slots)
+static ril_plugin *ril_plugin_manager_create(struct sailfish_slot_manager *m)
{
- struct ril_plugin_priv *plugin = ril_plugin_cast(pub);
- struct ril_plugin_set_enabled_slots_data context;
-
- context.enabled = slots;
- context.changed = FALSE;
- context.all_enabled = TRUE;
- g_slist_foreach(plugin->slots, ril_plugin_set_enabled_slots_proc,
- &context);
- if (context.changed) {
- char **new_slots = NULL;
+ ril_plugin *plugin = g_slice_new0(ril_plugin);
- g_slist_foreach(plugin->slots, ril_plugin_enabled_slots_proc,
- &new_slots);
+ DBG("");
+ plugin->handle = m;
+ plugin->settings.dm_flags = RILMODEM_DEFAULT_DM_FLAGS;
+ plugin->settings.set_radio_cap = RIL_SET_RADIO_CAP_AUTO;
+ return plugin;
+}
- /* Save the new config value. If it exactly matches the list
- * of available modems, delete the setting because that's the
- * default behavior. */
- if (context.all_enabled) {
- ril_plugin_set_config_string(plugin,
- RIL_STORE_ENABLED_SLOTS, NULL, TRUE);
- } else {
- const char *value;
- char *tmp;
+static guint ril_plugin_manager_start(ril_plugin *plugin)
+{
+ struct ril_plugin_settings *ps = &plugin->settings;
- if (new_slots) {
- tmp = g_strjoinv(RIL_STORE_SLOTS_SEP, new_slots);
- value = tmp;
- } else {
- tmp = NULL;
- value = "";
- }
+ DBG("");
+ GASSERT(!plugin->start_timeout_id);
+ plugin->slots = ril_plugin_load_config(RILMODEM_CONF_FILE, ps);
+ plugin->data_manager = ril_data_manager_new(ps->dm_flags);
+ ril_plugin_init_slots(plugin);
- ril_plugin_set_config_string(plugin,
- RIL_STORE_ENABLED_SLOTS, value, TRUE);
- g_free(tmp);
- }
- g_strfreev(new_slots);
- ril_plugin_dbus_signal(plugin->dbus,
- RIL_PLUGIN_SIGNAL_ENABLED_SLOTS);
+ ofono_modem_driver_register(&ril_modem_driver);
+ ofono_sim_driver_register(&ril_sim_driver);
+ ofono_sms_driver_register(&ril_sms_driver);
+ ofono_netmon_driver_register(&ril_netmon_driver);
+ ofono_netreg_driver_register(&ril_netreg_driver);
+ ofono_devinfo_driver_register(&ril_devinfo_driver);
+ ofono_voicecall_driver_register(&ril_voicecall_driver);
+ ofono_call_barring_driver_register(&ril_call_barring_driver);
+ ofono_call_forwarding_driver_register(&ril_call_forwarding_driver);
+ ofono_call_settings_driver_register(&ril_call_settings_driver);
+ ofono_call_volume_driver_register(&ril_call_volume_driver);
+ ofono_radio_settings_driver_register(&ril_radio_settings_driver);
+ ofono_gprs_driver_register(&ril_gprs_driver);
+ ofono_gprs_context_driver_register(&ril_gprs_context_driver);
+ ofono_phonebook_driver_register(&ril_phonebook_driver);
+ ofono_ussd_driver_register(&ril_ussd_driver);
+ ofono_cbs_driver_register(&ril_cbs_driver);
+ ofono_stk_driver_register(&ril_stk_driver);
- /* Add and remove modems */
- ril_plugin_update_slots(plugin);
+ if (plugin->slots) {
+ plugin->start_timeout_id =
+ g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
+ RIL_START_TIMEOUT_SEC,
+ ril_plugin_manager_start_timeout, plugin,
+ ril_plugin_manager_start_done);
}
+
+ return plugin->start_timeout_id;
}
-void ril_plugin_set_default_voice_imsi(struct ril_plugin *pub, const char *imsi)
+static void ril_plugin_manager_cancel_start(ril_plugin *plugin, guint id)
{
- struct ril_plugin_priv *plugin = ril_plugin_cast(pub);
-
- if (g_strcmp0(plugin->default_voice_imsi, imsi)) {
- DBG("Default voice sim set to %s", imsi ? imsi : "(auto)");
- g_free(plugin->default_voice_imsi);
- pub->default_voice_imsi =
- plugin->default_voice_imsi = g_strdup(imsi);
- ril_plugin_set_config_string(plugin, RIL_STORE_DEFAULT_VOICE_SIM,
- imsi, TRUE);
- ril_plugin_dbus_signal(plugin->dbus,
- RIL_PLUGIN_SIGNAL_VOICE_IMSI |
- ril_plugin_update_modem_paths(plugin));
- }
+ g_source_remove(id);
}
-void ril_plugin_set_default_data_imsi(struct ril_plugin *pub, const char *imsi)
+static void ril_plugin_manager_free(ril_plugin *plugin)
{
- struct ril_plugin_priv *plugin = ril_plugin_cast(pub);
-
- if (g_strcmp0(plugin->default_data_imsi, imsi)) {
- DBG("Default data sim set to %s", imsi ? imsi : "(auto)");
- g_free(plugin->default_data_imsi);
- pub->default_data_imsi =
- plugin->default_data_imsi = g_strdup(imsi);
- ril_plugin_set_config_string(plugin, RIL_STORE_DEFAULT_DATA_SIM,
- imsi, TRUE);
- ril_plugin_dbus_signal(plugin->dbus,
- RIL_PLUGIN_SIGNAL_DATA_IMSI |
- ril_plugin_update_modem_paths(plugin));
+ if (plugin) {
+ GASSERT(!plugin->slots);
+ ril_data_manager_unref(plugin->data_manager);
+ ril_radio_caps_manager_remove_handler(plugin->caps_manager,
+ plugin->caps_manager_event_id);
+ ril_radio_caps_manager_unref(plugin->caps_manager);
+ g_slice_free(ril_plugin, plugin);
}
}
-gboolean ril_plugin_set_mms_imsi(struct ril_plugin *pub, const char *imsi)
+static void ril_slot_set_data_role(ril_slot *slot, enum sailfish_data_role r)
{
- struct ril_plugin_priv *plugin = ril_plugin_cast(pub);
-
- if (imsi && imsi[0]) {
- if (g_strcmp0(plugin->mms_imsi, imsi)) {
- if (ril_plugin_find_slot_imsi(plugin->slots, imsi)) {
- DBG("MMS sim %s", imsi);
- g_free(plugin->mms_imsi);
- pub->mms_imsi = plugin->mms_imsi =
- g_strdup(imsi);
- ril_plugin_dbus_signal(plugin->dbus,
- RIL_PLUGIN_SIGNAL_MMS_IMSI |
- ril_plugin_update_modem_paths(plugin));
- } else {
- DBG("IMSI not found: %s", imsi);
- return FALSE;
- }
- }
- } else {
- if (plugin->mms_imsi) {
- DBG("No MMS sim");
- g_free(plugin->mms_imsi);
- pub->mms_imsi = plugin->mms_imsi = NULL;
- ril_plugin_dbus_signal(plugin->dbus,
- RIL_PLUGIN_SIGNAL_MMS_IMSI |
- ril_plugin_update_modem_paths(plugin));
- }
- }
-
- return TRUE;
+ ril_data_allow(slot->data,
+ (r == SAILFISH_DATA_ROLE_INTERNET) ? RIL_DATA_ROLE_INTERNET :
+ (r == SAILFISH_DATA_ROLE_MMS) ? RIL_DATA_ROLE_MMS :
+ RIL_DATA_ROLE_NONE);
}
-static void ril_plugin_init_slots(struct ril_plugin_priv *plugin)
+static void ril_slot_enabled_changed(struct sailfish_slot_impl *s)
{
- int i;
- GSList *link;
- ril_slot_info_ptr *info = g_new0(ril_slot_info_ptr,
- g_slist_length(plugin->slots) + 1);
-
- plugin->pub.slots = plugin->slots_info = info;
- for (i = 0, link = plugin->slots; link; link = link->next, i++) {
- struct ril_slot *slot = link->data;
-
- *info++ = &slot->pub;
- slot->index = i;
- slot->plugin = plugin;
- slot->pub.path = slot->path;
- slot->pub.config = &slot->config;
- slot->sim_info = ril_sim_info_new(ril_plugin_log_prefix(slot));
- slot->sim_settings = ril_sim_settings_new(&slot->config);
+ if (s->handle->enabled) {
+ ril_plugin_check_modem(s);
+ } else {
+ ril_plugin_shutdown_slot(s, FALSE);
}
-
- *info = NULL;
}
-static void ril_plugin_enable_disable_slot(gpointer data, gpointer user_data)
+static void ril_slot_free(ril_slot *slot)
{
- struct ril_slot *slot = data;
- slot->pub.enabled = gutil_strv_contains(user_data, slot->path);
-}
+ ril_plugin* plugin = slot->plugin;
-static void ril_plugin_enable_slot(struct ril_slot *slot)
-{
- slot->pub.enabled = TRUE;
+ ril_plugin_shutdown_slot(slot, TRUE);
+ plugin->slots = g_slist_remove(plugin->slots, slot);
+ mce_display_remove_handlers(slot->display, slot->display_event_id,
+ G_N_ELEMENTS(slot->display_event_id));
+ mce_display_unref(slot->display);
+ sailfish_watch_remove_all_handlers(slot->watch, slot->watch_event_id);
+ sailfish_watch_unref(slot->watch);
+ ril_sim_settings_unref(slot->sim_settings);
+ gutil_ints_unref(slot->config.local_hangup_reasons);
+ gutil_ints_unref(slot->config.remote_hangup_reasons);
+ g_free(slot->path);
+ g_free(slot->imei);
+ g_free(slot->imeisv);
+ g_free(slot->name);
+ g_free(slot->sockpath);
+ g_free(slot->sub);
+ g_free(slot->ecclist_file);
+ g_slice_free(ril_slot, slot);
}
-static struct ril_plugin_priv *ril_plugin = NULL;
+/* Global part (that requires access to global variables) */
+
+static struct sailfish_slot_driver_reg *ril_driver = NULL;
+static guint ril_driver_init_id = 0;
static void ril_debug_trace_notify(struct ofono_debug_desc *desc)
{
- if (ril_plugin) {
- ril_plugin_foreach_slot(ril_plugin, ril_debug_trace_update);
- }
+ ril_plugin_foreach_slot_manager(ril_driver, ril_debug_trace_update);
}
static void ril_debug_dump_notify(struct ofono_debug_desc *desc)
{
- if (ril_plugin) {
- ril_plugin_foreach_slot(ril_plugin, ril_debug_dump_update);
- }
+ ril_plugin_foreach_slot_manager(ril_driver, ril_debug_dump_update);
}
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc)
@@ -1836,16 +1566,34 @@
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_INHERIT;
}
-static int ril_plugin_init(void)
+static gboolean ril_plugin_start(gpointer user_data)
{
- char *enabled_slots;
- struct ril_plugin_settings ps;
+ static const struct sailfish_slot_driver ril_slot_driver = {
+ .name = RILMODEM_DRIVER,
+ .manager_create = ril_plugin_manager_create,
+ .manager_start = ril_plugin_manager_start,
+ .manager_cancel_start = ril_plugin_manager_cancel_start,
+ .manager_free = ril_plugin_manager_free,
+ .slot_enabled_changed = ril_slot_enabled_changed,
+ .slot_set_data_role = ril_slot_set_data_role,
+ .slot_free = ril_slot_free
+ };
+
+ DBG("");
+ ril_driver_init_id = 0;
- /* Default settings */
- ps.dm_flags = RILMODEM_DEFAULT_DM_FLAGS;
+ /* Switch the user to the one RIL expects */
+ ril_plugin_switch_user();
+
+ /* Register the driver */
+ ril_driver = sailfish_slot_driver_register(&ril_slot_driver);
+ return G_SOURCE_REMOVE;
+}
+static int ril_plugin_init(void)
+{
DBG("");
- GASSERT(!ril_plugin);
+ GASSERT(!ril_driver);
/*
* Log categories (accessible via D-Bus) are generated from
@@ -1866,101 +1614,19 @@
*/
gutil_log_func = gutil_log_syslog;
- ril_plugin_switch_user();
-
- ril_plugin = g_new0(struct ril_plugin_priv, 1);
- ril_plugin->slots = ril_plugin_load_config(RILMODEM_CONF_FILE, &ps);
- ril_plugin_init_slots(ril_plugin);
- ril_plugin->dbus = ril_plugin_dbus_new(&ril_plugin->pub);
- ril_plugin->data_manager = ril_data_manager_new(ps.dm_flags);
- ril_plugin->display = mce_display_new();
- ril_plugin->display_on = ril_plugin_display_on(ril_plugin->display);
-
- if (ril_plugin->slots) {
- /*
- * Since IMEI query is asynchronous, we need to hold IMEI
- * related requests until all queries complete.
- */
- ril_plugin_dbus_block_imei_requests(ril_plugin->dbus, TRUE);
- }
-
- /* Load settings */
- ril_plugin->storage = storage_open(NULL, RIL_STORE);
- enabled_slots = g_key_file_get_string(ril_plugin->storage,
- RIL_STORE_GROUP, RIL_STORE_ENABLED_SLOTS, NULL);
- if (enabled_slots) {
- char **strv = g_strsplit(enabled_slots, RIL_STORE_SLOTS_SEP, 0);
-
- DBG("Enabled slots: %s", enabled_slots);
- g_slist_foreach(ril_plugin->slots,
- ril_plugin_enable_disable_slot, strv);
- g_strfreev(strv);
- g_free(enabled_slots);
- } else {
- /* Let all slots be enabled by default */
- ril_plugin_foreach_slot(ril_plugin, ril_plugin_enable_slot);
- }
-
- ril_plugin->pub.default_voice_imsi =
- ril_plugin->default_voice_imsi =
- g_key_file_get_string(ril_plugin->storage, RIL_STORE_GROUP,
- RIL_STORE_DEFAULT_VOICE_SIM, NULL);
- ril_plugin->pub.default_data_imsi =
- ril_plugin->default_data_imsi =
- g_key_file_get_string(ril_plugin->storage, RIL_STORE_GROUP,
- RIL_STORE_DEFAULT_DATA_SIM, NULL);
-
- DBG("Default voice sim is %s", ril_plugin->default_voice_imsi ?
- ril_plugin->default_voice_imsi : "(auto)");
- DBG("Default data sim is %s", ril_plugin->default_data_imsi ?
- ril_plugin->default_data_imsi : "(auto)");
-
- ofono_modem_driver_register(&ril_modem_driver);
- ofono_sim_driver_register(&ril_sim_driver);
- ofono_sms_driver_register(&ril_sms_driver);
- ofono_netmon_driver_register(&ril_netmon_driver);
- ofono_netreg_driver_register(&ril_netreg_driver);
- ofono_devinfo_driver_register(&ril_devinfo_driver);
- ofono_voicecall_driver_register(&ril_voicecall_driver);
- ofono_call_barring_driver_register(&ril_call_barring_driver);
- ofono_call_forwarding_driver_register(&ril_call_forwarding_driver);
- ofono_call_settings_driver_register(&ril_call_settings_driver);
- ofono_call_volume_driver_register(&ril_call_volume_driver);
- ofono_radio_settings_driver_register(&ril_radio_settings_driver);
- ofono_gprs_driver_register(&ril_gprs_driver);
- ofono_gprs_context_driver_register(&ril_gprs_context_driver);
- ofono_phonebook_driver_register(&ril_phonebook_driver);
- ofono_ussd_driver_register(&ril_ussd_driver);
- ofono_cbs_driver_register(&ril_cbs_driver);
- ofono_stk_driver_register(&ril_stk_driver);
-
- /* This will create the modems (those that are enabled) */
- ril_plugin_update_slots(ril_plugin);
-
/*
- * Init RIL I/O for disabled slots as well so that we can receive
- * SIM insertion/removal notifications
+ * The real initialization happens later, to make sure that
+ * sailfish_manager plugin gets initialized first (and we don't
+ * depend on the order of initialization).
*/
- ril_plugin_foreach_slot(ril_plugin, ril_plugin_init_io);
-
- /* Set initial screen state and register for updates */
- ril_plugin_foreach_slot(ril_plugin, ril_plugin_send_screen_state);
- ril_plugin->display_event_id[DISPLAY_EVENT_VALID] =
- mce_display_add_valid_changed_handler(ril_plugin->display,
- ril_plugin_display_cb, ril_plugin);
- ril_plugin->display_event_id[DISPLAY_EVENT_STATE] =
- mce_display_add_state_changed_handler(ril_plugin->display,
- ril_plugin_display_cb, ril_plugin);
-
- /* This will set 'ready' flag if we have no modems at all */
- ril_plugin_update_ready(ril_plugin);
+ ril_driver_init_id = g_idle_add(ril_plugin_start, ril_driver);
return 0;
}
static void ril_plugin_exit(void)
{
DBG("");
- GASSERT(ril_plugin);
+ GASSERT(ril_driver);
ofono_modem_driver_unregister(&ril_modem_driver);
ofono_sim_driver_unregister(&ril_sim_driver);
@@ -1981,24 +1647,18 @@
ofono_cbs_driver_unregister(&ril_cbs_driver);
ofono_stk_driver_unregister(&ril_stk_driver);
- if (ril_plugin) {
- g_slist_free_full(ril_plugin->slots, ril_plugin_destroy_slot);
- ril_plugin_dbus_free(ril_plugin->dbus);
- ril_data_manager_unref(ril_plugin->data_manager);
- gutil_disconnect_handlers(ril_plugin->display,
- ril_plugin->display_event_id, DISPLAY_EVENT_COUNT);
- mce_display_unref(ril_plugin->display);
- g_key_file_free(ril_plugin->storage);
- g_free(ril_plugin->slots_info);
- g_free(ril_plugin->default_voice_imsi);
- g_free(ril_plugin->default_data_imsi);
- g_free(ril_plugin->mms_imsi);
- g_free(ril_plugin);
- ril_plugin = NULL;
+ if (ril_driver) {
+ sailfish_slot_driver_unregister(ril_driver);
+ ril_driver = NULL;
+ }
+
+ if (ril_driver_init_id) {
+ g_source_remove(ril_driver_init_id);
+ ril_driver_init_id = 0;
}
}
-OFONO_PLUGIN_DEFINE(ril, "RIL driver", VERSION,
+OFONO_PLUGIN_DEFINE(ril, "Sailfish OS RIL plugin", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT, ril_plugin_init, ril_plugin_exit)
/*
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_plugin.h
^
|
@@ -17,6 +17,7 @@
#define RIL_PLUGIN_H
#include "ril_types.h"
+#include "sailfish_manager.h"
#include <ofono/modem.h>
#include <ofono/call-barring.h>
@@ -43,30 +44,6 @@
#define RILMODEM_DRIVER "ril"
-typedef struct ril_slot_info const *ril_slot_info_ptr;
-
-struct ril_slot_info {
- const char *path;
- const char *imei;
- const char *imeisv;
- const char *ecclist_file;
- gboolean enabled;
- gboolean sim_present;
- const struct ril_slot_config *config;
- GHashTable *errors;
-};
-
-struct ril_plugin {
- const char *mms_imsi;
- const char *mms_path;
- const char *default_voice_imsi;
- const char *default_data_imsi;
- const char *default_voice_path;
- const char *default_data_path;
- const ril_slot_info_ptr *slots;
- gboolean ready;
-};
-
struct ril_modem {
GRilIoChannel *io;
const char *imei;
@@ -83,65 +60,27 @@
struct ril_slot_config config;
};
-#define RIL_PLUGIN_SIGNAL_VOICE_IMSI (0x01)
-#define RIL_PLUGIN_SIGNAL_DATA_IMSI (0x02)
-#define RIL_PLUGIN_SIGNAL_VOICE_PATH (0x04)
-#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x08)
-#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x10)
-#define RIL_PLUGIN_SIGNAL_MMS_IMSI (0x20)
-#define RIL_PLUGIN_SIGNAL_MMS_PATH (0x40)
-#define RIL_PLUGIN_SIGNAL_READY (0x80)
-
-typedef void (*ril_modem_cb_t)(struct ril_modem *modem, void *data);
-typedef void (*ril_modem_online_cb_t)(struct ril_modem *modem, gboolean online,
- void *data);
-
-void ril_plugin_set_enabled_slots(struct ril_plugin *plugin, char **slots);
-gboolean ril_plugin_set_mms_imsi(struct ril_plugin *plugin, const char *imsi);
-void ril_plugin_set_default_voice_imsi(struct ril_plugin *plugin,
- const char *imsi);
-void ril_plugin_set_default_data_imsi(struct ril_plugin *plugin,
- const char *imsi);
-
struct ril_oem_raw;
-struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *md,
+struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
const char *log_prefix);
void ril_oem_raw_free(struct ril_oem_raw *raw);
-struct ril_sim_info_dbus;
-struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
- struct ril_sim_info *info);
-void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus);
-
struct ril_cell_info_dbus;
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
struct ril_cell_info *info);
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus);
-struct ril_plugin_dbus;
-struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin);
-void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus);
-void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
- gboolean clock);
-void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
-void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
- gboolean present);
-void ril_plugin_dbus_signal_modem_error(struct ril_plugin_dbus *dbus,
- int index, const char *id, const char *message);
-
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
- const struct ril_slot_info *slot, struct ril_radio *radio,
- struct ril_network *network, struct ril_sim_card *card,
- struct ril_data *data, struct ril_sim_settings *settings,
+ const char *path, const char *imei, const char *imeisv,
+ const char *ecclist_file, const struct ril_slot_config *config,
+ struct ril_radio *radio, struct ril_network *network,
+ struct ril_sim_card *card, struct ril_data *data,
+ struct ril_sim_settings *settings,
struct ril_cell_info *cell_info);
void ril_modem_delete(struct ril_modem *modem);
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
-void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
- void *data);
-void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
- void *data);
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
@@ -149,7 +88,7 @@
#define ril_modem_io(modem) ((modem)->io)
int ril_sim_app_type(struct ofono_sim *sim);
-int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
+int ril_netreg_check_if_really_roaming(struct ofono_netreg *reg, gint status);
extern const struct ofono_call_barring_driver ril_call_barring_driver;
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_radio.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015-2016 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -50,14 +50,12 @@
enum ril_radio_signal {
SIGNAL_STATE_CHANGED,
- SIGNAL_ONLINE_CHANGED,
SIGNAL_COUNT
};
#define POWER_RETRY_SECS (1)
#define SIGNAL_STATE_CHANGED_NAME "ril-radio-state-changed"
-#define SIGNAL_ONLINE_CHANGED_NAME "ril-radio-online-changed"
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
@@ -77,8 +75,7 @@
{
struct ril_radio_priv *priv = self->priv;
- return self->online && !priv->power_cycle &&
- g_hash_table_size(priv->req_table) > 0;
+ return !priv->power_cycle && g_hash_table_size(priv->req_table) > 0;
}
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
@@ -99,13 +96,14 @@
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
{
- struct ril_radio *self = user_data;
+ struct ril_radio *self = RIL_RADIO(user_data);
struct ril_radio_priv *priv = self->priv;
DBG("%s", priv->log_prefix);
GASSERT(priv->retry_id);
priv->retry_id = 0;
- ril_radio_submit_power_request(self, ril_radio_power_should_be_on(self));
+ ril_radio_submit_power_request(self,
+ ril_radio_power_should_be_on(self));
return G_SOURCE_REMOVE;
}
@@ -126,7 +124,7 @@
struct ril_radio_priv *priv = self->priv;
if (!priv->pending_id) {
- const gboolean should_be_on = ril_radio_power_should_be_on(self);
+ gboolean should_be_on = ril_radio_power_should_be_on(self);
if (ril_radio_state_on(self->priv->last_known_state) ==
should_be_on) {
@@ -157,7 +155,7 @@
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
const void *data, guint len, void *user_data)
{
- struct ril_radio *self = user_data;
+ struct ril_radio *self = RIL_RADIO(user_data);
struct ril_radio_priv *priv = self->priv;
GASSERT(priv->pending_id);
@@ -177,11 +175,17 @@
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
{
+ /*
+ * RIL_REQUEST_RADIO_POWER
+ *
+ * "data" is int *
+ * ((int *)data)[0] is > 0 for "Radio On"
+ * ((int *)data)[0] is == 0 for "Radio Off"
+ *
+ * "response" is NULL
+ **/
+ GRilIoRequest *req = grilio_request_array_int32_new(1, on);
struct ril_radio_priv *priv = self->priv;
- GRilIoRequest *req = grilio_request_sized_new(8);
-
- grilio_request_append_int32(req, 1);
- grilio_request_append_int32(req, on); /* Radio ON=1, OFF=0 */
priv->next_state_valid = FALSE;
priv->next_state = on;
@@ -189,8 +193,10 @@
ril_radio_cancel_retry(self);
GASSERT(!priv->pending_id);
+ grilio_request_set_blocking(req, TRUE);
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
- RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb, NULL, self);
+ RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb,
+ NULL, self);
grilio_request_unref(req);
}
@@ -274,19 +280,6 @@
}
}
-void ril_radio_set_online(struct ril_radio *self, gboolean online)
-{
- if (G_LIKELY(self) && self->online != online) {
- gboolean on, was_on = ril_radio_power_should_be_on(self);
- self->online = online;
- on = ril_radio_power_should_be_on(self);
- if (was_on != on) {
- ril_radio_power_request(self, on, FALSE);
- }
- ril_radio_emit_signal(self, SIGNAL_ONLINE_CHANGED);
- }
-}
-
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
ril_radio_cb_t cb, void *arg)
{
@@ -294,13 +287,6 @@
SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
-gulong ril_radio_add_online_changed_handler(struct ril_radio *self,
- ril_radio_cb_t cb, void *arg)
-{
- return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
- SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
-}
-
void ril_radio_remove_handler(struct ril_radio *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
@@ -330,7 +316,7 @@
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
- struct ril_radio *self = user_data;
+ struct ril_radio *self = RIL_RADIO(user_data);
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
@@ -438,7 +424,6 @@
object_class->finalize = ril_radio_finalize;
g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
NEW_SIGNAL(klass, STATE);
- NEW_SIGNAL(klass, ONLINE);
}
/*
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_radio.h
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015-2016 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,7 +22,6 @@
GObject object;
struct ril_radio_priv *priv;
enum ril_radio_state state;
- gboolean online;
};
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
@@ -35,15 +34,15 @@
void ril_radio_power_off(struct ril_radio *radio, gpointer tag);
void ril_radio_power_cycle(struct ril_radio *radio);
void ril_radio_confirm_power_on(struct ril_radio *radio);
-void ril_radio_set_online(struct ril_radio *radio, gboolean online);
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
ril_radio_cb_t cb, void *arg);
-gulong ril_radio_add_online_changed_handler(struct ril_radio *radio,
- ril_radio_cb_t cb, void *arg);
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
void ril_radio_remove_handlers(struct ril_radio *radio, gulong *ids, int n);
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
+#define ril_radio_remove_all_handlers(r,ids) \
+ ril_radio_remove_handlers(r, ids, G_N_ELEMENTS(ids))
+
#endif /* RIL_RADIO_H */
/*
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_radio_caps.c
^
|
@@ -0,0 +1,1407 @@
+/*
+ * oFono - Open Source Telephony - RIL-based devices
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "ril_radio_caps.h"
+#include "ril_radio.h"
+#include "ril_network.h"
+#include "ril_sim_card.h"
+#include "ril_sim_settings.h"
+#include "ril_data.h"
+#include "ril_log.h"
+
+#include <grilio_queue.h>
+#include <grilio_channel.h>
+#include <grilio_parser.h>
+#include <grilio_request.h>
+
+#define SET_CAPS_TIMEOUT_MS (30*1000)
+#define GET_CAPS_TIMEOUT_MS (5*1000)
+#define DATA_OFF_TIMEOUT_MS (10*1000)
+#define DEACTIVATE_TIMEOUT_MS (10*1000)
+#define CHECK_LATER_TIMEOUT_SEC (5)
+
+#define GET_CAPS_RETRIES 60
+
+/*
+ * This code is doing something similar to what
+ * com.android.internal.telephony.ProxyController
+ * is doing.
+ */
+
+enum ril_radio_caps_sim_events {
+ SIM_EVENT_STATE_CHANGED,
+ SIM_EVENT_IO_ACTIVE_CHANGED,
+ SIM_EVENT_COUNT
+};
+
+enum ril_radio_caps_settings_events {
+ SETTINGS_EVENT_PREF_MODE,
+ SETTINGS_EVENT_IMSI,
+ SETTINGS_EVENT_COUNT
+};
+
+enum ril_radio_caps_io_events {
+ IO_EVENT_UNSOL_RADIO_CAPABILITY,
+ IO_EVENT_PENDING,
+ IO_EVENT_OWNER,
+ IO_EVENT_COUNT
+};
+
+struct ril_radio_caps {
+ gint ref_count;
+ guint slot;
+ char *log_prefix;
+ GRilIoQueue *q;
+ GRilIoChannel *io;
+ gulong settings_event_id[SETTINGS_EVENT_COUNT];
+ gulong simcard_event_id[SIM_EVENT_COUNT];
+ gulong io_event_id[IO_EVENT_COUNT];
+ gulong max_pref_mode_event_id;
+ gulong radio_event_id;
+ int tx_id;
+ struct ril_data *data;
+ struct ril_radio *radio;
+ struct ril_network *network;
+ struct ril_sim_card *simcard;
+ struct ril_radio_caps_manager *mgr;
+ struct ril_radio_capability cap;
+ struct ril_radio_capability old_cap;
+ struct ril_radio_capability new_cap;
+};
+
+typedef struct ril_radio_caps_manager {
+ GObject object;
+ GPtrArray *caps_list;
+ guint check_id;
+ int tx_pending;
+ int tx_id;
+ int tx_phase_index;
+ gboolean tx_failed;
+ struct ril_data_manager *data_manager;
+} RilRadioCapsManager;
+
+struct ril_radio_caps_check_data {
+ ril_radio_caps_check_cb_t cb;
+ void *data;
+};
+
+struct ril_radio_caps_request_tx_phase {
+ const char *name;
+ enum ril_radio_capability_phase phase;
+ enum ril_radio_capability_status status;
+ gboolean send_new_cap;
+};
+
+typedef void (*ril_radio_caps_cb_t)(struct ril_radio_caps_manager *self,
+ struct ril_radio_caps *caps);
+
+typedef GObjectClass RilRadioCapsManagerClass;
+G_DEFINE_TYPE(RilRadioCapsManager, ril_radio_caps_manager, G_TYPE_OBJECT)
+#define RADIO_CAPS_MANAGER_TYPE (ril_radio_caps_manager_get_type())
+#define RADIO_CAPS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ RADIO_CAPS_MANAGER_TYPE, RilRadioCapsManager))
+
+enum ril_radio_caps_manager_signal {
+ SIGNAL_ABORTED,
+ SIGNAL_COUNT
+};
+
+#define SIGNAL_ABORTED_NAME "ril-capsmgr-aborted"
+
+static guint ril_radio_caps_manager_signals[SIGNAL_COUNT] = { 0 };
+
+static const struct ril_radio_caps_request_tx_phase
+ ril_radio_caps_tx_phase[] = {
+ { "START", RC_PHASE_START, RC_STATUS_NONE, FALSE },
+ { "APPLY", RC_PHASE_APPLY, RC_STATUS_NONE, TRUE },
+ { "FINISH", RC_PHASE_FINISH, RC_STATUS_SUCCESS, FALSE }
+};
+
+static const struct ril_radio_caps_request_tx_phase
+ ril_radio_caps_fail_phase =
+ { "ABORT", RC_PHASE_FINISH, RC_STATUS_FAIL, FALSE };
+
+#define DBG_(caps, fmt, args...) DBG("%s" fmt, (caps)->log_prefix, ##args)
+
+static void ril_radio_caps_manager_next_phase
+ (struct ril_radio_caps_manager *self);
+static void ril_radio_caps_manager_schedule_check
+ (struct ril_radio_caps_manager *self);
+static void ril_radio_caps_manager_recheck_later
+ (struct ril_radio_caps_manager *self);
+
+static gboolean ril_radio_caps_parse(const char *log_prefix,
+ const void *data, guint len, struct ril_radio_capability *cap)
+{
+ GRilIoParser rilp;
+ guint32 version, tx, phase, rat;
+
+ memset(cap, 0, sizeof(*cap));
+ grilio_parser_init(&rilp, data, len);
+
+ if (grilio_parser_get_uint32(&rilp, &version) &&
+ grilio_parser_get_uint32(&rilp, &tx) &&
+ grilio_parser_get_uint32(&rilp, &phase) &&
+ grilio_parser_get_uint32(&rilp, &rat)) {
+ guint32 status;
+ char *uuid = grilio_parser_get_utf8(&rilp);
+
+ if (grilio_parser_get_uint32(&rilp, &status) &&
+ grilio_parser_at_end(&rilp)) {
+ DBG("%sversion=%d,tx=%d,phase=%d,rat=0x%x,"
+ "uuid=%s,status=%d", log_prefix, version,
+ tx, phase, rat, uuid, status);
+ cap->version = version;
+ cap->session = tx;
+ cap->phase = phase;
+ cap->rat = rat;
+ cap->status = status;
+ if (uuid) {
+ strncpy(cap->logicalModemUuid, uuid,
+ G_N_ELEMENTS(cap->logicalModemUuid));
+ g_free(uuid);
+ }
+ return TRUE;
+ }
+
+ g_free(uuid);
+ }
+
+ return FALSE;
+}
+
+static void ril_radio_caps_check_done(GRilIoChannel *io, int ril_status,
+ const void *data, guint len, void *user_data)
+{
+ struct ril_radio_caps_check_data *check = user_data;
+ const struct ril_radio_capability *result = NULL;
+ struct ril_radio_capability cap;
+
+ if (ril_status == RIL_E_SUCCESS &&
+ ril_radio_caps_parse("", data, len, &cap)) {
+ GASSERT(cap.rat);
+ if (cap.rat) {
+ result = ∩
+ }
+ }
+
+ check->cb(result, check->data);
+}
+
+static gboolean ril_radio_caps_check_retry(GRilIoRequest *request,
+ int ril_status, const void *resp, guint len, void *user_data)
+{
+ /*
+ * RIL_E_REQUEST_NOT_SUPPORTED is not listed among the valid
+ * RIL_REQUEST_GET_RADIO_CAPABILITY errors in ril.h but some
+ * RILs (e.g. Jolla C) return is anyway.
+ */
+ switch (ril_status) {
+ case RIL_E_SUCCESS:
+ case RIL_E_REQUEST_NOT_SUPPORTED:
+ case RIL_E_OPERATION_NOT_ALLOWED:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+guint ril_radio_caps_check(GRilIoChannel *io, ril_radio_caps_check_cb_t cb,
+ void *data)
+{
+ guint id;
+ GRilIoRequest *req = grilio_request_new();
+ struct ril_radio_caps_check_data *check =
+ g_new0(struct ril_radio_caps_check_data, 1);
+
+ check->cb = cb;
+ check->data = data;
+
+ /* Make is blocking because this is typically happening at startup
+ * when there are lots of things happening at the same time which
+ * makes some RILs unhappy. Slow things down a bit by not letting
+ * to submit any other requests while this one is pending. */
+ grilio_request_set_blocking(req, TRUE);
+ grilio_request_set_retry(req, GET_CAPS_TIMEOUT_MS, GET_CAPS_RETRIES);
+ grilio_request_set_retry_func(req, ril_radio_caps_check_retry);
+ id = grilio_channel_send_request_full(io, req,
+ RIL_REQUEST_GET_RADIO_CAPABILITY,
+ ril_radio_caps_check_done, g_free, check);
+ grilio_request_unref(req);
+ return id;
+}
+
+/*==========================================================================*
+ * ril_radio_caps
+ *==========================================================================*/
+
+static enum ofono_radio_access_mode ril_radio_caps_access_mode
+ (const struct ril_radio_caps *caps)
+{
+ const enum ril_radio_access_family raf = caps->cap.rat;
+
+ if (raf & (RAF_LTE | RAF_LTE_CA)) {
+ return OFONO_RADIO_ACCESS_MODE_LTE;
+ } else if (raf & RAF_UMTS) {
+ return OFONO_RADIO_ACCESS_MODE_UMTS;
+ } else if (raf & (RAF_EDGE | RAF_GPRS | RAF_GSM)) {
+ return OFONO_RADIO_ACCESS_MODE_GSM;
+ } else {
+ return OFONO_RADIO_ACCESS_MODE_ANY;
+ }
+}
+
+static enum ofono_radio_access_mode ril_radio_caps_pref_mode_limit
+ (const struct ril_radio_caps *caps)
+{
+ struct ril_network *network = caps->network;
+ struct ril_sim_settings *settings = network->settings;
+
+ if (network->max_pref_mode == settings->pref_mode) {
+ return network->max_pref_mode;
+ } else if (network->max_pref_mode == OFONO_RADIO_ACCESS_MODE_ANY) {
+ return settings->pref_mode;
+ } else {
+ return network->max_pref_mode;
+ }
+}
+
+static gboolean ril_radio_caps_ready(const struct ril_radio_caps *caps)
+{
+ /* We don't want to start messing with radio capabilities before
+ * the user has entered the pin. Some RIL don't like it so much
+ * thet they refuse to work after that. */
+ return caps->radio->state == RADIO_STATE_ON && caps->simcard->status &&
+ (caps->simcard->status->card_state != RIL_CARDSTATE_PRESENT ||
+ caps->network->settings->imsi);
+}
+
+static gboolean ril_radio_caps_ok(const struct ril_radio_caps *caps,
+ const enum ofono_radio_access_mode limit)
+{
+ /* Check if the slot is happy with its present state */
+ return caps->radio->state != RADIO_STATE_ON ||
+ !caps->simcard->status ||
+ caps->simcard->status->card_state != RIL_CARDSTATE_PRESENT ||
+ !caps->network->settings->imsi ||
+ limit == OFONO_RADIO_ACCESS_MODE_ANY ||
+ ril_radio_caps_access_mode(caps) <= limit;
+}
+
+static gboolean ril_radio_caps_wants_upgrade(const struct ril_radio_caps *caps)
+{
+ if (caps->radio->state == RADIO_STATE_ON &&
+ caps->simcard->status &&
+ caps->simcard->status->card_state == RIL_CARDSTATE_PRESENT &&
+ caps->network->settings->imsi) {
+ enum ofono_radio_access_mode limit =
+ ril_radio_caps_pref_mode_limit(caps);
+
+ if (!limit) limit = OFONO_RADIO_ACCESS_MODE_LTE;
+ return ril_radio_caps_access_mode(caps) < limit;
+ }
+ return FALSE;
+}
+
+static int ril_radio_caps_index(const struct ril_radio_caps * caps)
+{
+ guint i;
+ const GPtrArray *list = caps->mgr->caps_list;
+
+ for (i = 0; i < list->len; i++) {
+ if (list->pdata[i] == caps) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static void ril_radio_caps_radio_event(struct ril_radio *radio, void *arg)
+{
+ struct ril_radio_caps *self = arg;
+
+ DBG_(self, "");
+ ril_radio_caps_manager_schedule_check(self->mgr);
+}
+
+static void ril_radio_caps_simcard_event(struct ril_sim_card *sim,
+ void *arg)
+{
+ struct ril_radio_caps *self = arg;
+
+ DBG_(self, "");
+ ril_radio_caps_manager_schedule_check(self->mgr);
+}
+
+static void ril_radio_caps_settings_event(struct ril_sim_settings *settings,
+ void *arg)
+{
+ struct ril_radio_caps *self = arg;
+
+ DBG_(self, "");
+ ril_radio_caps_manager_schedule_check(self->mgr);
+}
+
+static void ril_radio_caps_network_event(struct ril_network *network,
+ void *arg)
+{
+ struct ril_radio_caps *self = arg;
+
+ DBG_(self, "");
+ ril_radio_caps_manager_schedule_check(self->mgr);
+}
+
+static void ril_radio_caps_changed_cb(GRilIoChannel *io, guint code,
+ const void *data, guint len, void *arg)
+{
+ struct ril_radio_caps *self = arg;
+
+ DBG_(self, "");
+ GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
+ if (ril_radio_caps_parse(self->log_prefix, data, len, &self->cap)) {
+ ril_radio_caps_manager_schedule_check(self->mgr);
+ }
+}
+
+static void ril_radio_caps_finish_init(struct ril_radio_caps *self)
+{
+ GASSERT(ril_radio_caps_access_mode(self));
+
+ /* Register for update notifications */
+ self->io_event_id[IO_EVENT_UNSOL_RADIO_CAPABILITY] =
+ grilio_channel_add_unsol_event_handler(self->io,
+ ril_radio_caps_changed_cb, RIL_UNSOL_RADIO_CAPABILITY,
+ self);
+
+ /* Schedule capability check */
+ ril_radio_caps_manager_schedule_check(self->mgr);
+}
+
+static void ril_radio_caps_initial_query_cb(GRilIoChannel *io, int ril_status,
+ const void *data, guint len, void *user_data)
+{
+ struct ril_radio_caps *self = user_data;
+
+ if (ril_status == RIL_E_SUCCESS) {
+ ril_radio_caps_parse(self->log_prefix, data, len, &self->cap);
+ }
+
+ if (self->cap.rat) {
+ ril_radio_caps_finish_init(self);
+ } else {
+ DBG_(self, "failed to query radio capabilities");
+ }
+}
+
+static gint ril_caps_compare_cb(gconstpointer a, gconstpointer b)
+{
+ const struct ril_radio_caps *c1 = *(void**)a;
+ const struct ril_radio_caps *c2 = *(void**)b;
+
+ return c1->slot < c2->slot ? (-1) : c1->slot > c2->slot ? 1 : 0;
+}
+
+static void ril_radio_caps_free(struct ril_radio_caps *self)
+{
+ struct ril_radio_caps_manager *mgr = self->mgr;
+ struct ril_sim_settings *settings = self->network->settings;
+
+ ril_network_remove_handler(self->network, self->max_pref_mode_event_id);
+ ril_radio_remove_handler(self->radio, self->radio_event_id);
+ ril_sim_settings_remove_handlers(settings, self->settings_event_id,
+ G_N_ELEMENTS(self->settings_event_id));
+ ril_sim_card_remove_handlers(self->simcard, self->simcard_event_id,
+ G_N_ELEMENTS(self->simcard_event_id));
+ grilio_channel_remove_handlers(self->io, self->io_event_id,
+ G_N_ELEMENTS(self->io_event_id));
+ g_ptr_array_remove(mgr->caps_list, self);
+ ril_radio_caps_manager_unref(mgr);
+ grilio_queue_cancel_all(self->q, FALSE);
+ grilio_queue_unref(self->q);
+ grilio_channel_unref(self->io);
+ ril_data_unref(self->data);
+ ril_radio_unref(self->radio);
+ ril_sim_card_unref(self->simcard);
+ ril_network_unref(self->network);
+ g_free(self->log_prefix);
+ g_slice_free(struct ril_radio_caps, self);
+}
+
+struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
+ const char *log_prefix, GRilIoChannel *io,
+ struct ril_data *data, struct ril_radio *radio,
+ struct ril_sim_card *sim, struct ril_network *net,
+ const struct ril_slot_config *config,
+ const struct ril_radio_capability *cap)
+{
+ GASSERT(mgr);
+ if (G_LIKELY(mgr)) {
+ struct ril_sim_settings *settings = net->settings;
+ struct ril_radio_caps *self =
+ g_slice_new0(struct ril_radio_caps);
+
+ self->ref_count = 1;
+ self->slot = config->slot;
+ self->log_prefix = (log_prefix && log_prefix[0]) ?
+ g_strconcat(log_prefix, " ", NULL) : g_strdup("");
+
+ self->q = grilio_queue_new(io);
+ self->io = grilio_channel_ref(io);
+ self->data = ril_data_ref(data);
+ self->mgr = ril_radio_caps_manager_ref(mgr);
+
+ self->radio = ril_radio_ref(radio);
+ self->radio_event_id = ril_radio_add_state_changed_handler(
+ radio, ril_radio_caps_radio_event, self);
+
+ self->simcard = ril_sim_card_ref(sim);
+ self->simcard_event_id[SIM_EVENT_STATE_CHANGED] =
+ ril_sim_card_add_state_changed_handler(sim,
+ ril_radio_caps_simcard_event, self);
+
+ self->network = ril_network_ref(net);
+ self->settings_event_id[SETTINGS_EVENT_PREF_MODE] =
+ ril_sim_settings_add_pref_mode_changed_handler(
+ settings, ril_radio_caps_settings_event, self);
+ self->settings_event_id[SETTINGS_EVENT_IMSI] =
+ ril_sim_settings_add_pref_mode_changed_handler(
+ settings, ril_radio_caps_settings_event, self);
+
+ self->max_pref_mode_event_id =
+ ril_network_add_max_pref_mode_changed_handler(net,
+ ril_radio_caps_network_event, self);
+
+ /* Order list elements according to slot numbers */
+ g_ptr_array_add(mgr->caps_list, self);
+ g_ptr_array_sort(mgr->caps_list, ril_caps_compare_cb);
+
+ if (cap) {
+ /* Current capabilities are provided by the caller */
+ self->cap = *cap;
+ ril_radio_caps_finish_init(self);
+ } else {
+ /* Need to query current capabilities */
+ GRilIoRequest *req = grilio_request_new();
+ grilio_request_set_retry(req, GET_CAPS_TIMEOUT_MS,
+ GET_CAPS_RETRIES);
+ grilio_queue_send_request_full(self->q, req,
+ RIL_REQUEST_GET_RADIO_CAPABILITY,
+ ril_radio_caps_initial_query_cb,
+ NULL, self);
+ grilio_request_unref(req);
+ }
+
+ return self;
+ }
+ return NULL;
+}
+
+struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *self)
+{
+ if (G_LIKELY(self)) {
+ GASSERT(self->ref_count > 0);
+ g_atomic_int_inc(&self->ref_count);
+ }
+ return self;
+}
+
+void ril_radio_caps_unref(struct ril_radio_caps *self)
+{
+ if (G_LIKELY(self)) {
+ GASSERT(self->ref_count > 0);
+ if (g_atomic_int_dec_and_test(&self->ref_count)) {
+ ril_radio_caps_free(self);
+ }
+ }
+}
+
+/*==========================================================================*
+ * ril_radio_caps_manager
+ *==========================================================================*/
+
+static void ril_radio_caps_manager_foreach(struct ril_radio_caps_manager *self,
+ ril_radio_caps_cb_t cb)
+{
+ guint i;
+ const GPtrArray *list = self->caps_list;
+
+ for (i = 0; i < list->len; i++) {
+ cb(self, (struct ril_radio_caps *)(list->pdata[i]));
+ }
+}
+
+static void ril_radio_caps_manager_foreach_tx
+ (struct ril_radio_caps_manager *self,
+ ril_radio_caps_cb_t cb)
+{
+ guint i;
+ const GPtrArray *list = self->caps_list;
+
+ for (i = 0; i < list->len; i++) {
+ struct ril_radio_caps *caps = list->pdata[i];
+
+ /* Ignore the modems not associated with this transaction */
+ if (caps->tx_id == self->tx_id) {
+ cb(self, caps);
+ }
+ }
+}
+
+/**
+ * Checks that all radio caps have been initialized (i.e. all the initial
+ * GET_RADIO_CAPABILITY requests have completed) and there's no transaction
+ * in progress.
+ */
+static gboolean ril_radio_caps_manager_ready
+ (struct ril_radio_caps_manager *self)
+{
+ if (self->caps_list && !self->tx_pending) {
+ const GPtrArray *list = self->caps_list;
+ guint i;
+
+ for (i = 0; i < list->len; i++) {
+ const struct ril_radio_caps *caps = list->pdata[i];
+
+ if (caps->radio->state == RADIO_STATE_ON &&
+ !caps->cap.rat) {
+ DBG_(caps, "not ready");
+ return FALSE;
+ }
+
+ DBG_(caps, "radio=%s,sim=%s,imsi=%s,raf=0x%x(%s),"
+ "uuid=%s,limit=%s", (caps->radio->state ==
+ RADIO_STATE_ON) ? "on" : "off",
+ caps->simcard->status ?
+ (caps->simcard->status->card_state ==
+ RIL_CARDSTATE_PRESENT) ? "yes" : "no" : "?",
+ caps->network->settings->imsi ?
+ caps->network->settings->imsi : "",
+ caps->cap.rat,
+ ofono_radio_access_mode_to_string
+ (ril_radio_caps_access_mode(caps)),
+ caps->cap.logicalModemUuid,
+ ofono_radio_access_mode_to_string
+ (ril_radio_caps_pref_mode_limit(caps)));
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int ril_radio_caps_manager_first_mismatch
+ (struct ril_radio_caps_manager *self)
+{
+ guint i;
+ const GPtrArray *list = self->caps_list;
+
+ for (i = 0; i < list->len; i++) {
+ const struct ril_radio_caps *caps = list->pdata[i];
+
+ if (!ril_radio_caps_ok(caps,
+ ril_radio_caps_pref_mode_limit(caps))) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static int ril_radio_caps_manager_find_mismatch
+ (struct ril_radio_caps_manager *self,
+ const guint *order, const gboolean *done)
+{
+ guint i;
+ const GPtrArray *list = self->caps_list;
+
+ for (i = 0; i < list->len; i++) {
+ if (!done[i] && !ril_radio_caps_ok(list->pdata[order[i]],
+ ril_radio_caps_pref_mode_limit(list->pdata[i]))) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static int ril_radio_caps_manager_find_match
+ (struct ril_radio_caps_manager *self,
+ guint from, const guint *order,
+ const gboolean *done)
+{
+ guint i;
+ const GPtrArray *list = self->caps_list;
+ const struct ril_radio_caps *src = list->pdata[order[from]];
+
+ for (i = 0; i < list->len; i++) {
+ if (!done[i] && ril_radio_caps_ok(src,
+ ril_radio_caps_pref_mode_limit(list->pdata[i]))) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * Updates the order of capabilities (i.e. which slots should get
+ * assigned which capabilities). Returns FALSE if nothing can be
+ * done due to impossible constraints. If everything is already
+ * fine, we shouldn't even get here - the caller makes sure of that.
+ */
+static gboolean ril_radio_caps_manager_update_caps
+ (struct ril_radio_caps_manager *self, int mismatch)
+{
+ guint i;
+ int from, to;
+ gboolean ok = TRUE;
+ const GPtrArray *list = self->caps_list;
+ guint *order = g_new(guint, list->len);
+ gboolean *done = g_new(gboolean, list->len);
+
+ for (i = 0; i < list->len; i++) {
+ const struct ril_radio_caps *caps = list->pdata[i];
+
+ /* Not touching powered off modems */
+ done[i] = !ril_radio_caps_ready(caps);
+ order[i] = i;
+ }
+
+ /* The first mismatch is already known */
+ to = ril_radio_caps_manager_find_match(self, mismatch, order, done);
+ if (to < 0) {
+ ok = FALSE;
+ } else {
+ DBG("%d <-> %d", mismatch, to);
+ order[mismatch] = to;
+ order[to] = mismatch;
+ done[to] = TRUE;
+ }
+
+ /* Handle other mismatched slots (if any) */
+ while (ok && (from = ril_radio_caps_manager_find_mismatch(self, order,
+ done)) >= 0) {
+ to = ril_radio_caps_manager_find_match(self, from, order,
+ done);
+ if (to < 0) {
+ ok = FALSE;
+ } else {
+ const guint tmp = order[from];
+ DBG("%d <-> %d", order[from], order[to]);
+ order[from] = order[to];
+ order[to] = tmp;
+ done[to] = TRUE;
+ }
+ }
+
+ if (ok) {
+ for (i = 0; i < list->len; i++) {
+ struct ril_radio_caps *caps = list->pdata[i];
+ caps->new_cap = caps->old_cap = caps->cap;
+ }
+
+ /* Update the rafs */
+ for (i = 0; i < list->len; i++) {
+ struct ril_radio_caps *src = list->pdata[i];
+ struct ril_radio_caps *dest = list->pdata[order[i]];
+ dest->new_cap = src->cap;
+ }
+ }
+
+ g_free(order);
+ g_free(done);
+ return ok;
+}
+
+static void ril_radio_caps_manager_issue_requests
+ (struct ril_radio_caps_manager *self,
+ const struct ril_radio_caps_request_tx_phase *phase,
+ GRilIoChannelResponseFunc handler)
+{
+ guint i;
+ const GPtrArray *list = self->caps_list;
+
+ DBG("%s transaction %d", phase->name, self->tx_id);
+ for (i = 0; i < list->len; i++) {
+ struct ril_radio_caps *caps = list->pdata[i];
+
+ /* Ignore the modems not associated with this transaction */
+ if (caps->tx_id == self->tx_id) {
+ GRilIoRequest *req = grilio_request_new();
+ const struct ril_radio_capability *cap =
+ phase->send_new_cap ? &caps->new_cap :
+ &caps->old_cap;
+
+ /* Encode and send the request */
+ grilio_request_append_int32(req,
+ RIL_RADIO_CAPABILITY_VERSION);
+ grilio_request_append_int32(req, self->tx_id);
+ grilio_request_append_int32(req, phase->phase);
+ grilio_request_append_int32(req, cap->rat);
+ grilio_request_append_utf8(req, cap->logicalModemUuid);
+ grilio_request_append_int32(req, phase->status);
+ grilio_request_set_timeout(req, SET_CAPS_TIMEOUT_MS);
+ grilio_queue_send_request_full(caps->q, req,
+ RIL_REQUEST_SET_RADIO_CAPABILITY,
+ handler, NULL, caps);
+ grilio_request_unref(req);
+
+ /* Count it */
+ self->tx_pending++;
+ }
+ }
+}
+
+static void ril_radio_caps_manager_next_transaction_cb
+ (struct ril_radio_caps_manager *self,
+ struct ril_radio_caps *caps)
+{
+ grilio_queue_cancel_all(caps->q, FALSE);
+ grilio_channel_remove_handlers(caps->io, caps->io_event_id +
+ IO_EVENT_PENDING, 1);
+ grilio_channel_remove_handlers(caps->io, caps->io_event_id +
+ IO_EVENT_OWNER, 1);
+ ril_sim_card_remove_handlers(caps->simcard, caps->simcard_event_id +
+ SIM_EVENT_IO_ACTIVE_CHANGED, 1);
+}
+
+static void ril_radio_caps_manager_next_transaction
+ (struct ril_radio_caps_manager *self)
+{
+ ril_radio_caps_manager_foreach(self,
+ ril_radio_caps_manager_next_transaction_cb);
+ self->tx_pending = 0;
+ self->tx_failed = FALSE;
+ self->tx_phase_index = -1;
+ self->tx_id++;
+ if (self->tx_id <= 0) self->tx_id = 1;
+}
+
+static void ril_radio_caps_manager_cancel_cb
+ (struct ril_radio_caps_manager *self,
+ struct ril_radio_caps *caps)
+{
+ GASSERT(!caps->io_event_id[IO_EVENT_OWNER]);
+ GASSERT(!caps->io_event_id[IO_EVENT_PENDING]);
+ grilio_queue_transaction_finish(caps->q);
+}
+
+static void ril_radio_caps_manager_finish_cb
+ (struct ril_radio_caps_manager *self,
+ struct ril_radio_caps *caps)
+{
+ ril_radio_caps_manager_cancel_cb(self, caps);
+ ril_network_assert_pref_mode(caps->network, FALSE);
+}
+
+static void ril_radio_caps_manager_transaction_done
+ (struct ril_radio_caps_manager *self)
+{
+ ril_radio_caps_manager_schedule_check(self);
+ ril_data_manager_assert_data_on(self->data_manager);
+ ril_radio_caps_manager_foreach(self, ril_radio_caps_manager_finish_cb);
+}
+
+static void ril_radio_caps_manager_abort_cb(GRilIoChannel *io,
+ int ril_status, const void *data, guint len, void *user_data)
+{
+ struct ril_radio_caps *caps = user_data;
+ struct ril_radio_caps_manager *self = caps->mgr;
+
+ GASSERT(self->tx_pending > 0);
+ if (!(--self->tx_pending)) {
+ DBG("transaction aborted");
+ ril_radio_caps_manager_transaction_done(self);
+ }
+}
+
+static void ril_radio_caps_manager_abort_transaction
+ (struct ril_radio_caps_manager *self)
+{
+ guint i;
+ const GPtrArray *list = self->caps_list;
+ const int prev_tx_id = self->tx_id;
+
+ /* Generate new transaction id */
+ DBG("aborting transaction %d", prev_tx_id);
+ ril_radio_caps_manager_next_transaction(self);
+
+ /* Re-associate the modems with the new transaction */
+ for (i = 0; i < list->len; i++) {
+ struct ril_radio_caps *caps = list->pdata[i];
+
+ if (caps->tx_id == prev_tx_id) {
+ caps->tx_id = self->tx_id;
+ }
+ }
+
+ /*
+ * Issue a FINISH with RC_STATUS_FAIL. That's what
+ * com.android.internal.telephony.ProxyController does
+ * when something goes wrong.
+ */
+ ril_radio_caps_manager_issue_requests(self, &ril_radio_caps_fail_phase,
+ ril_radio_caps_manager_abort_cb);
+
+ /* Notify the listeners */
+ g_signal_emit(self, ril_radio_caps_manager_signals[SIGNAL_ABORTED], 0);
+}
+
+static void ril_radio_caps_manager_next_phase_cb(GRilIoChannel *io,
+ int ril_status, const void *data, guint len, void *user_data)
+{
+ struct ril_radio_caps *caps = user_data;
+ struct ril_radio_caps_manager *self = caps->mgr;
+ gboolean ok = FALSE;
+
+ GASSERT(self->tx_pending > 0);
+ if (ril_status == RIL_E_SUCCESS) {
+ struct ril_radio_capability cap;
+ if (ril_radio_caps_parse(caps->log_prefix, data, len, &cap) &&
+ cap.status == RC_STATUS_SUCCESS) {
+ caps->cap = cap;
+ ok = TRUE;
+ }
+ }
+
+ if (!ok) {
+ if (!self->tx_failed) {
+ self->tx_failed = TRUE;
+ DBG("transaction %d failed", self->tx_id);
+ }
+ }
+
+ if (!(--self->tx_pending)) {
+ if (self->tx_failed) {
+ ril_radio_caps_manager_abort_transaction(self);
+ } else {
+ ril_radio_caps_manager_next_phase(self);
+ }
+ }
+}
+
+static void ril_radio_caps_manager_next_phase
+ (struct ril_radio_caps_manager *self)
+{
+ /* Note: -1 > 2 if 2 is unsigned (which turns -1 into 4294967295) */
+ const int max_index = G_N_ELEMENTS(ril_radio_caps_tx_phase) - 1;
+
+ GASSERT(!self->tx_pending);
+ if (self->tx_phase_index >= max_index) {
+ DBG("transaction %d is done", self->tx_id);
+ ril_radio_caps_manager_transaction_done(self);
+ } else {
+ const struct ril_radio_caps_request_tx_phase *phase =
+ ril_radio_caps_tx_phase +
+ (++self->tx_phase_index);
+
+ ril_radio_caps_manager_issue_requests(self, phase,
+ ril_radio_caps_manager_next_phase_cb);
+ }
+}
+
+static void ril_radio_caps_manager_data_off_done(GRilIoChannel *io,
+ int status, const void *req_data, guint len, void *user_data)
+{
+ struct ril_radio_caps_manager *self = RADIO_CAPS_MANAGER(user_data);
+
+ DBG("%d", self->tx_pending);
+ GASSERT(self->tx_pending > 0);
+ if (status != GRILIO_STATUS_OK) {
+ self->tx_failed = TRUE;
+ }
+ if (!(--self->tx_pending)) {
+ if (self->tx_failed) {
+ DBG("failed to start the transaction");
+ ril_data_manager_assert_data_on(self->data_manager);
+ ril_radio_caps_manager_recheck_later(self);
+ ril_radio_caps_manager_foreach(self,
+ ril_radio_caps_manager_cancel_cb);
+ } else {
+ DBG("starting transaction");
+ ril_radio_caps_manager_next_phase(self);
+ }
+ }
+}
+
+static void ril_radio_caps_manager_data_off
+ (struct ril_radio_caps_manager *self,
+ struct ril_radio_caps *caps)
+{
+ GRilIoRequest *req = ril_request_allow_data_new(FALSE);
+
+ self->tx_pending++;
+ DBG_(caps, "disallowing data");
+ grilio_request_set_timeout(req, DATA_OFF_TIMEOUT_MS);
+ grilio_queue_send_request_full(caps->q, req,
+ RIL_REQUEST_ALLOW_DATA,
+ ril_radio_caps_manager_data_off_done,
+ NULL, self);
+ grilio_request_unref(req);
+}
+
+static void ril_radio_caps_manager_deactivate_data_call_done(GRilIoChannel *io,
+ int status, const void *data, guint len, void *user_data)
+{
+ struct ril_radio_caps *caps = user_data;
+ struct ril_radio_caps_manager *self = caps->mgr;
+
+ GASSERT(self->tx_pending > 0);
+ if (status != GRILIO_STATUS_OK) {
+ self->tx_failed = TRUE;
+ /* Something seems to be slightly broken, try requesting the
+ * current state (later, after we release the transaction). */
+ ril_data_poll_call_state(caps->data);
+ }
+ if (!(--self->tx_pending)) {
+ if (self->tx_failed) {
+ DBG("failed to start the transaction");
+ ril_radio_caps_manager_recheck_later(self);
+ ril_radio_caps_manager_foreach(self,
+ ril_radio_caps_manager_cancel_cb);
+ } else {
+ ril_radio_caps_manager_foreach_tx(self,
+ ril_radio_caps_manager_data_off);
+ }
+ }
+}
+
+static void ril_radio_caps_deactivate_data_call(struct ril_radio_caps *caps,
+ int cid)
+{
+ GRilIoRequest *req = ril_request_deactivate_data_call_new(cid);
+
+ caps->mgr->tx_pending++;
+ DBG_(caps, "deactivating call %u", cid);
+ grilio_request_set_blocking(req, TRUE);
+ grilio_request_set_timeout(req, DEACTIVATE_TIMEOUT_MS);
+ grilio_queue_send_request_full(caps->q, req,
+ RIL_REQUEST_DEACTIVATE_DATA_CALL,
+ ril_radio_caps_manager_deactivate_data_call_done,
+ NULL, caps);
+ grilio_request_unref(req);
+}
+
+static void ril_radio_caps_deactivate_data_call_cb(gpointer list_data,
+ gpointer user_data)
+{
+ struct ril_data_call *call = list_data;
+
+ if (call->status == PDP_FAIL_NONE) {
+ ril_radio_caps_deactivate_data_call(user_data, call->cid);
+ }
+}
+
+static void ril_radio_caps_manager_deactivate_all_cb
+ (struct ril_radio_caps_manager *self,
+ struct ril_radio_caps *caps)
+{
+ if (caps->data->data_calls) {
+ g_slist_foreach(caps->data->data_calls->calls,
+ ril_radio_caps_deactivate_data_call_cb, caps);
+ }
+}
+
+static void ril_radio_caps_manager_deactivate_all
+ (struct ril_radio_caps_manager *self)
+{
+ ril_radio_caps_manager_foreach_tx(self,
+ ril_radio_caps_manager_deactivate_all_cb);
+ if (!self->tx_pending) {
+ /* No data calls, submit ALLOW_DATA requests right away */
+ ril_radio_caps_manager_foreach_tx(self,
+ ril_radio_caps_manager_data_off);
+ GASSERT(self->tx_pending);
+ }
+}
+
+static void ril_radio_caps_tx_wait_cb(GRilIoChannel *io, void *user_data)
+{
+ struct ril_radio_caps *caps = user_data;
+ struct ril_radio_caps_manager *self = caps->mgr;
+ const GPtrArray *list = self->caps_list;
+ gboolean can_start = TRUE;
+ guint i;
+
+ if (grilio_queue_transaction_state(caps->q) ==
+ GRILIO_TRANSACTION_STARTED) {
+ /* We no longer need owner notifications from this channel */
+ grilio_channel_remove_handlers(caps->io,
+ caps->io_event_id + IO_EVENT_OWNER, 1);
+ if (!grilio_channel_has_pending_requests(caps->io)) {
+ /* And pending notifications too */
+ grilio_channel_remove_handlers(caps->io,
+ caps->io_event_id + IO_EVENT_PENDING, 1);
+ }
+ }
+
+ /* Check if all channels are ours */
+ for (i = 0; i < list->len && can_start; i++) {
+ struct ril_radio_caps *caps = list->pdata[i];
+
+ if (caps->tx_id == self->tx_id &&
+ (grilio_channel_has_pending_requests(caps->io) ||
+ grilio_queue_transaction_state(caps->q) !=
+ GRILIO_TRANSACTION_STARTED)) {
+ /* Still waiting for this one */
+ DBG_(caps, "still waiting");
+ can_start = FALSE;
+ }
+ }
+
+ if (can_start) {
+ /* All modems are ready */
+ ril_radio_caps_manager_deactivate_all(self);
+ }
+}
+
+static void ril_radio_caps_manager_lock_io_for_transaction
+ (struct ril_radio_caps_manager *self)
+{
+ const GPtrArray *list = self->caps_list;
+ gboolean can_start = TRUE;
+ guint i;
+
+ /* We want to actually start the transaction when all the
+ * involved modems stop doing other things. Otherwise some
+ * RILs get confused and break. We have already checked that
+ * SIM I/O has stopped. The next synchronization point is the
+ * completion of all DEACTIVATE_DATA_CALL and ALLOW_DATA requests.
+ * Then we can start the capability switch transaction. */
+ for (i = 0; i < list->len; i++) {
+ struct ril_radio_caps *caps = list->pdata[i];
+ GRILIO_TRANSACTION_STATE state;
+
+ /* Restart the queue transation to make sure that
+ * we get to the end of the owner queue (to avoid
+ * deadlocks since we are going to wait for all
+ * queues to become the owners before actually
+ * starting the transaction) */
+ grilio_queue_transaction_finish(caps->q);
+ state = grilio_queue_transaction_start(caps->q);
+
+ /* Check if we need to wait for all transaction to
+ * complete on this I/O channel before we can actually
+ * start the transaction */
+ if (state == GRILIO_TRANSACTION_QUEUED) {
+ GASSERT(!caps->io_event_id[IO_EVENT_OWNER]);
+ caps->io_event_id[IO_EVENT_OWNER] =
+ grilio_channel_add_owner_changed_handler(
+ caps->io, ril_radio_caps_tx_wait_cb,
+ caps);
+ can_start = FALSE;
+ }
+
+ if (state == GRILIO_TRANSACTION_QUEUED ||
+ grilio_channel_has_pending_requests(caps->io)) {
+ GASSERT(!caps->io_event_id[IO_EVENT_PENDING]);
+ caps->io_event_id[IO_EVENT_PENDING] =
+ grilio_channel_add_pending_changed_handler(
+ caps->io, ril_radio_caps_tx_wait_cb,
+ caps);
+ can_start = FALSE;
+ }
+ }
+
+ if (can_start) {
+ /* All modems are ready */
+ ril_radio_caps_manager_deactivate_all(self);
+ }
+}
+
+static void ril_radio_caps_manager_stop_sim_io_watch
+ (struct ril_radio_caps_manager *self,
+ struct ril_radio_caps *caps)
+{
+ /* ril_sim_card_remove_handlers zeros the id */
+ ril_sim_card_remove_handlers(caps->simcard, caps->simcard_event_id +
+ SIM_EVENT_IO_ACTIVE_CHANGED, 1);
+}
+
+static void ril_radio_caps_tx_wait_sim_io_cb(struct ril_sim_card *simcard,
+ void *data)
+{
+ struct ril_radio_caps *caps = data;
+ struct ril_radio_caps_manager *self = caps->mgr;
+ const GPtrArray *list = self->caps_list;
+ guint i;
+
+ for (i = 0; i < list->len; i++) {
+ const struct ril_radio_caps *caps = list->pdata[i];
+
+ if (caps->simcard->sim_io_active) {
+ DBG_(caps, "still waiting for SIM I/O to calm down");
+ return;
+ }
+ }
+
+ /* We no longer need to be notified about SIM I/O activity */
+ DBG("SIM I/O has calmed down");
+ ril_radio_caps_manager_foreach(self,
+ ril_radio_caps_manager_stop_sim_io_watch);
+
+ /* Now this looks like a good moment to start the transaction */
+ ril_radio_caps_manager_lock_io_for_transaction(self);
+}
+
+static void ril_radio_caps_manager_start_sim_io_watch
+ (struct ril_radio_caps_manager *self,
+ struct ril_radio_caps *caps)
+{
+ caps->simcard_event_id[SIM_EVENT_IO_ACTIVE_CHANGED] =
+ ril_sim_card_add_sim_io_active_changed_handler(caps->simcard,
+ ril_radio_caps_tx_wait_sim_io_cb, caps);
+}
+
+static void ril_radio_caps_manager_start_transaction
+ (struct ril_radio_caps_manager *self)
+{
+ const GPtrArray *list = self->caps_list;
+ gboolean sim_io_active = FALSE;
+ guint i, count = 0;
+
+ /* Start the new request transaction */
+ ril_radio_caps_manager_next_transaction(self);
+ DBG("transaction %d", self->tx_id);
+
+ for (i = 0; i < list->len; i++) {
+ struct ril_radio_caps *caps = list->pdata[i];
+
+ if (memcmp(&caps->new_cap, &caps->old_cap, sizeof(caps->cap))) {
+ /* Mark it as taking part in this transaction */
+ caps->tx_id = self->tx_id;
+ count++;
+ if (caps->simcard->sim_io_active) {
+ sim_io_active = TRUE;
+ }
+ }
+ }
+
+ GASSERT(count);
+ if (!count) {
+ /* This is not supposed to happen */
+ DBG("nothing to do!");
+ } else if (sim_io_active) {
+ DBG("waiting for SIM I/O to calm down");
+ ril_radio_caps_manager_foreach_tx(self,
+ ril_radio_caps_manager_start_sim_io_watch);
+ } else {
+ /* Make sure we don't get notified about SIM I/O activity */
+ ril_radio_caps_manager_foreach(self,
+ ril_radio_caps_manager_stop_sim_io_watch);
+
+ /* And continue with locking RIL I/O for the transaction */
+ ril_radio_caps_manager_lock_io_for_transaction(self);
+ }
+
+}
+
+static GSList *ril_radio_caps_manager_upgradable_slots
+ (struct ril_radio_caps_manager *self)
+{
+ GSList *found = NULL;
+ const GPtrArray *list = self->caps_list;
+ guint i;
+
+ for (i = 0; i < list->len; i++) {
+ struct ril_radio_caps *caps = list->pdata[i];
+
+ if (ril_radio_caps_wants_upgrade(caps)) {
+ found = g_slist_append(found, caps);
+ }
+ }
+
+ return found;
+}
+
+static GSList *ril_radio_caps_manager_empty_slots
+ (struct ril_radio_caps_manager *self)
+{
+ GSList *found = NULL;
+ const GPtrArray *list = self->caps_list;
+ guint i;
+
+ for (i = 0; i < list->len; i++) {
+ struct ril_radio_caps *caps = list->pdata[i];
+
+ if (ril_radio_caps_ready(caps) &&
+ caps->simcard->status->card_state !=
+ RIL_CARDSTATE_PRESENT) {
+ found = g_slist_append(found, caps);
+ }
+ }
+
+ return found;
+}
+
+/**
+ * There could be no capability mismatch but LTE could be enabled for
+ * the slot that has no SIM card in it. That's a waste, fix it.
+ */
+static gboolean ril_radio_caps_manager_upgrade_caps
+ (struct ril_radio_caps_manager *self)
+{
+ gboolean upgrading = FALSE;
+ GSList *upgradable = ril_radio_caps_manager_upgradable_slots(self);
+
+ if (upgradable) {
+ GSList *empty = ril_radio_caps_manager_empty_slots(self);
+
+ if (empty) {
+ struct ril_radio_caps *dest = upgradable->data;
+ struct ril_radio_caps *src = empty->data;
+
+ if (ril_radio_caps_access_mode(src) >
+ ril_radio_caps_access_mode(dest)) {
+
+ DBG("%d <-> %d", ril_radio_caps_index(src),
+ ril_radio_caps_index(dest));
+ src->old_cap = src->cap;
+ src->new_cap = dest->cap;
+ dest->old_cap = dest->cap;
+ dest->new_cap = src->cap;
+ ril_radio_caps_manager_start_transaction(self);
+ upgrading = TRUE;
+ }
+ g_slist_free(empty);
+ }
+ g_slist_free(upgradable);
+ }
+
+ return upgrading;
+}
+
+static void ril_radio_caps_manager_check(struct ril_radio_caps_manager *self)
+{
+ DBG("");
+ if (ril_radio_caps_manager_ready(self)) {
+ const int first = ril_radio_caps_manager_first_mismatch(self);
+
+ if (first >= 0) {
+ if (ril_radio_caps_manager_update_caps(self, first)) {
+ ril_radio_caps_manager_start_transaction(self);
+ }
+ } else if (!ril_radio_caps_manager_upgrade_caps(self)) {
+ DBG("nothing to do");
+ }
+ }
+}
+
+static gboolean ril_radio_caps_manager_check_cb(gpointer data)
+{
+ struct ril_radio_caps_manager *self = RADIO_CAPS_MANAGER(data);
+
+ GASSERT(self->check_id);
+ self->check_id = 0;
+ ril_radio_caps_manager_check(self);
+ return G_SOURCE_REMOVE;
+}
+
+static void ril_radio_caps_manager_recheck_later
+ (struct ril_radio_caps_manager *self)
+{
+ if (!self->tx_pending) {
+ if (self->check_id) {
+ g_source_remove(self->check_id);
+ self->check_id = 0;
+ }
+ self->check_id = g_timeout_add_seconds(CHECK_LATER_TIMEOUT_SEC,
+ ril_radio_caps_manager_check_cb, self);
+ }
+}
+
+static void ril_radio_caps_manager_schedule_check
+ (struct ril_radio_caps_manager *self)
+{
+ if (!self->check_id && !self->tx_pending) {
+ self->check_id = g_idle_add(ril_radio_caps_manager_check_cb,
+ self);
+ }
+}
+
+gulong ril_radio_caps_manager_add_aborted_handler
+ (struct ril_radio_caps_manager *self,
+ ril_radio_caps_manager_cb_t cb, void *arg)
+{
+ return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
+ SIGNAL_ABORTED_NAME, G_CALLBACK(cb), arg) : 0;
+}
+
+void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *self,
+ gulong id)
+{
+ if (G_LIKELY(self) && G_LIKELY(id)) {
+ g_signal_handler_disconnect(self, id);
+ }
+}
+
+RilRadioCapsManager *ril_radio_caps_manager_ref(RilRadioCapsManager *self)
+{
+ if (G_LIKELY(self)) {
+ g_object_ref(RADIO_CAPS_MANAGER(self));
+ }
+ return self;
+}
+
+void ril_radio_caps_manager_unref(RilRadioCapsManager *self)
+{
+ if (G_LIKELY(self)) {
+ g_object_ref(RADIO_CAPS_MANAGER(self));
+ }
+}
+
+RilRadioCapsManager *ril_radio_caps_manager_new(struct ril_data_manager *dm)
+{
+ RilRadioCapsManager *self = g_object_new(RADIO_CAPS_MANAGER_TYPE, 0);
+
+ self->data_manager = ril_data_manager_ref(dm);
+ return self;
+}
+
+static void ril_radio_caps_manager_init(RilRadioCapsManager *self)
+{
+ self->caps_list = g_ptr_array_new();
+ self->tx_phase_index = -1;
+}
+
+static void ril_radio_caps_manager_finalize(GObject *object)
+{
+ RilRadioCapsManager *self = RADIO_CAPS_MANAGER(object);
+
+ GASSERT(!self->caps_list->len);
+ g_ptr_array_free(self->caps_list, TRUE);
+ if (self->check_id) {
+ g_source_remove(self->check_id);
+ }
+ ril_data_manager_unref(self->data_manager);
+ G_OBJECT_CLASS(ril_radio_caps_manager_parent_class)->finalize(object);
+}
+
+static void ril_radio_caps_manager_class_init(RilRadioCapsManagerClass *klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = ril_radio_caps_manager_finalize;
+ ril_radio_caps_manager_signals[SIGNAL_ABORTED] =
+ g_signal_new(SIGNAL_ABORTED_NAME,
+ G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_radio_caps.h
^
|
@@ -0,0 +1,66 @@
+/*
+ * oFono - Open Source Telephony - RIL-based devices
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RIL_RADIO_CAPS_H
+#define RIL_RADIO_CAPS_H
+
+#include "ril_types.h"
+
+struct ril_data_manager;
+struct ril_radio_caps;
+struct ril_radio_caps_manager;
+struct ril_radio_capability;
+
+typedef void (*ril_radio_caps_manager_cb_t)(struct ril_radio_caps_manager *mgr,
+ void *user_data);
+/* ril_radio_capability pointer is NULL if functionality is unsupported */
+typedef void (*ril_radio_caps_check_cb_t)
+ (const struct ril_radio_capability *cap, void *user_data);
+
+/* The check can be cancelled with grilio_channel_cancel_request */
+guint ril_radio_caps_check(GRilIoChannel *io, ril_radio_caps_check_cb_t cb,
+ void *user_data);
+
+/* There should be a single ril_radio_caps_manager shared by all all modems */
+struct ril_radio_caps_manager *ril_radio_caps_manager_new
+ (struct ril_data_manager *dm);
+struct ril_radio_caps_manager *ril_radio_caps_manager_ref
+ (struct ril_radio_caps_manager *mgr);
+void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr);
+gulong ril_radio_caps_manager_add_aborted_handler
+ (struct ril_radio_caps_manager *mgr,
+ ril_radio_caps_manager_cb_t cb, void *arg);
+void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *mgr,
+ gulong id);
+
+/* And one ril_radio_caps object per modem */
+struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
+ const char *log_prefix, GRilIoChannel *io,
+ struct ril_data *data, struct ril_radio *radio,
+ struct ril_sim_card *sim, struct ril_network *net,
+ const struct ril_slot_config *config,
+ const struct ril_radio_capability *cap);
+struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps);
+void ril_radio_caps_unref(struct ril_radio_caps *caps);
+
+#endif /* RIL_RADIO_CAPS_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_radio_settings.c
^
|
@@ -17,7 +17,6 @@
#include "ril_sim_settings.h"
#include "ril_util.h"
#include "ril_log.h"
-#include "ril_constants.h"
struct ril_radio_settings {
struct ofono_radio_settings *rs;
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_sim.c
^
|
@@ -40,13 +40,6 @@
/* FID/path of SIM/USIM root directory */
#define ROOTMF "3F00"
-/* RIL_Request* parameter counts */
-#define GET_IMSI_NUM_PARAMS 1
-#define ENTER_SIM_PIN_PARAMS 2
-#define SET_FACILITY_LOCK_PARAMS 5
-#define ENTER_SIM_PUK_PARAMS 3
-#define CHANGE_SIM_PIN_PARAMS 3
-
/* P2 coding (modes) for READ RECORD and UPDATE RECORD (see TS 102.221) */
#define MODE_SELECTED (0x00) /* Currently selected EF */
#define MODE_CURRENT (0x04) /* P1='00' denotes the current record */
@@ -113,6 +106,7 @@
gpointer ptr;
} cb;
gpointer data;
+ guint req_id;
};
struct ril_sim_pin_cbd {
@@ -429,6 +423,7 @@
struct ofono_error error;
DBG_(sd, "");
+ ril_sim_card_sim_io_finished(sd->card, cbd->req_id);
ril_error_init_failure(&error);
res = ril_sim_parse_io_response(data, len);
@@ -489,8 +484,10 @@
grilio_request_append_utf8(req, NULL); /* pin2; only for writes */
grilio_request_append_utf8(req, ril_sim_app_id(sd));
- grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_SIM_IO,
- cb, ril_sim_cbd_free, cbd);
+ grilio_request_set_blocking(req, TRUE);
+ cbd->req_id = grilio_queue_send_request_full(sd->q, req,
+ RIL_REQUEST_SIM_IO, cb, ril_sim_cbd_free, cbd);
+ ril_sim_card_sim_io_started(sd->card, cbd->req_id);
grilio_request_unref(req);
}
@@ -512,6 +509,8 @@
struct ofono_error err;
DBG_(cbd->sd, "");
+ ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
+
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);
@@ -565,6 +564,8 @@
struct ofono_error err;
DBG_(cbd->sd, "");
+ ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
+
res = ril_sim_parse_io_response(data, len);
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
cb(ril_error_ok(&err), cbd->data);
@@ -625,6 +626,8 @@
ofono_sim_imsi_cb_t cb = cbd->cb.imsi;
struct ofono_error error;
+ ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
+
if (status == RIL_E_SUCCESS) {
gchar *imsi;
GRilIoParser rilp;
@@ -649,11 +652,11 @@
void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
- GRilIoRequest *req = grilio_request_sized_new(60);
+ const char *app_id = ril_sim_app_id(sd);
+ struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
+ GRilIoRequest *req = grilio_request_array_utf8_new(1, app_id);
- DBG_(sd, "%s", ril_sim_app_id(sd));
- grilio_request_append_int32(req, GET_IMSI_NUM_PARAMS);
- grilio_request_append_utf8(req, ril_sim_app_id(sd));
+ DBG_(sd, "%s", app_id);
/*
* If we fail the .read_imsi call, ofono gets into "Unable to
@@ -661,9 +664,11 @@
* on failure.
*/
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
- grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_GET_IMSI,
- ril_sim_get_imsi_cb, ril_sim_cbd_free,
- ril_sim_cbd_new(sd, cb, data));
+ grilio_request_set_blocking(req, TRUE);
+ cbd->req_id = grilio_queue_send_request_full(sd->q, req,
+ RIL_REQUEST_GET_IMSI, ril_sim_get_imsi_cb,
+ ril_sim_cbd_free, cbd);
+ ril_sim_card_sim_io_started(sd->card, cbd->req_id);
grilio_request_unref(req);
}
@@ -861,10 +866,10 @@
{
const char *app_id = ril_sim_app_id(sd);
if (app_id) {
- GRilIoRequest *req = grilio_request_new();
- grilio_request_append_int32(req, ENTER_SIM_PIN_PARAMS);
- grilio_request_append_utf8(req, pin);
- grilio_request_append_utf8(req, app_id);
+ GRilIoRequest *req = grilio_request_array_utf8_new(2,
+ pin, app_id);
+
+ grilio_request_set_blocking(req, TRUE);
return req;
}
return NULL;
@@ -875,11 +880,9 @@
{
const char *app_id = ril_sim_app_id(sd);
if (app_id) {
- GRilIoRequest *req = grilio_request_new();
- grilio_request_append_int32(req, ENTER_SIM_PUK_PARAMS);
- grilio_request_append_utf8(req, puk);
- grilio_request_append_utf8(req, pin);
- grilio_request_append_utf8(req, app_id);
+ GRilIoRequest *req = grilio_request_array_utf8_new(3,
+ puk, pin, app_id);
+ grilio_request_set_blocking(req, TRUE);
return req;
}
return NULL;
@@ -1256,26 +1259,23 @@
const char *passwd, ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
- struct ofono_error error;
+ const char *app_id = ril_sim_app_id(sd);
const char *type_str = ril_sim_facility_code(passwd_type);
+ struct ofono_error error;
guint id = 0;
- DBG_(sd, "%d,%s,%d,%s,0,aid=%s", passwd_type, type_str, enable, passwd,
- ril_sim_app_id(sd));
+ DBG_(sd, "%d,%s,%d,%s,0,aid=%s", passwd_type, type_str,
+ enable, passwd, app_id);
if (passwd_type == OFONO_SIM_PASSWORD_PHNET_PIN) {
id = ril_perso_change_state(sim, passwd_type, enable, passwd,
cb, data);
} else if (type_str) {
- GRilIoRequest *req = grilio_request_new();
- grilio_request_append_int32(req, SET_FACILITY_LOCK_PARAMS);
- grilio_request_append_utf8(req, type_str);
- grilio_request_append_utf8(req, enable ?
- RIL_FACILITY_LOCK : RIL_FACILITY_UNLOCK);
- grilio_request_append_utf8(req, passwd);
- grilio_request_append_utf8(req, "0"); /* class */
- grilio_request_append_utf8(req, ril_sim_app_id(sd));
+ GRilIoRequest *req = grilio_request_array_utf8_new(5, type_str,
+ enable ? RIL_FACILITY_LOCK : RIL_FACILITY_UNLOCK,
+ passwd, "0" /* class */, app_id);
+ grilio_request_set_blocking(req, TRUE);
id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SET_FACILITY_LOCK,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
@@ -1317,15 +1317,12 @@
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
- GRilIoRequest *req = grilio_request_sized_new(60);
-
- grilio_request_append_int32(req, CHANGE_SIM_PIN_PARAMS);
- grilio_request_append_utf8(req, old_passwd);
- grilio_request_append_utf8(req, new_passwd);
- grilio_request_append_utf8(req, ril_sim_app_id(sd));
+ const char *app_id = ril_sim_app_id(sd);
+ GRilIoRequest *req = grilio_request_array_utf8_new(3,
+ old_passwd, new_passwd, app_id);
- DBG_(sd, "old=%s,new=%s,aid=%s", old_passwd, new_passwd,
- ril_sim_app_id(sd));
+ DBG_(sd, "old=%s,new=%s,aid=%s", old_passwd, new_passwd, app_id);
+ grilio_request_set_blocking(req, TRUE);
grilio_queue_send_request_full(sd->q, req,
(passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2) ?
RIL_REQUEST_CHANGE_SIM_PIN2 : RIL_REQUEST_CHANGE_SIM_PIN,
@@ -1341,6 +1338,8 @@
struct ril_sim_cbd *cbd = user_data;
ofono_query_facility_lock_cb_t cb = cbd->cb.query_facility_lock;
+ ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
+
if (status == RIL_E_SUCCESS) {
int locked = 0;
GRilIoParser rilp;
@@ -1362,18 +1361,16 @@
ofono_query_facility_lock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
- GRilIoRequest *req = grilio_request_new();
const char *type_str = ril_sim_facility_code(type);
+ struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
+ GRilIoRequest *req = grilio_request_array_utf8_new(4,
+ type_str, "", "0" /* class */, ril_sim_app_id(sd));
DBG_(sd, "%s", type_str);
- grilio_request_append_int32(req, 4);
- grilio_request_append_utf8(req, type_str);
- grilio_request_append_utf8(req, "");
- grilio_request_append_utf8(req, "0"); /* class */
- grilio_request_append_utf8(req, ril_sim_app_id(sd));
- grilio_queue_send_request_full(sd->q, req,
+ cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_QUERY_FACILITY_LOCK, ril_sim_query_facility_lock_cb,
- ril_sim_cbd_free, ril_sim_cbd_new(sd, cb, data));
+ ril_sim_cbd_free, cbd);
+ ril_sim_card_sim_io_started(sd->card, cbd->req_id);
grilio_request_unref(req);
}
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_sim_card.c
^
|
@@ -24,6 +24,15 @@
#include <gutil_misc.h>
+#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
+
+/* SIM I/O idle timeout is measured in the number of idle loops.
+ * When active SIM I/O is going on, the idle loop count very rarely
+ * exceeds 1 between the requests, so 10 is more than enough. Idle
+ * loop is actually more accurate criteria than a timeout because
+ * it doesn't depend that much on the system load. */
+#define SIM_IO_IDLE_LOOPS (10)
+
typedef GObjectClass RilSimCardClass;
typedef struct ril_sim_card RilSimCard;
@@ -38,7 +47,11 @@
GRilIoQueue *q;
int flags;
guint status_req_id;
+ guint sub_req_id;
gulong event_id[EVENT_COUNT];
+ guint sim_io_idle_id;
+ guint sim_io_idle_count;
+ GHashTable* sim_io_pending;
};
enum ril_sim_card_signal {
@@ -46,13 +59,15 @@
SIGNAL_STATUS_CHANGED,
SIGNAL_STATE_CHANGED,
SIGNAL_APP_CHANGED,
+ SIGNAL_SIM_IO_ACTIVE_CHANGED,
SIGNAL_COUNT
};
-#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
-#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
-#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
-#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
+#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
+#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
+#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
+#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
+#define SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME "ril-simcard-sim-io-active-changed"
static guint ril_sim_card_signals[SIGNAL_COUNT] = { 0 };
@@ -61,6 +76,13 @@
#define RIL_SIMCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_SIMCARD_TYPE, RilSimCard))
+#define NEW_SIGNAL(klass,name) NEW_SIGNAL_(klass,name##_CHANGED)
+#define NEW_SIGNAL_(klass,name) \
+ ril_sim_card_signals[SIGNAL_##name] = \
+ g_signal_new(SIGNAL_##name##_NAME, \
+ G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
+ 0, NULL, NULL, NULL, G_TYPE_NONE, 0)
+
#define RIL_SIMCARD_STATE_CHANGED (0x01)
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
@@ -135,22 +157,65 @@
}
}
-static void ril_sim_card_subscribe(struct ril_sim_card *self,
- int app_index, int sub_status)
+static void ril_sim_card_subscription_done(struct ril_sim_card *self)
+{
+ struct ril_sim_card_priv *priv = self->priv;
+
+ if (priv->sub_req_id) {
+ /* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
+ * so we better drop rather than cancel it (so that it gets
+ * removed from the list of pending requests) */
+ grilio_channel_drop_request(priv->io, priv->sub_req_id);
+ priv->sub_req_id = 0;
+ }
+ grilio_queue_transaction_finish(priv->q);
+}
+
+static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
+ const void* data, guint len, void* user_data)
+{
+ struct ril_sim_card *self = RIL_SIMCARD(user_data);
+ struct ril_sim_card_priv *priv = self->priv;
+
+ GASSERT(status == GRILIO_STATUS_OK);
+ GASSERT(priv->sub_req_id);
+ priv->sub_req_id = 0;
+ DBG("UICC subscription OK for slot %u", self->slot);
+ ril_sim_card_subscription_done(self);
+}
+
+static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
+ enum ril_uicc_subscription_action sub_action)
{
struct ril_sim_card_priv *priv = self->priv;
GRilIoRequest *req = grilio_request_sized_new(16);
const guint sub_id = self->slot;
+ guint code;
- DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_status);
+ DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_action);
grilio_request_append_int32(req, self->slot);
grilio_request_append_int32(req, app_index);
grilio_request_append_int32(req, sub_id);
- grilio_request_append_int32(req, sub_status);
- grilio_queue_send_request(priv->q, req, (priv->io->ril_version <= 9 &&
+ grilio_request_append_int32(req, sub_action);
+
+ grilio_request_set_retry(req, 0, -1);
+ grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
+ code = (priv->io->ril_version <= 9 &&
(priv->flags & RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND)) ?
- RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
- RIL_REQUEST_SET_UICC_SUBSCRIPTION);
+ RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
+ RIL_REQUEST_SET_UICC_SUBSCRIPTION;
+ if (priv->sub_req_id) {
+ /* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
+ * so we better drop rather than cancel it (so that it gets
+ * removed from the list of pending requests) */
+ grilio_channel_drop_request(priv->io, priv->sub_req_id);
+ }
+
+ /* Don't allow any requests other that GET_SIM_STATUS until
+ * we are done with the subscription */
+ grilio_queue_transaction_start(priv->q);
+ priv->sub_req_id = grilio_queue_send_request_full(priv->q,
+ req, code, ril_sim_card_subscribe_cb, NULL, self);
grilio_request_unref(req);
}
@@ -183,14 +248,17 @@
if (status->gsm_umts_index >= 0 &&
status->gsm_umts_index < status->num_apps) {
app_index = status->gsm_umts_index;
+ ril_sim_card_subscription_done(self);
} else {
app_index = ril_sim_card_select_app(status);
if (app_index >= 0) {
- ril_sim_card_subscribe(self, app_index, 1);
+ ril_sim_card_subscribe(self, app_index,
+ RIL_UICC_SUBSCRIPTION_ACTIVATE);
}
}
} else {
app_index = -1;
+ ril_sim_card_subscription_done(self);
}
if (app_index >= 0 &&
@@ -201,8 +269,8 @@
}
if (!ril_sim_card_app_equal(old_app, self->app)) {
- g_signal_emit(self,
- ril_sim_card_signals[SIGNAL_APP_CHANGED], 0);
+ g_signal_emit(self, ril_sim_card_signals
+ [SIGNAL_APP_CHANGED], 0);
}
}
@@ -216,23 +284,23 @@
self->status = status;
ril_sim_card_update_app(self);
- g_signal_emit(self, ril_sim_card_signals[
- SIGNAL_STATUS_RECEIVED], 0);
+ g_signal_emit(self, ril_sim_card_signals
+ [SIGNAL_STATUS_RECEIVED], 0);
if (diff & RIL_SIMCARD_STATUS_CHANGED) {
DBG("status changed");
- g_signal_emit(self, ril_sim_card_signals[
- SIGNAL_STATUS_CHANGED], 0);
+ g_signal_emit(self, ril_sim_card_signals
+ [SIGNAL_STATUS_CHANGED], 0);
}
if (diff & RIL_SIMCARD_STATE_CHANGED) {
DBG("state changed");
- g_signal_emit(self, ril_sim_card_signals[
- SIGNAL_STATE_CHANGED], 0);
+ g_signal_emit(self, ril_sim_card_signals
+ [SIGNAL_STATE_CHANGED], 0);
}
ril_sim_card_status_free(old_status);
} else {
ril_sim_card_status_free(status);
- g_signal_emit(self, ril_sim_card_signals[
- SIGNAL_STATUS_RECEIVED], 0);
+ g_signal_emit(self, ril_sim_card_signals
+ [SIGNAL_STATUS_RECEIVED], 0);
}
}
@@ -315,7 +383,8 @@
status->num_apps = num_apps;
if (num_apps > 0) {
- status->apps = g_new0(struct ril_sim_card_app, num_apps);
+ status->apps =
+ g_new0(struct ril_sim_card_app, num_apps);
}
for (i = 0; i < num_apps; i++) {
@@ -336,6 +405,7 @@
}
if (i == num_apps) {
+ GASSERT(grilio_parser_at_end(&rilp));
return status;
} else {
ril_sim_card_status_free(status);
@@ -347,7 +417,7 @@
static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
const void *data, guint len, void *user_data)
{
- struct ril_sim_card *self = user_data;
+ struct ril_sim_card *self = RIL_SIMCARD(user_data);
struct ril_sim_card_priv *priv = self->priv;
GASSERT(priv->status_req_id);
@@ -365,26 +435,103 @@
void ril_sim_card_request_status(struct ril_sim_card *self)
{
- struct ril_sim_card_priv *priv = self->priv;
+ if (G_LIKELY(self)) {
+ struct ril_sim_card_priv *priv = self->priv;
- if (priv->status_req_id) {
- /* Retry right away, don't wait for retry timeout to expire */
- grilio_channel_retry_request(priv->io, priv->status_req_id);
- } else {
- GRilIoRequest* req = grilio_request_new();
+ if (priv->status_req_id) {
+ /* Retry right away, don't wait for retry
+ * timeout to expire */
+ grilio_channel_retry_request(priv->io,
+ priv->status_req_id);
+ } else {
+ GRilIoRequest* req = grilio_request_new();
- grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
- priv->status_req_id = grilio_queue_send_request_full(priv->q,
+ grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
+ priv->status_req_id =
+ grilio_queue_send_request_full(priv->q,
req, RIL_REQUEST_GET_SIM_STATUS,
ril_sim_card_status_cb, NULL, self);
- grilio_request_unref(req);
+ grilio_request_unref(req);
+ }
+ }
+}
+
+static void ril_sim_card_update_sim_io_active(struct ril_sim_card *self)
+{
+ /* SIM I/O is considered active for certain period of time after
+ * the last request has completed. That's because SIM_IO requests
+ * are usually submitted in large quantities and quick succession.
+ * Some RILs don't like being bothered while they are doing SIM I/O
+ * and some time after that too. That sucks but what else can we
+ * do about it? */
+ struct ril_sim_card_priv *priv = self->priv;
+ const gboolean active = priv->sim_io_idle_id ||
+ g_hash_table_size(priv->sim_io_pending);
+
+ if (self->sim_io_active != active) {
+ self->sim_io_active = active;
+ DBG("SIM I/O for slot %u is %sactive", self->slot,
+ active ? "" : "in");
+ g_signal_emit(self, ril_sim_card_signals
+ [SIGNAL_SIM_IO_ACTIVE_CHANGED], 0);
+ }
+}
+
+void ril_sim_card_sim_io_started(struct ril_sim_card *self, guint id)
+{
+ if (G_LIKELY(self) && G_LIKELY(id)) {
+ struct ril_sim_card_priv *priv = self->priv;
+ gpointer key = GINT_TO_POINTER(id);
+
+ g_hash_table_insert(priv->sim_io_pending, key, key);
+ if (priv->sim_io_idle_id) {
+ g_source_remove(priv->sim_io_idle_id);
+ priv->sim_io_idle_id = 0;
+ priv->sim_io_idle_count = 0;
+ }
+ ril_sim_card_update_sim_io_active(self);
+ }
+}
+
+static gboolean ril_sim_card_sim_io_idle_cb(gpointer user_data)
+{
+ struct ril_sim_card *self = RIL_SIMCARD(user_data);
+ struct ril_sim_card_priv *priv = self->priv;
+
+ if (++(priv->sim_io_idle_count) >= SIM_IO_IDLE_LOOPS) {
+ priv->sim_io_idle_id = 0;
+ priv->sim_io_idle_count = 0;
+ ril_sim_card_update_sim_io_active(self);
+ return G_SOURCE_REMOVE;
+ } else {
+ return G_SOURCE_CONTINUE;
+ }
+}
+
+void ril_sim_card_sim_io_finished(struct ril_sim_card *self, guint id)
+{
+ if (G_LIKELY(self) && G_LIKELY(id)) {
+ struct ril_sim_card_priv *priv = self->priv;
+ gpointer key = GINT_TO_POINTER(id);
+
+ if (g_hash_table_remove(priv->sim_io_pending, key) &&
+ !g_hash_table_size(priv->sim_io_pending)) {
+ /* Reset the idle loop count */
+ if (priv->sim_io_idle_id) {
+ g_source_remove(priv->sim_io_idle_id);
+ priv->sim_io_idle_count = 0;
+ }
+ priv->sim_io_idle_id =
+ g_idle_add(ril_sim_card_sim_io_idle_cb, self);
+ }
+ ril_sim_card_update_sim_io_active(self);
}
}
static void ril_sim_card_status_changed(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
- struct ril_sim_card *self = user_data;
+ struct ril_sim_card *self = RIL_SIMCARD(user_data);
ril_sim_card_request_status(self);
}
@@ -472,6 +619,13 @@
SIGNAL_APP_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
+gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *self,
+ ril_sim_card_cb_t cb, void *arg)
+{
+ return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
+ SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
+}
+
void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
@@ -486,8 +640,11 @@
static void ril_sim_card_init(struct ril_sim_card *self)
{
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIMCARD_TYPE,
- struct ril_sim_card_priv);
+ struct ril_sim_card_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
+ RIL_SIMCARD_TYPE, struct ril_sim_card_priv);
+
+ self->priv = priv;
+ priv->sim_io_pending = g_hash_table_new(g_direct_hash, g_direct_equal);
}
static void ril_sim_card_dispose(GObject *object)
@@ -505,6 +662,10 @@
struct ril_sim_card *self = RIL_SIMCARD(object);
struct ril_sim_card_priv *priv = self->priv;
+ if (priv->sim_io_idle_id) {
+ g_source_remove(priv->sim_io_idle_id);
+ }
+ g_hash_table_destroy(priv->sim_io_pending);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);
ril_sim_card_status_free(self->status);
@@ -518,22 +679,11 @@
object_class->dispose = ril_sim_card_dispose;
object_class->finalize = ril_sim_card_finalize;
g_type_class_add_private(klass, sizeof(struct ril_sim_card_priv));
- ril_sim_card_signals[SIGNAL_STATUS_RECEIVED] =
- g_signal_new(SIGNAL_STATUS_RECEIVED_NAME,
- G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
- ril_sim_card_signals[SIGNAL_STATUS_CHANGED] =
- g_signal_new(SIGNAL_STATUS_CHANGED_NAME,
- G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
- ril_sim_card_signals[SIGNAL_STATE_CHANGED] =
- g_signal_new(SIGNAL_STATE_CHANGED_NAME,
- G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
- ril_sim_card_signals[SIGNAL_APP_CHANGED] =
- g_signal_new(SIGNAL_APP_CHANGED_NAME,
- G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+ NEW_SIGNAL_(klass,STATUS_RECEIVED);
+ NEW_SIGNAL(klass,STATUS);
+ NEW_SIGNAL(klass,STATE);
+ NEW_SIGNAL(klass,APP);
+ NEW_SIGNAL(klass,SIM_IO_ACTIVE);
}
/*
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_sim_card.h
^
|
@@ -44,6 +44,7 @@
struct ril_sim_card_priv *priv;
struct ril_sim_card_status *status;
const struct ril_sim_card_app *app;
+ gboolean sim_io_active;
guint slot;
};
@@ -55,7 +56,9 @@
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
void ril_sim_card_unref(struct ril_sim_card *sc);
-void ril_sim_card_request_status(struct ril_sim_card *self);
+void ril_sim_card_request_status(struct ril_sim_card *sc);
+void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
+void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
@@ -65,6 +68,8 @@
ril_sim_card_cb_t cb, void *arg);
gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *sc,
ril_sim_card_cb_t cb, void *arg);
+gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *sc,
+ ril_sim_card_cb_t cb, void *arg);
void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_sim_settings.c
^
|
@@ -16,17 +16,14 @@
#include "ril_sim_settings.h"
#include "ril_log.h"
-#include <gutil_misc.h>
+#include "sailfish_watch.h"
-#include <ofono/sim.h>
+#include <gutil_misc.h>
+#include "ofono.h"
#include "storage.h"
-#define RIL_SIM_STORE "ril"
-#define RIL_SIM_STORE_GROUP "Settings"
-#define RIL_SIM_STORE_PREF_MODE "TechnologyPreference"
-
-#define RIL_SIM_STORE_PREF_MODE_DEFAULT(self) (\
+#define RIL_PREF_MODE_DEFAULT(self) (\
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
OFONO_RADIO_ACCESS_MODE_LTE : \
((self)->techs & OFONO_RADIO_ACCESS_MODE_UMTS) ? \
@@ -36,10 +33,14 @@
typedef GObjectClass RilSimSettingsClass;
typedef struct ril_sim_settings RilSimSettings;
+enum sailfish_watch_events {
+ WATCH_EVENT_IMSI,
+ WATCH_EVENT_COUNT
+};
+
struct ril_sim_settings_priv {
- struct ofono_sim *sim;
- guint imsi_watch_id;
- guint state_watch_id;
+ gulong watch_event_id[WATCH_EVENT_COUNT];
+ struct sailfish_watch *watch;
GKeyFile *storage;
char *imsi;
};
@@ -66,175 +67,77 @@
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
+/* Skip the leading slash from the modem path: */
+#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
+
static void ril_sim_settings_signal_emit(struct ril_sim_settings *self,
enum ril_sim_settings_signal id)
{
g_signal_emit(self, ril_sim_settings_signals[id], 0);
}
-static void ril_sim_settings_reload(struct ril_sim_settings *self)
-{
- struct ril_sim_settings_priv *priv = self->priv;
-
- if (priv->storage) {
- g_key_file_free(priv->storage);
- priv->storage = NULL;
- }
-
- if (priv->imsi) {
- char *mode_str;
- enum ofono_radio_access_mode mode;
- priv->storage = storage_open(priv->imsi, RIL_SIM_STORE);
- mode_str = g_key_file_get_string(priv->storage,
- RIL_SIM_STORE_GROUP, RIL_SIM_STORE_PREF_MODE, NULL);
- if (ofono_radio_access_mode_from_string(mode_str, &mode)) {
- if (!(self->techs & mode)) {
- mode = OFONO_RADIO_ACCESS_MODE_ANY;
- }
- } else {
- mode = OFONO_RADIO_ACCESS_MODE_ANY;
- }
- if (mode == OFONO_RADIO_ACCESS_MODE_ANY) {
- self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
- } else {
- self->pref_mode = mode;
- }
- g_free(mode_str);
- }
-}
-
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *self,
enum ofono_radio_access_mode mode)
{
if (G_LIKELY(self) && self->pref_mode != mode) {
- struct ril_sim_settings_priv *priv = self->priv;
- const char *mode_str = ofono_radio_access_mode_to_string(mode);
-
- GASSERT(priv->storage);
- if (mode_str) {
- if (priv->storage) {
- g_key_file_set_string(priv->storage,
- RIL_SIM_STORE_GROUP,
- RIL_SIM_STORE_PREF_MODE, mode_str);
- storage_sync(self->imsi, RIL_SIM_STORE,
- priv->storage);
- }
- self->pref_mode = mode;
- ril_sim_settings_signal_emit(self,
- SIGNAL_PREF_MODE_CHANGED);
- }
+ self->pref_mode = mode;
+ ril_sim_settings_signal_emit(self, SIGNAL_PREF_MODE_CHANGED);
}
}
-static void ril_sim_settings_set_imsi(struct ril_sim_settings *self,
- const char *imsi)
+static void ril_sim_settings_imsi_changed(struct sailfish_watch *watch,
+ void *user_data)
{
+ struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
struct ril_sim_settings_priv *priv = self->priv;
- if (g_strcmp0(priv->imsi, imsi)) {
- enum ofono_radio_access_mode prev_mode = self->pref_mode;
+
+ if (g_strcmp0(priv->imsi, watch->imsi)) {
g_free(priv->imsi);
- self->imsi = priv->imsi = g_strdup(imsi);
- ril_sim_settings_reload(self);
+ self->imsi = priv->imsi = g_strdup(watch->imsi);
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
- if (prev_mode != self->pref_mode) {
- ril_sim_settings_signal_emit(self,
- SIGNAL_PREF_MODE_CHANGED);
- }
}
}
-static void ril_sim_settings_imsi_watch_cb(const char *imsi, void *user_data)
-{
- ril_sim_settings_set_imsi(RIL_SIM_SETTINGS(user_data), imsi);
-}
-
-static void ril_sim_settings_imsi_watch_done(void *user_data)
+struct ril_sim_settings *ril_sim_settings_new(const char *path,
+ enum ofono_radio_access_mode techs)
{
- struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
- struct ril_sim_settings_priv *priv = self->priv;
+ struct ril_sim_settings *self = NULL;
- GASSERT(priv->imsi_watch_id);
- priv->imsi_watch_id = 0;
-}
+ if (G_LIKELY(path)) {
+ struct ril_sim_settings_priv *priv;
-static void ril_sim_settings_state_check(struct ril_sim_settings *self,
- enum ofono_sim_state new_state)
-{
- if (new_state != OFONO_SIM_STATE_READY) {
- ril_sim_settings_set_imsi(self, NULL);
+ self = g_object_new(RIL_SIM_SETTINGS_TYPE, NULL);
+ priv = self->priv;
+ self->techs = techs;
+ self->pref_mode = RIL_PREF_MODE_DEFAULT(self);
+ priv->watch = sailfish_watch_new(path);
+ priv->watch_event_id[WATCH_EVENT_IMSI] =
+ sailfish_watch_add_imsi_changed_handler(priv->watch,
+ ril_sim_settings_imsi_changed, self);
+ self->imsi = priv->imsi = g_strdup(priv->watch->imsi);
}
-}
-static void ril_sim_settings_state_watch(enum ofono_sim_state new_state,
- void *user_data)
-{
- ril_sim_settings_state_check(RIL_SIM_SETTINGS(user_data), new_state);
+ return self;
}
-static void ril_sim_settings_state_watch_done(void *user_data)
+struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
{
- struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
- struct ril_sim_settings_priv *priv = self->priv;
-
- GASSERT(priv->state_watch_id);
- priv->state_watch_id = 0;
+ if (G_LIKELY(self)) {
+ g_object_ref(RIL_SIM_SETTINGS(self));
+ return self;
+ } else {
+ return NULL;
+ }
}
-void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
- struct ofono_sim *sim)
+void ril_sim_settings_unref(struct ril_sim_settings *self)
{
if (G_LIKELY(self)) {
- struct ril_sim_settings_priv *priv = self->priv;
- if (priv->sim != sim) {
- GASSERT(priv->sim || !priv->imsi_watch_id);
- if (priv->imsi_watch_id) {
- ofono_sim_remove_imsi_watch(priv->sim,
- priv->imsi_watch_id);
- /*
- * ril_sim_settings_imsi_watch_done
- * clears it
- */
- GASSERT(!priv->imsi_watch_id);
- }
- if (priv->state_watch_id) {
- ofono_sim_remove_state_watch(priv->sim,
- priv->state_watch_id);
- /*
- * ril_sim_settings_state_watch_done
- * clears it
- */
- GASSERT(!priv->state_watch_id);
- }
- priv->sim = sim;
- if (sim) {
- priv->state_watch_id =
- ofono_sim_add_state_watch(sim,
- ril_sim_settings_state_watch, self,
- ril_sim_settings_state_watch_done);
- GASSERT(priv->state_watch_id);
- ril_sim_settings_state_check(self,
- ofono_sim_get_state(sim));
- /*
- * ofono_sim_add_imsi_watch immediately
- * calls the event callback if IMSI is
- * already known. It's useless though
- * because we still have to check the
- * current state in case if IMSI is not
- * available yet.
- */
- priv->imsi_watch_id =
- ofono_sim_add_imsi_watch(priv->sim,
- ril_sim_settings_imsi_watch_cb, self,
- ril_sim_settings_imsi_watch_done);
- GASSERT(priv->state_watch_id);
- }
- /* Luckily, ofono_sim_get_imsi handles NULL pointer */
- ril_sim_settings_set_imsi(self,
- ofono_sim_get_imsi(sim));
- }
+ g_object_unref(RIL_SIM_SETTINGS(self));
}
}
+
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *self,
ril_sim_settings_cb_t cb, void *arg)
{
@@ -263,51 +166,26 @@
gutil_disconnect_handlers(self, ids, count);
}
-struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc)
-{
- struct ril_sim_settings *self = g_object_new(RIL_SIM_SETTINGS_TYPE, 0);
- self->techs = sc->techs;
- self->slot = sc->slot;
- self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
- return self;
-}
-
-struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
-{
- if (G_LIKELY(self)) {
- g_object_ref(RIL_SIM_SETTINGS(self));
- return self;
- } else {
- return NULL;
- }
-}
-
-void ril_sim_settings_unref(struct ril_sim_settings *self)
-{
- if (G_LIKELY(self)) {
- g_object_unref(RIL_SIM_SETTINGS(self));
- }
-}
-
static void ril_sim_settings_init(struct ril_sim_settings *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIM_SETTINGS_TYPE,
struct ril_sim_settings_priv);
}
-static void ril_sim_settings_dispose(GObject *object)
+static void ril_sim_settings_finalize(GObject *object)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
+ struct ril_sim_settings_priv *priv = self->priv;
- ril_sim_settings_set_ofono_sim(self, NULL);
- G_OBJECT_CLASS(ril_sim_settings_parent_class)->dispose(object);
+ sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
+ sailfish_watch_unref(priv->watch);
+ g_free(priv->imsi);
+ G_OBJECT_CLASS(ril_sim_settings_parent_class)->finalize(object);
}
static void ril_sim_settings_class_init(RilSimSettingsClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
-
- object_class->dispose = ril_sim_settings_dispose;
+ G_OBJECT_CLASS(klass)->finalize = ril_sim_settings_finalize;
g_type_class_add_private(klass, sizeof(struct ril_sim_settings_priv));
NEW_SIGNAL(klass, IMSI);
NEW_SIGNAL(klass, PREF_MODE);
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_sim_settings.h
^
|
@@ -23,7 +23,6 @@
struct ril_sim_settings {
GObject object;
struct ril_sim_settings_priv *priv;
- guint slot;
const char *imsi;
enum ofono_radio_access_mode techs;
enum ofono_radio_access_mode pref_mode;
@@ -31,7 +30,8 @@
typedef void (*ril_sim_settings_cb_t)(struct ril_sim_settings *s, void *arg);
-struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc);
+struct ril_sim_settings *ril_sim_settings_new(const char *path,
+ enum ofono_radio_access_mode techs);
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *s);
void ril_sim_settings_unref(struct ril_sim_settings *s);
void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *s,
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_sms.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015-2016 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,7 +14,6 @@
*/
#include "ril_plugin.h"
-#include "ril_constants.h"
#include "ril_util.h"
#include "ril_log.h"
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_stk.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
-#include "ril_constants.h"
#include "util.h"
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_subscription.conf
^
|
@@ -35,18 +35,22 @@
#
#3GLTEHandover=true
+# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
+# This option allows you to forcibly enable or disable use of this request.
+# It's involved in 3G/LTE handover between the modems, meaning that it only
+# makes sense if you have more than one slot.
+#
+# Possible values are auto, on and off
+#
+# Default is auto (enable for RIL version >= 11)
+#
+#SetRadioCapability=auto
+
[ril_0]
# Required entry, defines the RIL socket path
socket=/dev/socket/rild
-# If modem entry entry is marked is optional, it will be ignored
-# if the socket path does not exist at the time when ofono starts.
-#
-# The default is false (i.e. keep trying to connect)
-#
-# optional=false
-
# Subscription string. Some (mostly, older) RILs require that 4 bytes
# (usually SUB1 or SUB2) are written to the socket before rild starts
# talking to us.
@@ -113,7 +117,7 @@
# This option allows you to forcibly enable or disable use of this request.
# Possible values are auto, on and off
#
-# Default is auto (usage based on the RIL version)
+# Default is auto (enable for RIL version >= 11)
#
#allowDataReq=auto
@@ -164,3 +168,11 @@
#
#remoteHangupReasons=20
#localHangupReasons=23
+
+# Voice call support. Some devices like USB modems and tablets don't support
+# voice calls. By default, voice calls are enabled and this option allows you
+# to disable voice call handling.
+#
+# Default true
+#
+#enableVoicecall=true
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_types.h
^
|
@@ -40,20 +40,18 @@
#define RIL_RETRY_SECS (2)
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
-struct ril_mce;
struct ril_data;
struct ril_modem;
struct ril_radio;
struct ril_network;
struct ril_sim_card;
-struct ril_sim_info;
-struct ril_sim_settings;
struct ril_cell_info;
struct ril_slot_config {
guint slot;
enum ofono_radio_access_mode techs;
gboolean empty_pin_query;
+ gboolean enable_voicecall;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
};
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_ussd.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015-2016 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,7 +16,6 @@
#include "ril_plugin.h"
#include "ril_util.h"
#include "ril_log.h"
-#include "ril_constants.h"
#include "smsutil.h"
#include "util.h"
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_util.c
^
|
@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015-2016 Jolla Ltd.
+ * Copyright (C) 2015-2017 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -48,7 +48,8 @@
RIL_E_(MODE_NOT_SUPPORTED);
RIL_E_(FDN_CHECK_FAILURE);
RIL_E_(ILLEGAL_SIM_OR_ME);
- RIL_E_(UNUSED);
+ RIL_E_(MISSING_RESOURCE);
+ RIL_E_(NO_SUCH_ELEMENT);
RIL_E_(DIAL_MODIFIED_TO_USSD);
RIL_E_(DIAL_MODIFIED_TO_SS);
RIL_E_(DIAL_MODIFIED_TO_DIAL);
@@ -57,11 +58,39 @@
RIL_E_(USSD_MODIFIED_TO_USSD);
RIL_E_(SS_MODIFIED_TO_DIAL);
RIL_E_(SS_MODIFIED_TO_USSD);
- RIL_E_(SS_MODIFIED_TO_SS);
RIL_E_(SUBSCRIPTION_NOT_SUPPORTED);
- RIL_E_(MISSING_RESOURCE);
- RIL_E_(NO_SUCH_ELEMENT);
- RIL_E_(INVALID_PARAMETER);
+ RIL_E_(SS_MODIFIED_TO_SS);
+ RIL_E_(LCE_NOT_SUPPORTED);
+ RIL_E_(NO_MEMORY);
+ RIL_E_(INTERNAL_ERR);
+ RIL_E_(SYSTEM_ERR);
+ RIL_E_(MODEM_ERR);
+ RIL_E_(INVALID_STATE);
+ RIL_E_(NO_RESOURCES);
+ RIL_E_(SIM_ERR);
+ RIL_E_(INVALID_ARGUMENTS);
+ RIL_E_(INVALID_SIM_STATE);
+ RIL_E_(INVALID_MODEM_STATE);
+ RIL_E_(INVALID_CALL_ID);
+ RIL_E_(NO_SMS_TO_ACK);
+ RIL_E_(NETWORK_ERR);
+ RIL_E_(REQUEST_RATE_LIMITED);
+ RIL_E_(SIM_BUSY);
+ RIL_E_(SIM_FULL);
+ RIL_E_(NETWORK_REJECT);
+ RIL_E_(OPERATION_NOT_ALLOWED);
+ RIL_E_(EMPTY_RECORD);
+ RIL_E_(INVALID_SMS_FORMAT);
+ RIL_E_(ENCODING_ERR);
+ RIL_E_(INVALID_SMSC_ADDRESS);
+ RIL_E_(NO_SUCH_ENTRY);
+ RIL_E_(NETWORK_NOT_READY);
+ RIL_E_(NOT_PROVISIONED);
+ RIL_E_(NO_SUBSCRIPTION);
+ RIL_E_(NO_NETWORK_FOUND);
+ RIL_E_(DEVICE_IN_USE);
+ RIL_E_(ABORTED);
+ RIL_E_(INVALID_RESPONSE);
default:
snprintf(unknown, sizeof(unknown), "%d", error);
return unknown;
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ril/ril_voicecall.c
^
|
@@ -14,7 +14,6 @@
*/
#include "ril_plugin.h"
-#include "ril_constants.h"
#include "ril_ecclist.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -23,9 +22,13 @@
#include <gutil_ints.h>
#include <gutil_ring.h>
+#include <gutil_idlequeue.h>
+#include <gutil_intarray.h>
#define FLAG_NEED_CLIP 1
+#define VOICECALL_BLOCK_TIMEOUT_MS (5*1000)
+
enum ril_voicecall_events {
VOICECALL_EVENT_CALL_STATE_CHANGED,
VOICECALL_EVENT_SUPP_SVC_NOTIFICATION,
@@ -39,11 +42,11 @@
GRilIoQueue *q;
struct ofono_voicecall *vc;
struct ril_ecclist *ecclist;
- unsigned int local_release;
unsigned char flags;
ofono_voicecall_cb_t cb;
void *data;
- guint timer_id;
+ GUtilIntArray *local_release_ids;
+ GUtilIdleQueue *idleq;
GUtilRing *dtmf_queue;
GUtilInts *local_hangup_reasons;
GUtilInts *remote_hangup_reasons;
@@ -55,11 +58,13 @@
gulong ecclist_change_id;
};
-struct ril_voicecall_change_state_req {
+struct ril_voicecall_request_data {
+ int ref_count;
+ int pending_call_count;
+ int success;
struct ofono_voicecall *vc;
ofono_voicecall_cb_t cb;
gpointer data;
- int affected_types;
};
struct lastcause_req {
@@ -70,6 +75,32 @@
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
+struct ril_voicecall_request_data *ril_voicecall_request_data_new
+ (struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data)
+{
+ struct ril_voicecall_request_data *req =
+ g_slice_new0(struct ril_voicecall_request_data);
+
+ req->ref_count = 1;
+ req->vc = vc;
+ req->cb = cb;
+ req->data = data;
+ return req;
+}
+
+static void ril_voicecall_request_data_unref
+ (struct ril_voicecall_request_data *req)
+{
+ if (!--req->ref_count) {
+ g_slice_free(struct ril_voicecall_request_data, req);
+ }
+}
+
+static void ril_voicecall_request_data_free(gpointer data)
+{
+ ril_voicecall_request_data_unref(data);
+}
+
static inline struct ril_voicecall *ril_voicecall_get_data(
struct ofono_voicecall *vc)
{
@@ -319,7 +350,9 @@
struct ofono_call *oc = o ? o->data : NULL;
if (oc && (nc == NULL || (nc->id > oc->id))) {
- if (vd->local_release & (1 << oc->id)) {
+ /* old call is gone */
+ if (gutil_int_array_remove_all_fast(
+ vd->local_release_ids, oc->id)) {
ofono_voicecall_disconnected(vd->vc, oc->id,
OFONO_DISCONNECT_REASON_LOCAL_HANGUP,
NULL);
@@ -399,9 +432,7 @@
}
g_slist_free_full(vd->calls, g_free);
-
vd->calls = calls;
- vd->local_release = 0;
}
static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
@@ -420,52 +451,47 @@
static void ril_voicecall_request_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
- struct ril_voicecall_change_state_req *req = user_data;
+ struct ril_voicecall_request_data *req = user_data;
struct ril_voicecall *vd = ril_voicecall_get_data(req->vc);
- struct ofono_error error;
+ ril_voicecall_clcc_poll(vd);
+
+ /*
+ * The ofono API call is considered successful if at least one
+ * associated RIL request succeeds.
+ */
if (status == RIL_E_SUCCESS) {
- GSList *l;
+ req->success++;
+ }
- if (req->affected_types) {
- for (l = vd->calls; l; l = l->next) {
- struct ofono_call *call = l->data;
+ /*
+ * Only invoke the callback if this is the last request associated
+ * with this ofono api call (pending call count becomes zero).
+ */
+ GASSERT(req->pending_call_count > 0);
+ if (!--req->pending_call_count && req->cb) {
+ struct ofono_error error;
- if (req->affected_types & (1 << call->status)) {
- vd->local_release |= (1 << call->id);
- }
- }
+ if (req->success) {
+ ril_error_init_ok(&error);
+ } else {
+ ril_error_init_failure(&error);
}
- ril_error_init_ok(&error);
- } else {
- ofono_error("generic fail");
- ril_error_init_failure(&error);
- }
-
- ril_voicecall_clcc_poll(vd);
-
- /* We have to callback after we schedule a poll if required */
- if (req->cb) {
req->cb(&error, req->data);
}
}
-static void ril_voicecall_request(const guint rreq, struct ofono_voicecall *vc,
- unsigned int affected_types, GRilIoRequest *ioreq,
- ofono_voicecall_cb_t cb, void *data)
+static void ril_voicecall_request(const guint code, struct ofono_voicecall *vc,
+ GRilIoRequest *req, ofono_voicecall_cb_t cb, void *data)
{
- struct ril_voicecall *vd = ril_voicecall_get_data(vc);
- struct ril_voicecall_change_state_req *req;
+ struct ril_voicecall_request_data *req_data =
+ ril_voicecall_request_data_new(vc, cb, data);
- req = g_new0(struct ril_voicecall_change_state_req, 1);
- req->vc = vc;
- req->cb = cb;
- req->data = data;
- req->affected_types = affected_types;
-
- grilio_queue_send_request_full(vd->q, ioreq, rreq,
- ril_voicecall_request_cb, g_free, req);
+ req_data->pending_call_count++;
+ grilio_queue_send_request_full(ril_voicecall_get_data(vc)->q, req,
+ code, ril_voicecall_request_cb,
+ ril_voicecall_request_data_free, req_data);
}
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
@@ -523,47 +549,68 @@
grilio_request_unref(req);
}
+static void ril_voicecall_submit_hangup_req(struct ofono_voicecall *vc,
+ int id, struct ril_voicecall_request_data *req)
+{
+ struct ril_voicecall *vd = ril_voicecall_get_data(vc);
+ GRilIoRequest *ioreq = grilio_request_array_int32_new(1, id);
+
+ /* Append the call id to the list of calls being released locally */
+ GASSERT(!gutil_int_array_contains(vd->local_release_ids, id));
+ gutil_int_array_append(vd->local_release_ids, id);
+
+ /* Send request to RIL. ril_voicecall_request_data_free will unref
+ * the request data */
+ req->ref_count++;
+ req->pending_call_count++;
+ grilio_queue_send_request_full(vd->q, ioreq, RIL_REQUEST_HANGUP,
+ ril_voicecall_request_cb,
+ ril_voicecall_request_data_free, req);
+ grilio_request_unref(ioreq);
+}
+
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
- struct ofono_error error;
- GSList *l;
- for (l = vd->calls; l; l = l->next) {
- struct ofono_call *call = l->data;
- GRilIoRequest *req = grilio_request_sized_new(8);
-
- /* TODO: Hangup just the active ones once we have call
- * state tracking (otherwise it can't handle ringing) */
- DBG("Hanging up call with id %d", call->id);
- grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
- grilio_request_append_int32(req, call->id);
-
- /* Send request to RIL */
- ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req,
- NULL, NULL);
- grilio_request_unref(req);
- }
+ if (vd->calls) {
+ GSList *l;
+ struct ril_voicecall_request_data *req =
+ ril_voicecall_request_data_new(vc, cb, data);
- /* TODO: Deal in case of an error at hungup */
- cb(ril_error_ok(&error), data);
+ /*
+ * Here the idea is that we submit (potentially) multiple
+ * hangup requests to RIL and invoke the callback after
+ * the last request has completed (pending call count
+ * becomes zero).
+ */
+ for (l = vd->calls; l; l = l->next) {
+ struct ofono_call *call = l->data;
+
+ /* Send request to RIL */
+ DBG("Hanging up call with id %d", call->id);
+ ril_voicecall_submit_hangup_req(vc, call->id, req);
+ }
+
+ /* Release our reference */
+ ril_voicecall_request_data_unref(req);
+ } else {
+ /* No calls */
+ struct ofono_error error;
+ cb(ril_error_ok(&error), data);
+ }
}
-static void ril_voicecall_hangup_specific(struct ofono_voicecall *vc,
+static void ril_voicecall_release_specific(struct ofono_voicecall *vc,
int id, ofono_voicecall_cb_t cb, void *data)
{
- GRilIoRequest *req = grilio_request_sized_new(8);
- struct ofono_error error;
+ struct ril_voicecall_request_data *req =
+ ril_voicecall_request_data_new(vc, cb, data);
DBG("Hanging up call with id %d", id);
- grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
- grilio_request_append_int32(req, id);
-
- /* Send request to RIL */
- ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req, NULL, NULL);
- grilio_request_unref(req);
- cb(ril_error_ok(&error), data);
+ ril_voicecall_submit_hangup_req(vc, id, req);
+ ril_voicecall_request_data_unref(req);
}
static void ril_voicecall_call_state_changed_event(GRilIoChannel *io,
@@ -618,7 +665,7 @@
{
/* Send request to RIL */
DBG("Answering current call");
- ril_voicecall_request(RIL_REQUEST_ANSWER, vc, 0, NULL, cb, data);
+ ril_voicecall_request(RIL_REQUEST_ANSWER, vc, NULL, cb, data);
}
static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
@@ -687,29 +734,25 @@
static void ril_voicecall_create_multiparty(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
- ril_voicecall_request(RIL_REQUEST_CONFERENCE,
- vc, 0, NULL, cb, data);
+ ril_voicecall_request(RIL_REQUEST_CONFERENCE, vc, NULL, cb, data);
}
static void ril_voicecall_transfer(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_request(RIL_REQUEST_EXPLICIT_CALL_TRANSFER,
- vc, 0, NULL, cb, data);
+ vc, NULL, cb, data);
}
static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
ofono_voicecall_cb_t cb, void *data)
{
- GRilIoRequest *req = grilio_request_sized_new(8);
+ GRilIoRequest *req = grilio_request_array_int32_new(1, id);
struct ofono_error error;
DBG("Private chat with id %d", id);
- grilio_request_append_int32(req, 1);
- grilio_request_append_int32(req, id);
-
ril_voicecall_request(RIL_REQUEST_SEPARATE_CONNECTION,
- vc, 0, req, NULL, NULL);
+ vc, req, NULL, NULL);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
}
@@ -717,51 +760,52 @@
static void ril_voicecall_swap_without_accept(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
+ DBG("");
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
- vc, 0, NULL, cb, data);
+ vc, NULL, cb, data);
}
static void ril_voicecall_hold_all_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
+ DBG("");
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
- vc, 0, NULL, cb, data);
+ vc, NULL, cb, data);
}
static void ril_voicecall_release_all_held(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
+ DBG("");
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
- vc, 0, NULL, cb, data);
+ vc, NULL, cb, data);
}
static void ril_voicecall_release_all_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
+ DBG("");
ril_voicecall_request(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
- vc, 0, NULL, cb, data);
+ vc, NULL, cb, data);
}
static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
+ DBG("");
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
- vc, 0, NULL, cb, data);
+ vc, NULL, cb, data);
}
-static gboolean ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
+static void ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
{
- GRilIoRequest *req = grilio_request_sized_new(8);
-
- grilio_request_append_int32(req, 1); /* size of array */
- grilio_request_append_int32(req, 1); /* notifications enabled */
+ GRilIoRequest *req = grilio_request_array_int32_new(1, 1);
+ grilio_request_set_timeout(req, VOICECALL_BLOCK_TIMEOUT_MS);
+ grilio_request_set_blocking(req, TRUE);
grilio_queue_send_request(vd->q, req,
RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION);
grilio_request_unref(req);
-
- /* Makes this a single shot */
- return FALSE;
}
static void ril_voicecall_ringback_tone_event(GRilIoChannel *io,
@@ -789,12 +833,10 @@
ofono_voicecall_en_list_notify(vd->vc, vd->ecclist->list);
}
-static gboolean ril_delayed_register(gpointer user_data)
+static void ril_voicecall_register(gpointer user_data)
{
struct ril_voicecall *vd = user_data;
- GASSERT(vd->timer_id);
- vd->timer_id = 0;
ofono_voicecall_register(vd->vc);
/* Emergency Call Codes */
@@ -828,9 +870,6 @@
grilio_channel_add_unsol_event_handler(vd->io,
ril_voicecall_ringback_tone_event,
RIL_UNSOL_RINGBACK_TONE, vd);
-
- /* This makes the timeout a single-shot */
- return FALSE;
}
static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
@@ -847,13 +886,15 @@
vd->dtmf_queue = gutil_ring_new();
vd->local_hangup_reasons = gutil_ints_ref(cfg->local_hangup_reasons);
vd->remote_hangup_reasons = gutil_ints_ref(cfg->remote_hangup_reasons);
+ vd->local_release_ids = gutil_int_array_new();
+ vd->idleq = gutil_idle_queue_new();
vd->vc = vc;
- vd->timer_id = g_idle_add(ril_delayed_register, vd);
if (modem->ecclist_file) {
vd->ecclist = ril_ecclist_new(modem->ecclist_file);
}
ril_voicecall_clear_dtmf_queue(vd);
ofono_voicecall_set_data(vc, vd);
+ gutil_idle_queue_add(vd->idleq, ril_voicecall_register, vd);
return 0;
}
@@ -865,10 +906,6 @@
ofono_voicecall_set_data(vc, NULL);
g_slist_free_full(vd->calls, g_free);
- if (vd->timer_id > 0) {
- g_source_remove(vd->timer_id);
- }
-
ril_ecclist_remove_handler(vd->ecclist, vd->ecclist_change_id);
ril_ecclist_unref(vd->ecclist);
@@ -880,6 +917,8 @@
gutil_ring_unref(vd->dtmf_queue);
gutil_ints_unref(vd->local_hangup_reasons);
gutil_ints_unref(vd->remote_hangup_reasons);
+ gutil_int_array_free(vd->local_release_ids, TRUE);
+ gutil_idle_queue_free(vd->idleq);
g_free(vd);
}
@@ -890,7 +929,7 @@
.dial = ril_voicecall_dial,
.answer = ril_voicecall_answer,
.hangup_all = ril_voicecall_hangup_all,
- .release_specific = ril_voicecall_hangup_specific,
+ .release_specific = ril_voicecall_release_specific,
.send_tones = ril_voicecall_send_dtmf,
.create_multiparty = ril_voicecall_create_multiparty,
.transfer = ril_voicecall_transfer,
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/drivers/ubloxmodem/gprs-context.c
^
|
@@ -261,6 +261,7 @@
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = 1;
break;
+ case OFONO_GPRS_AUTH_METHOD_ANY:
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = 2;
break;
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/include/gprs-context.h
^
|
@@ -49,7 +49,9 @@
};
enum ofono_gprs_auth_method {
- OFONO_GPRS_AUTH_METHOD_CHAP = 0,
+ OFONO_GPRS_AUTH_METHOD_ANY = 0,
+ OFONO_GPRS_AUTH_METHOD_NONE,
+ OFONO_GPRS_AUTH_METHOD_CHAP,
OFONO_GPRS_AUTH_METHOD_PAP,
};
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/include/netreg.h
^
|
@@ -114,6 +114,7 @@
int ofono_netreg_get_technology(struct ofono_netreg *netreg);
const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg);
const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg);
+const char *ofono_netreg_get_name(struct ofono_netreg *netreg);
struct sim_spdi *ofono_netreg_get_spdi(struct ofono_netreg *netreg);
#ifdef __cplusplus
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/include/sailfish_manager.h
^
|
@@ -0,0 +1,121 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SAILFISHOS_MANAGER_H
+#define SAILFISHOS_MANAGER_H
+
+struct ofono_modem;
+
+#include <ofono/types.h>
+#include <ofono/radio-settings.h>
+
+#include <glib.h>
+
+struct sailfish_manager;
+struct sailfish_slot;
+struct sailfish_slot_impl;
+struct sailfish_slot_driver;
+struct sailfish_slot_driver_reg;
+struct sailfish_slot_manager;
+struct sailfish_slot_manager_impl;
+typedef void (*sailfish_slot_manager_impl_cb_t)
+ (struct sailfish_slot_manager_impl *impl, void *user_data);
+
+typedef struct sailfish_slot {
+ const char *path;
+ const char *imei;
+ const char *imeisv;
+ gboolean sim_present;
+ gboolean enabled;
+} const *sailfish_slot_ptr;
+
+struct sailfish_manager {
+ const char *mms_imsi;
+ const char *mms_path;
+ const char *default_voice_imsi;
+ const char *default_data_imsi;
+ const char *default_voice_path;
+ const char *default_data_path;
+ const sailfish_slot_ptr *slots;
+ gboolean ready;
+};
+
+enum sailfish_sim_state {
+ SAILFISH_SIM_STATE_UNKNOWN,
+ SAILFISH_SIM_STATE_ABSENT,
+ SAILFISH_SIM_STATE_PRESENT,
+ SAILFISH_SIM_STATE_ERROR
+};
+
+enum sailfish_data_role {
+ SAILFISH_DATA_ROLE_NONE, /* Data not allowed */
+ SAILFISH_DATA_ROLE_MMS, /* Data is allowed at any speed */
+ SAILFISH_DATA_ROLE_INTERNET /* Data is allowed at full speed */
+};
+
+/* Register/unregister the driver */
+struct sailfish_slot_driver_reg *sailfish_slot_driver_register
+ (const struct sailfish_slot_driver *d);
+void sailfish_slot_driver_unregister(struct sailfish_slot_driver_reg *r);
+
+/* For use by the driver implementations */
+void sailfish_manager_foreach_slot_manager
+ (struct sailfish_slot_driver_reg *r,
+ sailfish_slot_manager_impl_cb_t cb, void *user_data);
+struct sailfish_slot *sailfish_manager_slot_add
+ (struct sailfish_slot_manager *m, struct sailfish_slot_impl *i,
+ const char *path, enum ofono_radio_access_mode techs,
+ const char *imei, const char *imeisv,
+ enum sailfish_sim_state sim_state);
+void sailfish_manager_imei_obtained(struct sailfish_slot *s, const char *imei);
+void sailfish_manager_imeisv_obtained(struct sailfish_slot *s,
+ const char *imeisv);
+void sailfish_manager_set_sim_state(struct sailfish_slot *s,
+ enum sailfish_sim_state state);
+void sailfish_slot_manager_started(struct sailfish_slot_manager *m);
+void sailfish_manager_slot_error(struct sailfish_slot *s, const char *key,
+ const char *message);
+void sailfish_manager_error(struct sailfish_slot_manager *m, const char *key,
+ const char *message);
+
+/* Callbacks provided by slot plugins */
+struct sailfish_slot_driver {
+ const char *name;
+ int priority;
+
+ /* Slot manager methods */
+ struct sailfish_slot_manager_impl *(*manager_create)
+ (struct sailfish_slot_manager *m);
+ guint (*manager_start)(struct sailfish_slot_manager_impl *s);
+ void (*manager_cancel_start)(struct sailfish_slot_manager_impl *s,
+ guint id);
+ void (*manager_free)(struct sailfish_slot_manager_impl *s);
+
+ /* Slot methods */
+ void (*slot_enabled_changed)(struct sailfish_slot_impl *s);
+ void (*slot_set_data_role)(struct sailfish_slot_impl *s,
+ enum sailfish_data_role role);
+ void (*slot_free)(struct sailfish_slot_impl *s);
+};
+
+#endif /* SAILFISHOS_MANAGER_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/include/sailfish_watch.h
^
|
@@ -0,0 +1,81 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SAILFISH_WATCH_H
+#define SAILFISH_WATCH_H
+
+struct ofono_modem;
+struct ofono_sim;
+struct ofono_netreg;
+
+#include <glib.h>
+#include <glib-object.h>
+
+/* This object watches ofono modem and various related things */
+struct sailfish_watch_priv;
+struct sailfish_watch {
+ GObject object;
+ struct sailfish_watch_priv *priv;
+ const char *path;
+ /* Modem */
+ struct ofono_modem *modem;
+ gboolean online;
+ /* OFONO_ATOM_TYPE_SIM */
+ struct ofono_sim *sim;
+ const char *iccid;
+ const char *imsi;
+ const char *spn;
+ /* OFONO_ATOM_TYPE_NETREG */
+ struct ofono_netreg *netreg;
+};
+
+typedef void (*sailfish_watch_cb_t)(struct sailfish_watch *w, void *user_data);
+
+struct sailfish_watch *sailfish_watch_new(const char *path);
+struct sailfish_watch *sailfish_watch_ref(struct sailfish_watch *w);
+void sailfish_watch_unref(struct sailfish_watch *w);
+
+gulong sailfish_watch_add_modem_changed_handler(struct sailfish_watch *w,
+ sailfish_watch_cb_t cb, void *user_data);
+gulong sailfish_watch_add_online_changed_handler(struct sailfish_watch *w,
+ sailfish_watch_cb_t cb, void *user_data);
+gulong sailfish_watch_add_sim_changed_handler(struct sailfish_watch *w,
+ sailfish_watch_cb_t cb, void *user_data);
+gulong sailfish_watch_add_sim_state_changed_handler(struct sailfish_watch *w,
+ sailfish_watch_cb_t cb, void *user_data);
+gulong sailfish_watch_add_iccid_changed_handler(struct sailfish_watch *w,
+ sailfish_watch_cb_t cb, void *user_data);
+gulong sailfish_watch_add_imsi_changed_handler(struct sailfish_watch *w,
+ sailfish_watch_cb_t cb, void *user_data);
+gulong sailfish_watch_add_spn_changed_handler(struct sailfish_watch *w,
+ sailfish_watch_cb_t cb, void *user_data);
+gulong sailfish_watch_add_netreg_changed_handler(struct sailfish_watch *w,
+ sailfish_watch_cb_t cb, void *user_data);
+void sailfish_watch_remove_handler(struct sailfish_watch *w, gulong id);
+void sailfish_watch_remove_handlers(struct sailfish_watch *w, gulong *ids,
+ int count);
+
+#define sailfish_watch_remove_all_handlers(w,ids) \
+ sailfish_watch_remove_handlers(w, ids, G_N_ELEMENTS(ids))
+
+#endif /* SAILFISH_WATCH_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/mbpi.c
^
|
@@ -53,6 +53,9 @@
enum ofono_gprs_proto mbpi_default_internet_proto = OFONO_GPRS_PROTO_IPV4V6;
enum ofono_gprs_proto mbpi_default_mms_proto = OFONO_GPRS_PROTO_IP;
enum ofono_gprs_proto mbpi_default_proto = OFONO_GPRS_PROTO_IP;
+enum ofono_gprs_auth_method mbpi_default_auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
+
+#define OFONO_GPRS_AUTH_METHOD_UNSPECIFIED ((enum ofono_gprs_auth_method)(-1))
#define _(x) case x: return (#x)
@@ -166,6 +169,10 @@
*auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
else if (strcmp(text, "pap") == 0)
*auth_method = OFONO_GPRS_AUTH_METHOD_PAP;
+ else if (strcmp(text, "any") == 0)
+ *auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
+ else if (strcmp(text, "none") == 0)
+ *auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
else
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
@@ -344,7 +351,7 @@
ap->apn = g_strdup(apn);
ap->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
ap->proto = mbpi_default_proto;
- ap->auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
+ ap->auth_method = OFONO_GPRS_AUTH_METHOD_UNSPECIFIED;
g_markup_parse_context_push(context, &apn_parser, ap);
}
@@ -414,6 +421,17 @@
if (ap == NULL)
return;
+ /* Fix the authentication method if none was specified */
+ if (ap->auth_method == OFONO_GPRS_AUTH_METHOD_UNSPECIFIED) {
+ if ((!ap->username || !ap->username[0]) &&
+ (!ap->password || !ap->password[0])) {
+ /* No username or password => no authentication */
+ ap->auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
+ } else {
+ ap->auth_method = mbpi_default_auth_method;
+ }
+ }
+
if (gsm->allow_duplicates == FALSE) {
GSList *l;
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/mbpi.h
^
|
@@ -23,6 +23,7 @@
extern enum ofono_gprs_proto mbpi_default_internet_proto;
extern enum ofono_gprs_proto mbpi_default_mms_proto;
extern enum ofono_gprs_proto mbpi_default_proto;
+extern enum ofono_gprs_auth_method mbpi_default_auth_method;
const char *mbpi_ap_type(enum ofono_gprs_context_type type);
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/provision.c
^
|
@@ -3,7 +3,6 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
- * Copyright (C) 2013-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,7 +23,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <errno.h>
#include <string.h>
@@ -37,114 +35,9 @@
#include <ofono/modem.h>
#include <ofono/gprs-provision.h>
-#include "provision.h"
#include "mbpi.h"
-struct provision_ap_defaults {
- enum ofono_gprs_context_type type;
- const char *name;
- const char *apn;
-};
-
-static gboolean provision_match_name(const struct ofono_gprs_provision_data *ap,
- const char* spn)
-{
- return (ap->provider_name && strcasestr(ap->provider_name, spn)) ||
- (ap->name && strcasestr(ap->name, spn)) ||
- (ap->apn && strcasestr(ap->apn, spn));
-}
-
-static void provision_free_ap(gpointer data)
-{
- mbpi_ap_free(data);
-}
-
-static gint provision_compare_ap(gconstpointer a, gconstpointer b, gpointer data)
-{
- const struct ofono_gprs_provision_data *ap1 = a;
- const struct ofono_gprs_provision_data *ap2 = b;
- const char* spn = data;
-
- if (spn) {
- const gboolean match1 = provision_match_name(ap1, spn);
- const gboolean match2 = provision_match_name(ap2, spn);
- if (match1 && !match2) {
- return -1;
- } else if (match2 && !match1) {
- return 1;
- }
- }
-
- if (ap1->provider_primary && !ap2->provider_primary) {
- return -1;
- } else if (ap2->provider_primary && !ap1->provider_primary) {
- return 1;
- } else {
- return 0;
- }
-}
-
-/* Picks best ap, deletes the rest. Creates one if necessary */
-static GSList *provision_pick_best_ap(GSList *list, const char* spn,
- const enum ofono_gprs_proto default_proto,
- const struct provision_ap_defaults *defaults)
-{
- /* Sort the list */
- list = g_slist_sort_with_data(list, provision_compare_ap, (void*)spn);
- if (list) {
- /* Pick the best one, delete the rest */
- GSList *best = list;
- g_slist_free_full(g_slist_remove_link(list, best),
- provision_free_ap);
- return best;
- } else {
- /* or create one from the default data */
- struct ofono_gprs_provision_data *ap =
- g_new0(struct ofono_gprs_provision_data, 1);
-
- ap->proto = default_proto;
- ap->type = defaults->type;
- ap->name = g_strdup(defaults->name);
- ap->apn = g_strdup(defaults->apn);
- return g_slist_append(NULL, ap);
- }
-}
-
-/* Returns the list containing exactly one INTERNET and one MMS access point */
-static GSList *provision_normalize_apn_list(GSList *apns, const char* spn)
-{
- static const struct provision_ap_defaults internet_defaults =
- { OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
- static const struct provision_ap_defaults mms_defaults =
- { OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
-
- GSList *internet_apns = NULL;
- GSList *mms_apns = NULL;
-
- /* Split internet and mms apns, delete all others */
- while (apns) {
- GSList *link = apns;
- struct ofono_gprs_provision_data *ap = link->data;
-
- apns = g_slist_remove_link(apns, link);
- if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
- internet_apns = g_slist_concat(internet_apns, link);
- } else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
- mms_apns = g_slist_concat(mms_apns, link);
- } else {
- g_slist_free_full(link, provision_free_ap);
- }
- }
-
- /* Pick the best ap of each type and concatenate them */
- return g_slist_concat(
- provision_pick_best_ap(internet_apns, spn,
- mbpi_default_internet_proto, &internet_defaults),
- provision_pick_best_ap(mms_apns, spn,
- mbpi_default_mms_proto, &mms_defaults));
-}
-
-int provision_get_settings(const char *mcc, const char *mnc,
+static int provision_get_settings(const char *mcc, const char *mnc,
const char *spn,
struct ofono_gprs_provision_data **settings,
int *count)
@@ -155,26 +48,21 @@
int ap_count;
int i;
- ofono_info("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
+ DBG("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
- /*
- * Passing FALSE to mbpi_lookup_apn() would return
- * an empty list if duplicates are found.
- */
- apns = mbpi_lookup_apn(mcc, mnc, TRUE, &error);
- if (error != NULL) {
- ofono_error("%s", error->message);
- g_error_free(error);
- }
+ apns = mbpi_lookup_apn(mcc, mnc, FALSE, &error);
+ if (apns == NULL) {
+ if (error != NULL) {
+ ofono_error("%s", error->message);
+ g_error_free(error);
+ }
- ofono_info("Found %d APs in MBPI", g_slist_length(apns));
- apns = provision_normalize_apn_list(apns, spn);
- if (apns == NULL)
return -ENOENT;
+ }
ap_count = g_slist_length(apns);
- ofono_info("Provisioning %d APs", ap_count);
+ DBG("Found %d APs", ap_count);
*settings = g_try_new0(struct ofono_gprs_provision_data, ap_count);
if (*settings == NULL) {
@@ -193,11 +81,11 @@
for (l = apns, i = 0; l; l = l->next, i++) {
struct ofono_gprs_provision_data *ap = l->data;
- ofono_info("Name: '%s'", ap->name);
- ofono_info("APN: '%s'", ap->apn);
- ofono_info("Type: %s", mbpi_ap_type(ap->type));
- ofono_info("Username: '%s'", ap->username);
- ofono_info("Password: '%s'", ap->password);
+ DBG("Name: '%s'", ap->name);
+ DBG("APN: '%s'", ap->apn);
+ DBG("Type: %s", mbpi_ap_type(ap->type));
+ DBG("Username: '%s'", ap->username);
+ DBG("Password: '%s'", ap->password);
memcpy(*settings + i, ap,
sizeof(struct ofono_gprs_provision_data));
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_bt.c
^
|
(renamed from ofono/plugins/sfos_bt.c)
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_debuglog.c
^
|
(renamed from ofono/plugins/debuglog.c)
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_manager/sailfish_manager.c
^
|
@@ -0,0 +1,1300 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gutil_log.h>
+#include <gutil_strv.h>
+#include <gutil_macros.h>
+#include <string.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include "ofono.h"
+#include "storage.h"
+
+#include <sailfish_manager.h>
+#include "sailfish_manager_dbus.h"
+#include "sailfish_sim_info.h"
+#include "sailfish_watch.h"
+
+/* How long we wait for all drivers to register (number of idle loops) */
+#define SF_INIT_IDLE_COUNT (5)
+
+enum sailfish_watch_events {
+ WATCH_EVENT_MODEM,
+ WATCH_EVENT_ONLINE,
+ WATCH_EVENT_IMSI,
+ WATCH_EVENT_COUNT
+};
+
+struct sailfish_manager_priv {
+ struct sailfish_manager pub; /* Public part */
+ struct sailfish_slot_driver_reg *drivers;
+ struct sailfish_manager_dbus *dbus;
+ struct sailfish_slot_priv *voice_slot;
+ struct sailfish_slot_priv *data_slot;
+ struct sailfish_slot_priv *mms_slot;
+ sailfish_slot_ptr *slots;
+ int slot_count;
+ guint init_countdown;
+ guint init_id;
+ char *default_voice_imsi;
+ char *default_data_imsi;
+ char *mms_imsi;
+ GKeyFile *storage;
+ GHashTable *errors;
+};
+
+struct sailfish_slot_driver_reg {
+ struct sailfish_slot_driver_reg *next;
+ const struct sailfish_slot_driver *driver;
+ struct sailfish_manager_priv *plugin;
+ struct sailfish_slot_manager *manager;
+ guint init_id;
+};
+
+struct sailfish_slot_manager {
+ const struct sailfish_slot_driver *driver;
+ struct sailfish_manager_priv *plugin;
+ struct sailfish_slot_manager_impl *impl;
+ struct sailfish_slot_priv *slots;
+ gboolean started;
+ guint start_id;
+};
+
+struct sailfish_slot_priv {
+ struct sailfish_slot pub;
+ struct sailfish_slot_priv *next;
+ struct sailfish_slot_manager *manager;
+ struct sailfish_slot_impl *impl;
+ struct sailfish_watch *watch;
+ struct sailfish_sim_info *siminfo;
+ struct sailfish_sim_info_dbus *siminfo_dbus;
+ enum sailfish_sim_state sim_state;
+ gulong watch_event_id[WATCH_EVENT_COUNT];
+ char *imei;
+ char *imeisv;
+ gboolean enabled_changed;
+ GHashTable *errors;
+ int index;
+};
+
+/* "ril" is used for historical reasons */
+#define SF_STORE "ril"
+#define SF_STORE_GROUP "Settings"
+#define SF_STORE_ENABLED_SLOTS "EnabledSlots"
+#define SF_STORE_DEFAULT_VOICE_SIM "DefaultVoiceSim"
+#define SF_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
+#define SF_STORE_SLOTS_SEP ","
+
+/* The file where error statistics is stored. Again "rilerror" is historical */
+#define SF_ERROR_STORAGE "rilerror" /* File name */
+#define SF_ERROR_COMMON_SECTION "common" /* Modem independent section */
+
+/* Path always starts with a slash, skip it */
+#define sailfish_slot_debug_prefix(s) ((s)->pub.path + 1)
+
+static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *);
+static gboolean sailfish_manager_update_ready(struct sailfish_manager_priv *p);
+
+static inline struct sailfish_manager_priv *sailfish_manager_priv_cast
+ (struct sailfish_manager *m)
+{
+ return G_CAST(m, struct sailfish_manager_priv, pub);
+}
+
+static inline struct sailfish_slot_priv *sailfish_slot_priv_cast
+ (struct sailfish_slot *s)
+{
+ return G_CAST(s, struct sailfish_slot_priv, pub);
+}
+
+static inline const struct sailfish_slot_priv *sailfish_slot_priv_cast_const
+ (const struct sailfish_slot *s)
+{
+ return G_CAST(s, struct sailfish_slot_priv, pub);
+}
+
+static inline void sailfish_slot_set_data_role(struct sailfish_slot_priv *s,
+ enum sailfish_data_role role)
+{
+ const struct sailfish_slot_driver *d = s->manager->driver;
+
+ if (d->slot_set_data_role) {
+ d->slot_set_data_role(s->impl, role);
+ }
+}
+
+/* Update modem paths and emit D-Bus signal if necessary */
+static void sailfish_manager_update_modem_paths_full
+ (struct sailfish_manager_priv *p)
+{
+ sailfish_manager_dbus_signal(p->dbus,
+ sailfish_manager_update_modem_paths(p));
+}
+
+/*
+ * sailfish_manager_foreach_slot() terminates the loop and returns
+ * TRUE if the callback returns TRUE. If all callbacks return FALSE, it
+ * returns FALSE. It there are no slots, it returns FALSE too.
+ */
+
+#define SF_LOOP_CONTINUE (FALSE)
+#define SF_LOOP_DONE (TRUE)
+
+static gboolean sailfish_manager_foreach_slot
+ (struct sailfish_manager_priv *p,
+ gboolean (*fn)(struct sailfish_slot_priv *s, void *user_data),
+ void *user_data)
+{
+ struct sailfish_slot_driver_reg *r = p->drivers;
+ gboolean done = FALSE;
+
+ while (r && !done) {
+ struct sailfish_slot_manager *m = r->manager;
+ struct sailfish_slot_driver_reg *rnext = r->next;
+
+ if (m) {
+ struct sailfish_slot_priv *s = m->slots;
+
+ while (s) {
+ struct sailfish_slot_priv *snext = s->next;
+
+ /* The callback returns TRUE to terminate
+ * the loop */
+ if (fn(s, user_data)) {
+ done = TRUE;
+ break;
+ }
+ s = snext;
+ }
+ }
+ r = rnext;
+ }
+
+ return done;
+}
+
+static void sailfish_manager_slot_modem_changed(struct sailfish_watch *w,
+ void *user_data)
+{
+ struct sailfish_slot_priv *s = user_data;
+ struct sailfish_manager_priv *p = s->manager->plugin;
+
+ sailfish_manager_update_modem_paths_full(p);
+ sailfish_manager_update_ready(p);
+}
+
+static void sailfish_manager_slot_imsi_changed(struct sailfish_watch *w,
+ void *user_data)
+{
+ struct sailfish_slot_priv *slot = user_data;
+ struct sailfish_manager_priv *plugin = slot->manager->plugin;
+ struct sailfish_slot_priv *voice_slot = plugin->voice_slot;
+ struct sailfish_slot_priv *data_slot = plugin->data_slot;
+ int signal_mask;
+
+ /*
+ * We want the first slot to be selected by default.
+ * However, things may become available in pretty much
+ * any order, so reset the slot pointers to NULL and let
+ * sailfish_manager_update_modem_paths() to pick them again.
+ */
+ plugin->voice_slot = NULL;
+ plugin->data_slot = NULL;
+ plugin->pub.default_voice_path = NULL;
+ plugin->pub.default_data_path = NULL;
+ signal_mask = sailfish_manager_update_modem_paths(plugin);
+ if (voice_slot != plugin->voice_slot) {
+ if (!plugin->voice_slot) {
+ DBG("No default voice SIM");
+ }
+ signal_mask |= SAILFISH_MANAGER_SIGNAL_VOICE_PATH;
+ }
+ if (data_slot != plugin->data_slot) {
+ if (!plugin->data_slot) {
+ DBG("No default data SIM");
+ }
+ signal_mask |= SAILFISH_MANAGER_SIGNAL_DATA_PATH;
+ }
+ sailfish_manager_dbus_signal(plugin->dbus, signal_mask);
+}
+
+static gboolean sailfish_manager_count_slot(struct sailfish_slot_priv *s,
+ void *user_data)
+{
+ (*((int *)user_data))++;
+ return SF_LOOP_CONTINUE;
+}
+
+static gboolean sailfish_manager_index_slot(struct sailfish_slot_priv *s,
+ void *user_data)
+{
+ struct sailfish_manager_priv *p = user_data;
+
+ s->index = p->slot_count;
+ p->slots[p->slot_count++] = &s->pub;
+ return SF_LOOP_CONTINUE;
+}
+
+static void sailfish_manager_reindex_slots(struct sailfish_manager_priv *p)
+{
+ int count = 0;
+
+ sailfish_manager_foreach_slot(p, sailfish_manager_count_slot, &count);
+
+ g_free(p->slots);
+ p->pub.slots = p->slots = g_new0(sailfish_slot_ptr, count + 1);
+
+ /* p->slot_count is the index for sailfish_manager_index_slot */
+ p->slot_count = 0;
+ sailfish_manager_foreach_slot(p, sailfish_manager_index_slot, p);
+ p->slots[p->slot_count] = NULL;
+ GASSERT(p->slot_count == count);
+}
+
+static gboolean sailfish_manager_check_slot_name(struct sailfish_slot_priv *s,
+ void *path)
+{
+ return strcmp(s->pub.path, path) ? SF_LOOP_CONTINUE : SF_LOOP_DONE;
+}
+
+struct sailfish_slot *sailfish_manager_slot_add
+ (struct sailfish_slot_manager *m, struct sailfish_slot_impl *impl,
+ const char *path, enum ofono_radio_access_mode techs,
+ const char *imei, const char *imeisv,
+ enum sailfish_sim_state sim_state)
+{
+ /* Only accept these calls when we are starting! We have been
+ * assuming all along that the number of slots is known right
+ * from startup. Perhaps it wasn't a super bright idea because
+ * there are USB modems which can appear (and disappear) pretty
+ * much at any time. This has to be dealt with somehow at some
+ * point but for now let's leave it as is. */
+ if (path && m && !m->started && !sailfish_manager_foreach_slot
+ (m->plugin, sailfish_manager_check_slot_name,
+ (char*)path)) {
+ char *enabled_slots;
+ struct sailfish_manager_priv *p = m->plugin;
+ struct sailfish_slot_priv *s =
+ g_slice_new0(struct sailfish_slot_priv);
+
+ DBG("%s", path);
+ s->impl = impl;
+ s->manager = m;
+ s->sim_state = sim_state;
+ s->watch = sailfish_watch_new(path);
+ s->siminfo = sailfish_sim_info_new(path);
+ s->siminfo_dbus = sailfish_sim_info_dbus_new(s->siminfo);
+ s->pub.path = s->watch->path;
+ s->pub.imei = s->imei = g_strdup(imei);
+ s->pub.imeisv = s->imeisv = g_strdup(imeisv);
+ s->pub.sim_present = (sim_state == SAILFISH_SIM_STATE_PRESENT);
+
+ /* Check if it's enabled */
+ enabled_slots = g_key_file_get_string(p->storage,
+ SF_STORE_GROUP, SF_STORE_ENABLED_SLOTS, NULL);
+ if (enabled_slots) {
+ char **strv = g_strsplit(enabled_slots,
+ SF_STORE_SLOTS_SEP, 0);
+
+ DBG("Enabled slots: %s", enabled_slots);
+ s->pub.enabled = gutil_strv_contains(strv, path);
+ g_strfreev(strv);
+ g_free(enabled_slots);
+ } else {
+ /* All slots are enabled by default */
+ s->pub.enabled = TRUE;
+ }
+
+ /* Add it to the list */
+ if (!m->slots) {
+ /* The first one */
+ m->slots = s;
+ } else if (strcmp(m->slots->pub.path, path) > 0) {
+ /* This one becomes the head of the list */
+ s->next = m->slots;
+ m->slots = s;
+ } else {
+ /* Need to do some sorting */
+ struct sailfish_slot_priv *prev = m->slots;
+ struct sailfish_slot_priv *slot = m->slots->next;
+
+ while (slot && strcmp(slot->pub.path, path) < 0) {
+ prev = slot;
+ slot = prev->next;
+ }
+
+ s->next = prev->next;
+ prev->next = s;
+ }
+
+ sailfish_manager_reindex_slots(m->plugin);
+
+ /* Register for events */
+ s->watch_event_id[WATCH_EVENT_MODEM] =
+ sailfish_watch_add_modem_changed_handler(s->watch,
+ sailfish_manager_slot_modem_changed, s);
+ s->watch_event_id[WATCH_EVENT_ONLINE] =
+ sailfish_watch_add_online_changed_handler(s->watch,
+ sailfish_manager_slot_modem_changed, s);
+ s->watch_event_id[WATCH_EVENT_IMSI] =
+ sailfish_watch_add_imsi_changed_handler(s->watch,
+ sailfish_manager_slot_imsi_changed, s);
+
+ return &s->pub;
+ } else {
+ ofono_error("Refusing to register slot %s", path);
+ }
+
+ return NULL;
+}
+
+static void sailfish_slot_free(struct sailfish_slot_priv *s)
+{
+ struct sailfish_slot_manager *m = s->manager;
+ struct sailfish_manager_priv *p = m->plugin;
+
+ if (s->impl) {
+ const struct sailfish_slot_driver *d = m->driver;
+
+ if (d->slot_free) {
+ d->slot_free(s->impl);
+ s->impl = NULL;
+ }
+ }
+ if (s->errors) {
+ g_hash_table_destroy(s->errors);
+ }
+ sailfish_sim_info_unref(s->siminfo);
+ sailfish_sim_info_dbus_free(s->siminfo_dbus);
+ sailfish_watch_remove_all_handlers(s->watch, s->watch_event_id);
+ sailfish_watch_unref(s->watch);
+ g_free(s->imei);
+ g_free(s->imeisv);
+ s->next = NULL;
+ s->manager = NULL;
+ g_slice_free(struct sailfish_slot_priv, s);
+ sailfish_manager_reindex_slots(p);
+}
+
+static void sailfish_manager_update_dbus_block(struct sailfish_manager_priv *p)
+{
+ enum sailfish_manager_dbus_block block =
+ SAILFISH_MANAGER_DBUS_BLOCK_NONE;
+
+ if (p->init_countdown) {
+ /* Plugin is being initialized */
+ block |= SAILFISH_MANAGER_DBUS_BLOCK_ALL;
+ } else {
+ struct sailfish_slot_driver_reg *r;
+
+ for (r = p->drivers; r; r = r->next) {
+ struct sailfish_slot_manager *m;
+ struct sailfish_slot_priv *s;
+
+ if (r->init_id) {
+ /* Driver is being initialized */
+ block |= SAILFISH_MANAGER_DBUS_BLOCK_ALL;
+ break;
+ }
+
+ m = r->manager;
+ if (!m) {
+ continue;
+ }
+
+ if (!m->started) {
+ /* Slots are being initialized */
+ block |= SAILFISH_MANAGER_DBUS_BLOCK_ALL;
+ break;
+ }
+
+ for (s = m->slots; s && s->imei; s = s->next);
+ if (s) {
+ /* IMEI is not available (yet) */
+ block |= SAILFISH_MANAGER_DBUS_BLOCK_IMEI;
+ }
+ }
+ }
+
+ sailfish_manager_dbus_set_block(p->dbus, block);
+}
+
+static void sailfish_manager_set_config_string
+ (struct sailfish_manager_priv *p, const char *key,
+ const char *value, gboolean sync)
+{
+ if (value) {
+ g_key_file_set_string(p->storage, SF_STORE_GROUP, key, value);
+ } else {
+ g_key_file_remove_key(p->storage, SF_STORE_GROUP, key, NULL);
+ }
+ if (sync) {
+ storage_sync(NULL, SF_STORE, p->storage);
+ }
+}
+
+struct sailfish_manager_slot_imsi_data {
+ struct sailfish_slot_priv *slot;
+ const char *imsi;
+};
+
+static gboolean sailfish_manager_find_slot_imsi_proc
+ (struct sailfish_slot_priv *s, void *user_data)
+{
+ struct sailfish_manager_slot_imsi_data *data = user_data;
+ const char *slot_imsi = s->watch->imsi;
+
+ if (slot_imsi && !strcmp(slot_imsi, data->imsi)) {
+ data->slot = s;
+ return SF_LOOP_DONE;
+ } else {
+ return SF_LOOP_CONTINUE;
+ }
+}
+
+struct sailfish_manager_any_slot_data {
+ struct sailfish_slot_priv *slot;
+};
+
+static gboolean sailfish_manager_find_any_slot_proc
+ (struct sailfish_slot_priv *s, void *user_data)
+{
+ struct sailfish_manager_any_slot_data *data = user_data;
+ const char *slot_imsi = s->watch->imsi;
+
+ if (slot_imsi) {
+ data->slot = s;
+ return SF_LOOP_DONE;
+ } else {
+ return SF_LOOP_CONTINUE;
+ }
+}
+
+static struct sailfish_slot_priv *sailfish_manager_find_slot_imsi
+ (struct sailfish_manager_priv *p,
+ const char *imsi)
+{
+ if (imsi) {
+ /* We are looking for the specific sim */
+ struct sailfish_manager_slot_imsi_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.imsi = imsi;
+ sailfish_manager_foreach_slot(p,
+ sailfish_manager_find_slot_imsi_proc, &data);
+ return data.slot;
+ } else {
+ /* We are looking for any slot with a sim */
+ struct sailfish_manager_any_slot_data data;
+
+ memset(&data, 0, sizeof(data));
+ sailfish_manager_foreach_slot(p,
+ sailfish_manager_find_any_slot_proc, &data);
+ return data.slot;
+ }
+}
+
+/* Returns the event mask to be passed to sailfish_manager_dbus_signal.
+ * The caller has a chance to OR it with other bits */
+static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
+{
+ int mask = 0;
+ struct sailfish_slot_priv *slot = NULL;
+ struct sailfish_slot_priv *mms_slot = NULL;
+ struct sailfish_slot_priv *old_data_slot = NULL;
+ struct sailfish_slot_priv *new_data_slot = NULL;
+
+ /* Voice */
+ if (p->default_voice_imsi) {
+ slot = sailfish_manager_find_slot_imsi(p,
+ p->default_voice_imsi);
+ } else if (p->voice_slot) {
+ /* Make sure that the slot is enabled and SIM is in */
+ slot = sailfish_manager_find_slot_imsi(p,
+ p->voice_slot->watch->imsi);
+ }
+
+ /*
+ * If there's no default voice SIM, we will find any SIM instead.
+ * One should always be able to make and receive a phone call
+ * if there's a working SIM in the phone. However if the
+ * previously selected voice SIM is inserted, we will switch
+ * back to it.
+ *
+ * There is no such fallback for the data.
+ */
+ if (!slot) {
+ slot = sailfish_manager_find_slot_imsi(p, NULL);
+ }
+
+ if (p->voice_slot != slot) {
+ mask |= SAILFISH_MANAGER_SIGNAL_VOICE_PATH;
+ p->voice_slot = slot;
+ if (slot) {
+ const char *path = slot->pub.path;
+ DBG("Default voice SIM at %s", path);
+ p->pub.default_voice_path = path;
+ } else {
+ DBG("No default voice SIM");
+ p->pub.default_voice_path = NULL;
+ }
+ }
+
+ /* Data */
+ if (p->default_data_imsi) {
+ slot = sailfish_manager_find_slot_imsi(p,
+ p->default_data_imsi);
+ } else if (p->slot_count < 2) {
+ if (p->data_slot) {
+ /* Make sure that the slot is enabled and SIM is in */
+ slot = sailfish_manager_find_slot_imsi(p,
+ p->data_slot->watch->imsi);
+ } else {
+ /* Check if anything is available */
+ slot = sailfish_manager_find_slot_imsi(p, NULL);
+ }
+ } else {
+ /*
+ * Should we automatically select the default data sim
+ * on a multisim phone that has only one sim inserted?
+ */
+ slot = NULL;
+ }
+
+ if (slot && !slot->watch->online) {
+ slot = NULL;
+ }
+
+ if (p->mms_imsi) {
+ mms_slot = sailfish_manager_find_slot_imsi(p, p->mms_imsi);
+ }
+
+ if (mms_slot && mms_slot != slot) {
+ /*
+ * Reset default data SIM if another SIM is
+ * temporarily selected for MMS.
+ */
+ slot = NULL;
+ }
+
+ /* Are we actually switching data SIMs? */
+ old_data_slot = p->mms_slot ? p->mms_slot : p->data_slot;
+ new_data_slot = mms_slot ? mms_slot : slot;
+
+ if (p->data_slot != slot) {
+ mask |= SAILFISH_MANAGER_SIGNAL_DATA_PATH;
+ p->data_slot = slot;
+ if (slot) {
+ const char *path = slot->pub.path;
+ DBG("Default data SIM at %s", path);
+ p->pub.default_data_path = path;
+ } else {
+ DBG("No default data SIM");
+ p->pub.default_data_path = NULL;
+ }
+ }
+
+ if (p->mms_slot != mms_slot) {
+ mask |= SAILFISH_MANAGER_SIGNAL_MMS_PATH;
+ p->mms_slot = mms_slot;
+ if (mms_slot) {
+ const char *path = mms_slot->pub.path;
+ DBG("MMS data SIM at %s", path);
+ p->pub.mms_path = path;
+ } else {
+ DBG("No MMS data SIM");
+ p->pub.mms_path = NULL;
+ }
+ }
+
+ if (old_data_slot != new_data_slot) {
+ /* Yes we are switching data SIMs */
+ if (old_data_slot) {
+ sailfish_slot_set_data_role(old_data_slot,
+ SAILFISH_DATA_ROLE_NONE);
+ }
+ if (new_data_slot) {
+ sailfish_slot_set_data_role(new_data_slot,
+ (new_data_slot == p->data_slot) ?
+ SAILFISH_DATA_ROLE_INTERNET :
+ SAILFISH_DATA_ROLE_MMS);
+ }
+ }
+
+ return mask;
+}
+
+static gboolean sailfish_manager_update_ready_proc
+ (struct sailfish_slot_priv *s, void *unused)
+{
+ if (s->imei && s->sim_state != SAILFISH_SIM_STATE_UNKNOWN) {
+ /* This one is ready */
+ return SF_LOOP_CONTINUE;
+ } else {
+ /* This one is not */
+ return SF_LOOP_DONE;
+ }
+}
+
+static gboolean sailfish_manager_update_ready(struct sailfish_manager_priv *p)
+{
+ /*
+ * sailfish_manager_foreach_slot() returns FALSE if either all
+ * callbacks returned FALSE (SF_LOOP_CONTINUE) or there are no
+ * slots. In either case we are ready. */
+ const gboolean ready = !sailfish_manager_foreach_slot(p,
+ sailfish_manager_update_ready_proc, NULL);
+
+ if (p->pub.ready != ready) {
+ p->pub.ready = ready;
+ sailfish_manager_update_dbus_block(p);
+ DBG("%sready", ready ? "" : "not ");
+ sailfish_manager_dbus_signal(p->dbus,
+ SAILFISH_MANAGER_SIGNAL_READY);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+void sailfish_manager_imei_obtained(struct sailfish_slot *s, const char *imei)
+{
+ if (s) {
+ struct sailfish_slot_priv *slot = sailfish_slot_priv_cast(s);
+
+ /* We assume that IMEI never changes */
+ GASSERT(imei);
+ GASSERT(!slot->imei || !g_strcmp0(slot->imei, imei));
+ g_free(slot->imei); /* Just in case */
+ slot->pub.imei = slot->imei = g_strdup(imei);
+ sailfish_manager_update_ready(slot->manager->plugin);
+ }
+}
+
+void sailfish_manager_imeisv_obtained(struct sailfish_slot *s,
+ const char *imeisv)
+{
+ if (s) {
+ struct sailfish_slot_priv *slot = sailfish_slot_priv_cast(s);
+
+ /* We assume that IMEISV never changes */
+ GASSERT(imeisv);
+ GASSERT(!slot->imeisv || !g_strcmp0(slot->imeisv, imeisv));
+ g_free(slot->imeisv); /* Just in case */
+ slot->pub.imeisv = slot->imeisv = g_strdup(imeisv);
+ sailfish_manager_update_ready(slot->manager->plugin);
+ }
+}
+
+void sailfish_manager_set_sim_state(struct sailfish_slot *s,
+ enum sailfish_sim_state state)
+{
+ if (s) {
+ struct sailfish_slot_priv *slot = sailfish_slot_priv_cast(s);
+ struct sailfish_manager_priv *p = slot->manager->plugin;
+ const gboolean present = (state == SAILFISH_SIM_STATE_PRESENT);
+
+ if (slot->pub.sim_present != present) {
+ slot->pub.sim_present = present;
+ sailfish_manager_dbus_signal_sim(p->dbus,
+ slot->index, present);
+ if (!present) {
+ sailfish_sim_info_invalidate(slot->siminfo);
+ }
+ sailfish_manager_update_modem_paths_full(p);
+ }
+
+ if (slot->sim_state != state) {
+ slot->sim_state = state;
+ sailfish_manager_update_ready(p);
+ }
+ }
+}
+
+static gboolean sailfish_manager_update_enabled_slot
+ (struct sailfish_slot_priv *s, void *unused)
+{
+ if (s->pub.enabled && s->enabled_changed) {
+ const struct sailfish_slot_driver *d = s->manager->driver;
+
+ DBG("%s enabled", sailfish_slot_debug_prefix(s));
+ s->enabled_changed = TRUE;
+ if (d->slot_enabled_changed) {
+ d->slot_enabled_changed(s->impl);
+ }
+ }
+ return SF_LOOP_CONTINUE;
+}
+
+static gboolean sailfish_manager_update_disabled_slot
+ (struct sailfish_slot_priv *s, void *unused)
+{
+ if (!s->pub.enabled && s->enabled_changed) {
+ struct sailfish_slot_manager *m = s->manager;
+ const struct sailfish_slot_driver *d = m->driver;
+
+ DBG("%s disabled", sailfish_slot_debug_prefix(s));
+ s->enabled_changed = FALSE;
+ if (d->slot_enabled_changed) {
+ d->slot_enabled_changed(s->impl);
+ }
+ sailfish_manager_update_modem_paths_full(m->plugin);
+ }
+ return SF_LOOP_CONTINUE;
+}
+
+static void sailfish_manager_update_slots(struct sailfish_manager_priv *p)
+{
+ sailfish_manager_foreach_slot(p, sailfish_manager_update_disabled_slot,
+ NULL);
+ sailfish_manager_foreach_slot(p, sailfish_manager_update_enabled_slot,
+ NULL);
+ sailfish_manager_update_modem_paths_full(p);
+}
+
+static gboolean sailfish_manager_enabled_slots_proc
+ (struct sailfish_slot_priv *slot, void *user_data)
+{
+ if (slot->pub.enabled) {
+ char ***list = user_data;
+ *list = gutil_strv_add(*list, slot->pub.path);
+ }
+
+ return SF_LOOP_CONTINUE;
+}
+
+struct sailfish_manager_set_enabled_slots_data {
+ gchar * const * enabled;
+ gboolean all_enabled;
+ gboolean changed;
+};
+
+static gboolean sailfish_manager_set_enabled_slots_proc
+ (struct sailfish_slot_priv *slot, void *user_data)
+{
+ struct sailfish_manager_set_enabled_slots_data *data = user_data;
+ struct sailfish_slot *s = &slot->pub;
+ const gboolean was_enabled = s->enabled;
+
+ s->enabled = gutil_strv_contains(data->enabled, s->path);
+ if ((was_enabled && !s->enabled) || (!was_enabled && s->enabled)) {
+ slot->enabled_changed = TRUE;
+ data->changed = TRUE;
+ }
+
+ if (!s->enabled) {
+ data->all_enabled = FALSE;
+ }
+
+ return SF_LOOP_CONTINUE;
+}
+
+static void sailfish_manager_set_enabled_slots(struct sailfish_manager *m,
+ gchar **slots)
+{
+ struct sailfish_manager_priv *p = sailfish_manager_priv_cast(m);
+ struct sailfish_manager_set_enabled_slots_data data;
+
+ data.enabled = slots;
+ data.changed = FALSE;
+ data.all_enabled = TRUE;
+ sailfish_manager_foreach_slot(p,
+ sailfish_manager_set_enabled_slots_proc, &data);
+ if (data.changed) {
+ char **new_slots = NULL;
+
+ sailfish_manager_foreach_slot(p,
+ sailfish_manager_enabled_slots_proc, &new_slots);
+
+ /* Save the new config value. If it exactly matches the list
+ * of available modems, delete the setting because that's the
+ * default behavior. */
+ if (data.all_enabled) {
+ sailfish_manager_set_config_string(p,
+ SF_STORE_ENABLED_SLOTS, NULL, TRUE);
+ } else {
+ const char *value;
+ char *tmp;
+
+ if (new_slots) {
+ tmp = g_strjoinv(SF_STORE_SLOTS_SEP, new_slots);
+ value = tmp;
+ } else {
+ tmp = NULL;
+ value = "";
+ }
+
+ sailfish_manager_set_config_string(p,
+ SF_STORE_ENABLED_SLOTS, value, TRUE);
+ g_free(tmp);
+ }
+ g_strfreev(new_slots);
+ sailfish_manager_dbus_signal(p->dbus,
+ SAILFISH_MANAGER_SIGNAL_ENABLED_SLOTS);
+
+ /* Add and remove modems */
+ sailfish_manager_update_slots(p);
+ }
+}
+
+static void sailfish_manager_set_default_voice_imsi(struct sailfish_manager *m,
+ const char *imsi)
+{
+ struct sailfish_manager_priv *p = sailfish_manager_priv_cast(m);
+
+ if (g_strcmp0(p->default_voice_imsi, imsi)) {
+ DBG("Default voice sim set to %s", imsi ? imsi : "(auto)");
+ g_free(p->default_voice_imsi);
+ m->default_voice_imsi =
+ p->default_voice_imsi = g_strdup(imsi);
+ sailfish_manager_set_config_string(p,
+ SF_STORE_DEFAULT_VOICE_SIM, imsi, TRUE);
+ sailfish_manager_dbus_signal(p->dbus,
+ SAILFISH_MANAGER_SIGNAL_VOICE_IMSI |
+ sailfish_manager_update_modem_paths(p));
+ }
+}
+
+static void sailfish_manager_set_default_data_imsi(struct sailfish_manager *m,
+ const char *imsi)
+{
+ struct sailfish_manager_priv *p = sailfish_manager_priv_cast(m);
+
+ if (g_strcmp0(p->default_data_imsi, imsi)) {
+ DBG("Default data sim set to %s", imsi ? imsi : "(auto)");
+ g_free(p->default_data_imsi);
+ m->default_data_imsi =
+ p->default_data_imsi = g_strdup(imsi);
+ sailfish_manager_set_config_string(p,
+ SF_STORE_DEFAULT_DATA_SIM, imsi, TRUE);
+ sailfish_manager_dbus_signal(p->dbus,
+ SAILFISH_MANAGER_SIGNAL_DATA_IMSI |
+ sailfish_manager_update_modem_paths(p));
+ }
+}
+
+static gboolean sailfish_manager_set_mms_imsi(struct sailfish_manager *m,
+ const char *imsi)
+{
+ struct sailfish_manager_priv *p = sailfish_manager_priv_cast(m);
+
+ if (imsi && imsi[0]) {
+ if (g_strcmp0(p->mms_imsi, imsi)) {
+ if (sailfish_manager_find_slot_imsi(p, imsi)) {
+ DBG("MMS sim %s", imsi);
+ g_free(p->mms_imsi);
+ m->mms_imsi = p->mms_imsi = g_strdup(imsi);
+ sailfish_manager_dbus_signal(p->dbus,
+ SAILFISH_MANAGER_SIGNAL_MMS_IMSI |
+ sailfish_manager_update_modem_paths(p));
+ } else {
+ DBG("IMSI not found: %s", imsi);
+ return FALSE;
+ }
+ }
+ } else {
+ if (p->mms_imsi) {
+ DBG("No MMS sim");
+ g_free(p->mms_imsi);
+ m->mms_imsi = p->mms_imsi = NULL;
+ sailfish_manager_dbus_signal(p->dbus,
+ SAILFISH_MANAGER_SIGNAL_MMS_IMSI |
+ sailfish_manager_update_modem_paths(p));
+ }
+ }
+
+ return TRUE;
+}
+
+static GHashTable *sailfish_manager_inc_error_count(GHashTable *errors,
+ const char *group, const char *key)
+{
+ GKeyFile *storage = storage_open(NULL, SF_ERROR_STORAGE);
+
+ /* Update life-time statistics */
+ if (storage) {
+ g_key_file_set_integer(storage, group, key,
+ g_key_file_get_integer(storage, group, key, NULL) + 1);
+ storage_close(NULL, SF_ERROR_STORAGE, storage, TRUE);
+ }
+
+ /* Update run-time error counts. The key is the error id which
+ * is always a static string */
+ if (!errors) {
+ errors = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
+ }
+ g_hash_table_insert(errors, g_strdup(key), GINT_TO_POINTER(
+ GPOINTER_TO_INT(g_hash_table_lookup(errors, key)) + 1));
+ return errors;
+}
+
+void sailfish_manager_error(struct sailfish_slot_manager *m, const char *key,
+ const char *message)
+{
+ if (m) {
+ struct sailfish_manager_priv *p = m->plugin;
+
+ p->errors = sailfish_manager_inc_error_count(p->errors,
+ SF_ERROR_COMMON_SECTION, key);
+ sailfish_manager_dbus_signal_error(p->dbus, key, message);
+ }
+}
+
+void sailfish_manager_slot_error(struct sailfish_slot *s, const char *key,
+ const char *msg)
+{
+ if (s) {
+ struct sailfish_slot_priv *priv = sailfish_slot_priv_cast(s);
+ /* slot->path always starts with a slash, skip it */
+ const char *section = s->path + 1;
+ priv->errors = sailfish_manager_inc_error_count(priv->errors,
+ section, key);
+ sailfish_manager_dbus_signal_modem_error
+ (priv->manager->plugin->dbus, priv->index, key, msg);
+ }
+}
+
+static GHashTable *sailfish_manager_get_errors(struct sailfish_manager *m)
+{
+ return sailfish_manager_priv_cast(m)->errors;
+}
+
+static GHashTable *sailfish_manager_get_slot_errors
+ (const struct sailfish_slot *s)
+{
+ return sailfish_slot_priv_cast_const(s)->errors;
+}
+
+static void sailfish_slot_manager_has_started(struct sailfish_slot_manager *m)
+{
+ if (!m->started) {
+ DBG("%s", m->driver->name);
+ m->started = TRUE;
+ if (!sailfish_manager_update_ready(m->plugin)) {
+ sailfish_manager_update_dbus_block(m->plugin);
+ }
+ }
+}
+
+void sailfish_slot_manager_started(struct sailfish_slot_manager *m)
+{
+ DBG("%s", m->driver->name);
+ m->start_id = 0;
+ sailfish_slot_manager_has_started(m);
+}
+
+static void sailfish_slot_manager_start(struct sailfish_slot_manager *m)
+{
+ const struct sailfish_slot_driver *d = m->driver;
+
+ if (d->manager_start) {
+ m->start_id = d->manager_start(m->impl);
+ if (!m->start_id) {
+ sailfish_slot_manager_has_started(m);
+ }
+ }
+}
+
+static struct sailfish_slot_manager *sailfish_slot_manager_new
+ (struct sailfish_slot_driver_reg *r)
+{
+ const struct sailfish_slot_driver *d = r->driver;
+ struct sailfish_slot_manager *m =
+ g_slice_new0(struct sailfish_slot_manager);
+
+ m->driver = d;
+ m->plugin = r->plugin;
+ if (d->manager_create) {
+ m->impl = d->manager_create(m);
+ if (!m->impl) {
+ g_slice_free(struct sailfish_slot_manager, m);
+ return NULL;
+ }
+ }
+ return m;
+}
+
+static void sailfish_slot_manager_free(struct sailfish_slot_manager *m)
+{
+ /* Ignore nested sailfish_slot_manager_free calls */
+ if (m && m->impl) {
+ const struct sailfish_slot_driver *driver = m->driver;
+
+ if (m->start_id && driver->manager_cancel_start) {
+ driver->manager_cancel_start(m->impl, m->start_id);
+ }
+ while (m->slots) {
+ struct sailfish_slot_priv *s = m->slots;
+
+ m->slots = s->next;
+ s->next = NULL;
+ sailfish_slot_free(s);
+ }
+ if (driver->manager_free) {
+ struct sailfish_slot_manager_impl *impl = m->impl;
+
+ m->impl = NULL;
+ driver->manager_free(impl);
+ }
+ g_slice_free(struct sailfish_slot_manager, m);
+ }
+}
+
+static int sailfish_slot_driver_compare(const struct sailfish_slot_driver *a,
+ const struct sailfish_slot_driver *b)
+{
+ if (a->priority != b->priority) {
+ return a->priority - b->priority;
+ } else {
+ return -g_strcmp0(a->name, b->name);
+ }
+}
+
+static gboolean sailfish_slot_driver_init(gpointer user_data)
+{
+ struct sailfish_slot_driver_reg *r = user_data;
+
+ r->init_id = 0;
+ r->manager = sailfish_slot_manager_new(r);
+ if (r->manager) {
+ sailfish_slot_manager_start(r->manager);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static struct sailfish_slot_driver_reg *sailfish_manager_priv_reg_new
+ (struct sailfish_manager_priv *p,
+ const struct sailfish_slot_driver *d)
+{
+ struct sailfish_slot_driver_reg *r = NULL;
+
+ if (p) {
+ r = g_slice_new0(struct sailfish_slot_driver_reg);
+ r->plugin = p;
+ r->driver = d;
+ r->init_id = g_idle_add(sailfish_slot_driver_init, r);
+ if (!p->drivers || sailfish_slot_driver_compare
+ (p->drivers->driver, d) < 0) {
+ r->next = p->drivers;
+ p->drivers = r;
+ } else {
+ struct sailfish_slot_driver_reg *prev = p->drivers;
+
+ /* Keep the list sorted */
+ while (prev->next && sailfish_slot_driver_compare
+ (prev->next->driver, d) >= 0) {
+ prev = prev->next;
+ }
+
+ r->next = prev->next;
+ prev->next = r;
+ }
+ }
+
+ return r;
+}
+
+static void sailfish_slot_driver_free(struct sailfish_slot_driver_reg *r)
+{
+ if (r->init_id) {
+ g_source_remove(r->init_id);
+ }
+ if (r->manager) {
+ sailfish_slot_manager_free(r->manager);
+ r->manager = NULL;
+ }
+ r->next = NULL;
+ g_slice_free(struct sailfish_slot_driver_reg, r);
+}
+
+static void sailfish_manager_priv_unreg(struct sailfish_manager_priv *p,
+ struct sailfish_slot_driver_reg *r)
+{
+ if (r == p->drivers) {
+ p->drivers = r->next;
+ sailfish_slot_driver_free(r);
+ } else if (p->drivers) {
+ struct sailfish_slot_driver_reg *prev = p->drivers;
+
+ while (prev && prev->next != r) {
+ prev = prev->next;
+ }
+
+ if (prev) {
+ prev->next = r->next;
+ sailfish_slot_driver_free(r);
+ }
+ }
+}
+
+static gboolean sailfish_manager_priv_init(gpointer user_data)
+{
+ struct sailfish_manager_priv *p = user_data;
+
+ p->init_countdown--;
+ if (!p->init_countdown) {
+ p->init_id = 0;
+ DBG("done with registrations");
+ sailfish_manager_update_dbus_block(p);
+ return G_SOURCE_REMOVE;
+ } else {
+ /* Keep on waiting */
+ return G_SOURCE_CONTINUE;
+ }
+}
+
+static struct sailfish_manager_priv *sailfish_manager_priv_new()
+{
+ static const struct sailfish_manager_dbus_cb dbus_cb = {
+ .get_errors = sailfish_manager_get_errors,
+ .get_slot_errors = sailfish_manager_get_slot_errors,
+ .set_enabled_slots = sailfish_manager_set_enabled_slots,
+ .set_mms_imsi = sailfish_manager_set_mms_imsi,
+ .set_default_voice_imsi =
+ sailfish_manager_set_default_voice_imsi,
+ .set_default_data_imsi =
+ sailfish_manager_set_default_data_imsi
+ };
+
+ struct sailfish_manager_priv *p =
+ g_slice_new0(struct sailfish_manager_priv);
+
+ /* Load settings */
+ p->storage = storage_open(NULL, SF_STORE);
+ p->pub.default_voice_imsi = p->default_voice_imsi =
+ g_key_file_get_string(p->storage, SF_STORE_GROUP,
+ SF_STORE_DEFAULT_VOICE_SIM, NULL);
+ p->pub.default_data_imsi = p->default_data_imsi =
+ g_key_file_get_string(p->storage, SF_STORE_GROUP,
+ SF_STORE_DEFAULT_DATA_SIM, NULL);
+
+ DBG("Default voice sim is %s", p->default_voice_imsi ?
+ p->default_voice_imsi : "(auto)");
+ DBG("Default data sim is %s", p->default_data_imsi ?
+ p->default_data_imsi : "(auto)");
+
+ /* Delay the initialization until after all drivers get registered */
+ p->init_countdown = SF_INIT_IDLE_COUNT;
+ p->init_id = g_idle_add(sailfish_manager_priv_init, p);
+
+ /* And block all requests until that happens */
+ p->dbus = sailfish_manager_dbus_new(&p->pub, &dbus_cb);
+ sailfish_manager_dbus_set_block(p->dbus,
+ SAILFISH_MANAGER_DBUS_BLOCK_ALL);
+ return p;
+}
+
+static void sailfish_manager_priv_free(struct sailfish_manager_priv *p)
+{
+ if (p) {
+ while (p->drivers) {
+ sailfish_manager_priv_unreg(p, p->drivers);
+ }
+ if (p->init_id) {
+ g_source_remove(p->init_id);
+ }
+ if (p->errors) {
+ g_hash_table_destroy(p->errors);
+ }
+ sailfish_manager_dbus_free(p->dbus);
+ g_key_file_free(p->storage);
+ g_free(p->default_voice_imsi);
+ g_free(p->default_data_imsi);
+ g_free(p->mms_imsi);
+ g_free(p->slots);
+ g_slice_free(struct sailfish_manager_priv, p);
+ }
+}
+
+void sailfish_manager_foreach_slot_manager
+ (struct sailfish_slot_driver_reg *r,
+ sailfish_slot_manager_impl_cb_t cb, void *user_data)
+{
+ if (r && r->manager && cb) {
+ /* Yes, it's just one to one mapping but let's keep the API
+ * generic and allow many slot_manager instances. */
+ cb(r->manager->impl, user_data);
+ }
+}
+
+/* Global part (that requires access to sfos_manager_plugin variable) */
+
+static struct sailfish_manager_priv *sfos_manager_plugin;
+
+struct sailfish_slot_driver_reg *sailfish_slot_driver_register
+ (const struct sailfish_slot_driver *d)
+{
+ if (d) {
+ DBG("%s", d->name);
+
+ /* This function can be invoked before sailfish_manager_init */
+ if (!sfos_manager_plugin) {
+ sfos_manager_plugin = sailfish_manager_priv_new();
+ }
+
+ /* Only allow registrations at startup */
+ if (sfos_manager_plugin->init_countdown) {
+ return sailfish_manager_priv_reg_new
+ (sfos_manager_plugin, d);
+ } else {
+ ofono_error("Refusing to register driver %s", d->name);
+ }
+ }
+ return NULL;
+}
+
+void sailfish_slot_driver_unregister(struct sailfish_slot_driver_reg *r)
+{
+ if (r) {
+ DBG("%s", r->driver->name);
+ sailfish_manager_priv_unreg(sfos_manager_plugin, r);
+ }
+}
+
+static int sailfish_manager_init(void)
+{
+ DBG("");
+ if (!sfos_manager_plugin) {
+ sfos_manager_plugin = sailfish_manager_priv_new();
+ }
+ return 0;
+}
+
+static void sailfish_manager_exit(void)
+{
+ DBG("");
+ if (sfos_manager_plugin) {
+ sailfish_manager_priv_free(sfos_manager_plugin);
+ sfos_manager_plugin = NULL;
+ }
+}
+
+OFONO_PLUGIN_DEFINE(sailfish_manager, "Sailfish OS modem manager plugin",
+ VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
+ sailfish_manager_init, sailfish_manager_exit)
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_manager/sailfish_manager_dbus.c
^
|
@@ -0,0 +1,1174 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2015-2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sailfish_manager_dbus.h"
+
+#include <ofono/log.h>
+#include <ofono/dbus.h>
+
+#include <gutil_strv.h>
+#include <gutil_log.h>
+#include <gdbus.h>
+
+#include "ofono.h"
+
+typedef void (*sailfish_manager_dbus_append_fn)(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus);
+typedef gboolean (*sailfish_manager_dbus_slot_select_fn)
+ (const struct sailfish_slot *slot);
+typedef const char *(*sailfish_manager_dbus_slot_string_fn)
+ (const struct sailfish_slot *slot);
+
+struct sailfish_manager_dbus_request {
+ DBusMessage *msg;
+ sailfish_manager_dbus_append_fn fn;
+ enum sailfish_manager_dbus_block block;
+};
+
+struct sailfish_manager_dbus {
+ struct sailfish_manager *manager;
+ const struct sailfish_manager_dbus_cb *cb;
+ DBusConnection *conn;
+ enum sailfish_manager_dbus_block block_mask;
+ GSList *blocked_req;
+ guint mms_watch;
+};
+
+#define SF_DBUS_PATH "/"
+#define SF_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
+#define SF_DBUS_INTERFACE_VERSION (8)
+
+#define SF_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
+#define SF_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
+#define SF_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED "DefaultVoiceSimChanged"
+#define SF_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED "DefaultDataSimChanged"
+#define SF_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED "DefaultVoiceModemChanged"
+#define SF_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED "DefaultDataModemChanged"
+#define SF_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
+#define SF_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
+#define SF_DBUS_SIGNAL_READY_CHANGED "ReadyChanged"
+#define SF_DBUS_SIGNAL_MODEM_ERROR "ModemError"
+#define SF_DBUS_IMSI_AUTO "auto"
+
+#define SF_DBUS_ERROR_SIGNATURE "si"
+
+static gboolean sailfish_manager_dbus_enabled(const struct sailfish_slot *s)
+{
+ return s->enabled;
+}
+
+static gboolean sailfish_manager_dbus_present(const struct sailfish_slot *s)
+{
+ return s->sim_present;
+}
+
+static const char *sailfish_manager_dbus_imei(const struct sailfish_slot *s)
+{
+ return s->imei;
+}
+
+static const char *sailfish_manager_dbus_imeisv(const struct sailfish_slot *s)
+{
+ return s->imeisv;
+}
+
+static void sailfish_manager_dbus_append_path_array(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus,
+ sailfish_manager_dbus_slot_select_fn selector)
+{
+ DBusMessageIter array;
+ const sailfish_slot_ptr *ptr = dbus->manager->slots;
+
+ dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
+
+ if (ptr) {
+ while (*ptr) {
+ const struct sailfish_slot *slot = *ptr++;
+
+ if (!selector || selector(slot)) {
+ const char *path = slot->path;
+ dbus_message_iter_append_basic(&array,
+ DBUS_TYPE_OBJECT_PATH, &path);
+ }
+ }
+ }
+
+ dbus_message_iter_close_container(it, &array);
+}
+
+static void sailfish_manager_dbus_append_string_array(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus,
+ sailfish_manager_dbus_slot_string_fn fn)
+{
+ DBusMessageIter array;
+ const sailfish_slot_ptr *ptr = dbus->manager->slots;
+
+ dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array);
+
+ if (ptr) {
+ while (*ptr) {
+ const struct sailfish_slot *slot = *ptr++;
+ const char *str = fn(slot);
+
+ if (!str) str = "";
+ dbus_message_iter_append_basic(&array,
+ DBUS_TYPE_STRING, &str);
+ }
+ }
+
+ dbus_message_iter_close_container(it, &array);
+}
+
+static void sailfish_manager_dbus_append_boolean_array(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus,
+ sailfish_manager_dbus_slot_select_fn value)
+{
+ DBusMessageIter array;
+ const sailfish_slot_ptr *ptr = dbus->manager->slots;
+
+ dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BOOLEAN_AS_STRING, &array);
+
+ if (ptr) {
+ while (*ptr) {
+ const struct sailfish_slot *slot = *ptr++;
+ dbus_bool_t b = value(slot);
+
+ dbus_message_iter_append_basic(&array,
+ DBUS_TYPE_BOOLEAN, &b);
+ }
+ }
+
+ dbus_message_iter_close_container(it, &array);
+}
+
+static void sailfish_manager_dbus_append_boolean(DBusMessageIter *it,
+ dbus_bool_t b)
+{
+ dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &b);
+}
+
+static void sailfish_manager_dbus_append_string(DBusMessageIter *it,
+ const char *str)
+{
+ if (!str) str = "";
+ dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
+}
+
+static void sailfish_manager_dbus_append_imsi(DBusMessageIter *it,
+ const char *imsi)
+{
+ if (!imsi) imsi = SF_DBUS_IMSI_AUTO;
+ dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &imsi);
+}
+
+static void sailfish_manager_dbus_append_path(DBusMessageIter *it,
+ const char *path)
+{
+ if (!path) path = "";
+ /* It's DBUS_TYPE_STRING since DBUS_TYPE_OBJECT_PATH can't be empty */
+ dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &path);
+}
+
+static void sailfish_manager_dbus_message_append_path_array(DBusMessage *msg,
+ struct sailfish_manager_dbus *dbus,
+ sailfish_manager_dbus_slot_select_fn fn)
+{
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append(msg, &iter);
+ sailfish_manager_dbus_append_path_array(&iter, dbus, fn);
+}
+
+static void sailfish_manager_dbus_append_error_count(DBusMessageIter *it,
+ const char *id, dbus_uint32_t count)
+{
+ DBusMessageIter sub;
+
+ dbus_message_iter_open_container(it, DBUS_TYPE_STRUCT, NULL, &sub);
+ dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id);
+ dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &count);
+ dbus_message_iter_close_container(it, &sub);
+}
+
+static void sailfish_manager_dbus_append_error_counts(DBusMessageIter *it,
+ GHashTable *errors)
+{
+ DBusMessageIter counts;
+
+ dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
+ "(" SF_DBUS_ERROR_SIGNATURE ")", &counts);
+
+ if (errors && g_hash_table_size(errors)) {
+ gpointer key, value;
+ GHashTableIter iter;
+
+ g_hash_table_iter_init(&iter, errors);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ sailfish_manager_dbus_append_error_count(&counts,
+ key, GPOINTER_TO_INT(value));
+ }
+ }
+
+ dbus_message_iter_close_container(it, &counts);
+}
+
+static void sailfish_manager_dbus_append_modem_errors(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ DBusMessageIter slots;
+ const sailfish_slot_ptr *ptr = dbus->manager->slots;
+
+ dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
+ "a(" SF_DBUS_ERROR_SIGNATURE ")", &slots);
+
+ if (ptr) {
+ while (*ptr) {
+ const struct sailfish_slot *slot = *ptr++;
+
+ sailfish_manager_dbus_append_error_counts(&slots,
+ dbus->cb->get_slot_errors(slot));
+ }
+ }
+
+ dbus_message_iter_close_container(it, &slots);
+}
+
+static void sailfish_manager_dbus_append_errors(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_error_counts(it,
+ dbus->cb->get_errors(dbus->manager));
+}
+
+static void sailfish_manager_dbus_signal_path_array
+ (struct sailfish_manager_dbus *dbus, const char *name,
+ sailfish_manager_dbus_slot_select_fn fn)
+{
+ DBusMessage *signal = dbus_message_new_signal(SF_DBUS_PATH,
+ SF_DBUS_INTERFACE, name);
+
+ sailfish_manager_dbus_message_append_path_array(signal, dbus, fn);
+ g_dbus_send_message(dbus->conn, signal);
+}
+
+static inline void sailfish_manager_dbus_signal_imsi
+ (struct sailfish_manager_dbus *dbus,
+ const char *name, const char *imsi)
+{
+ if (!imsi) imsi = SF_DBUS_IMSI_AUTO;
+ g_dbus_emit_signal(dbus->conn, SF_DBUS_PATH, SF_DBUS_INTERFACE,
+ name, DBUS_TYPE_STRING, &imsi, DBUS_TYPE_INVALID);
+}
+
+static inline void sailfish_manager_dbus_signal_string
+ (struct sailfish_manager_dbus *dbus,
+ const char *name, const char *str)
+{
+ if (!str) str = "";
+ g_dbus_emit_signal(dbus->conn, SF_DBUS_PATH, SF_DBUS_INTERFACE,
+ name, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
+}
+
+static inline void sailfish_manager_dbus_signal_boolean
+ (struct sailfish_manager_dbus *dbus,
+ const char *name, dbus_bool_t value)
+{
+ g_dbus_emit_signal(dbus->conn, SF_DBUS_PATH, SF_DBUS_INTERFACE,
+ name, DBUS_TYPE_BOOLEAN, &value, DBUS_TYPE_INVALID);
+}
+
+void sailfish_manager_dbus_signal(struct sailfish_manager_dbus *dbus,
+ enum sailfish_manager_dbus_signal mask)
+{
+ if (dbus) {
+ struct sailfish_manager *manager = dbus->manager;
+
+ if (mask & SAILFISH_MANAGER_SIGNAL_VOICE_IMSI) {
+ sailfish_manager_dbus_signal_imsi(dbus,
+ SF_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
+ manager->default_voice_imsi);
+ }
+ if (mask & SAILFISH_MANAGER_SIGNAL_DATA_IMSI) {
+ sailfish_manager_dbus_signal_imsi(dbus,
+ SF_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
+ manager->default_data_imsi);
+ }
+ if (mask & SAILFISH_MANAGER_SIGNAL_MMS_IMSI) {
+ sailfish_manager_dbus_signal_string(dbus,
+ SF_DBUS_SIGNAL_MMS_SIM_CHANGED,
+ manager->mms_imsi);
+ }
+ if (mask & SAILFISH_MANAGER_SIGNAL_ENABLED_SLOTS) {
+ sailfish_manager_dbus_signal_path_array(dbus,
+ SF_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
+ sailfish_manager_dbus_enabled);
+ }
+ if (mask & SAILFISH_MANAGER_SIGNAL_VOICE_PATH) {
+ sailfish_manager_dbus_signal_string(dbus,
+ SF_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
+ manager->default_voice_path);
+ }
+ if (mask & SAILFISH_MANAGER_SIGNAL_DATA_PATH) {
+ sailfish_manager_dbus_signal_string(dbus,
+ SF_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
+ manager->default_data_path);
+ }
+ if (mask & SAILFISH_MANAGER_SIGNAL_MMS_PATH) {
+ sailfish_manager_dbus_signal_string(dbus,
+ SF_DBUS_SIGNAL_MMS_MODEM_CHANGED,
+ manager->mms_path);
+ }
+ if (mask & SAILFISH_MANAGER_SIGNAL_READY) {
+ sailfish_manager_dbus_signal_boolean(dbus,
+ SF_DBUS_SIGNAL_READY_CHANGED,
+ manager->ready);
+ }
+ }
+}
+
+void sailfish_manager_dbus_signal_sim(struct sailfish_manager_dbus *dbus,
+ int index, gboolean present)
+{
+ dbus_bool_t value = present;
+
+ g_dbus_emit_signal(dbus->conn, SF_DBUS_PATH, SF_DBUS_INTERFACE,
+ SF_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
+ DBUS_TYPE_INT32, &index,
+ DBUS_TYPE_BOOLEAN, &value,
+ DBUS_TYPE_INVALID);
+}
+
+void sailfish_manager_dbus_emit_modem_error(struct sailfish_manager_dbus *dbus,
+ const char *path, const char *id, const char *message)
+{
+ if (!message) message = "";
+ g_dbus_emit_signal(dbus->conn, SF_DBUS_PATH, SF_DBUS_INTERFACE,
+ SF_DBUS_SIGNAL_MODEM_ERROR,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &id,
+ DBUS_TYPE_STRING, &message,
+ DBUS_TYPE_INVALID);
+}
+
+void sailfish_manager_dbus_signal_modem_error
+ (struct sailfish_manager_dbus *dbus,
+ int index, const char *id, const char *msg)
+{
+ sailfish_manager_dbus_emit_modem_error(dbus,
+ dbus->manager->slots[index]->path, id, msg);
+}
+
+void sailfish_manager_dbus_signal_error(struct sailfish_manager_dbus *dbus,
+ const char *id, const char *message)
+{
+ sailfish_manager_dbus_emit_modem_error(dbus, "/", id, message);
+}
+
+static DBusMessage *sailfish_manager_dbus_reply(DBusMessage *msg,
+ struct sailfish_manager_dbus *dbus,
+ sailfish_manager_dbus_append_fn append)
+{
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append(reply, &iter);
+ append(&iter, dbus);
+ return reply;
+}
+
+static const char* sailfish_manager_dbus_block_name
+ (enum sailfish_manager_dbus_block block)
+{
+ return (block == SAILFISH_MANAGER_DBUS_BLOCK_IMEI) ? "IMEI" :
+ (block == SAILFISH_MANAGER_DBUS_BLOCK_MODEM) ? "MODEM" :
+ (block == SAILFISH_MANAGER_DBUS_BLOCK_ALL) ? "ALL" :
+ "???";
+}
+
+static void sailfish_manager_dbus_cancel_request(gpointer data)
+{
+ struct sailfish_manager_dbus_request *req = data;
+
+ DBG("cancelling %s request %p",
+ sailfish_manager_dbus_block_name(req->block), req);
+ __ofono_dbus_pending_reply(&req->msg, __ofono_error_canceled(req->msg));
+ g_slice_free(struct sailfish_manager_dbus_request, req);
+}
+
+void sailfish_manager_dbus_set_block(struct sailfish_manager_dbus *dbus,
+ enum sailfish_manager_dbus_block mask)
+{
+ enum sailfish_manager_dbus_block block = mask & ~dbus->block_mask;
+ enum sailfish_manager_dbus_block unblock = dbus->block_mask & ~mask;
+ dbus->block_mask = mask;
+ if (block) {
+ DBG("blocking %s requests",
+ sailfish_manager_dbus_block_name(block));
+ }
+ if (unblock) {
+ GSList *link = dbus->blocked_req, *prev = NULL;
+
+ DBG("unblocking %s requests",
+ sailfish_manager_dbus_block_name(unblock));
+ while (link) {
+ struct sailfish_manager_dbus_request *req = link->data;
+ GSList *next = link->next;
+
+ if (req->block & dbus->block_mask) {
+ prev = link;
+ } else {
+ if (prev) {
+ prev->next = next;
+ } else {
+ dbus->blocked_req = next;
+ }
+ link->next = NULL;
+ __ofono_dbus_pending_reply(&req->msg,
+ sailfish_manager_dbus_reply(req->msg,
+ dbus, req->fn));
+ g_slice_free1(sizeof(*req), req);
+ g_slist_free1(link);
+ }
+ link = next;
+ }
+ }
+}
+
+static DBusMessage *sailfish_manager_dbus_reply_or_block(DBusMessage *msg,
+ struct sailfish_manager_dbus *dbus,
+ sailfish_manager_dbus_append_fn fn,
+ enum sailfish_manager_dbus_block block)
+{
+ if (dbus->block_mask & block) {
+ struct sailfish_manager_dbus_request *req =
+ g_slice_new(struct sailfish_manager_dbus_request);
+
+ DBG("blocking %s request %s %p",
+ sailfish_manager_dbus_block_name(block),
+ dbus_message_get_member(msg), req);
+ req->msg = dbus_message_ref(msg);
+ req->fn = fn;
+ req->block = block;
+ dbus->blocked_req = g_slist_append(dbus->blocked_req, req);
+ return NULL;
+ } else {
+ return sailfish_manager_dbus_reply(msg, dbus, fn);
+ }
+}
+
+static DBusMessage *sailfish_manager_dbus_modem_reply(DBusMessage *msg,
+ struct sailfish_manager_dbus *dbus,
+ sailfish_manager_dbus_append_fn fn)
+{
+ return sailfish_manager_dbus_reply_or_block(msg, dbus, fn,
+ SAILFISH_MANAGER_DBUS_BLOCK_MODEM);
+}
+
+static DBusMessage *sailfish_manager_dbus_imei_reply(DBusMessage *msg,
+ struct sailfish_manager_dbus *dbus,
+ sailfish_manager_dbus_append_fn fn)
+{
+ return sailfish_manager_dbus_reply_or_block(msg, dbus, fn,
+ SAILFISH_MANAGER_DBUS_BLOCK_IMEI);
+}
+
+static void sailfish_manager_dbus_append_version(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ dbus_int32_t version = SF_DBUS_INTERFACE_VERSION;
+
+ dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
+}
+
+static void sailfish_manager_dbus_append_available_modems(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_path_array(it, dbus, NULL);
+}
+
+static void sailfish_manager_dbus_append_enabled_modems(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_path_array(it, dbus,
+ sailfish_manager_dbus_enabled);
+}
+
+static void sailfish_manager_dbus_append_present_sims(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_boolean_array(it, dbus,
+ sailfish_manager_dbus_present);
+}
+
+static void sailfish_manager_dbus_append_imei_array(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_string_array(it, dbus,
+ sailfish_manager_dbus_imei);
+}
+
+static void sailfish_manager_dbus_append_imeisv_array(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_string_array(it, dbus,
+ sailfish_manager_dbus_imeisv);
+}
+
+static void sailfish_manager_dbus_append_all(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ struct sailfish_manager *manager = dbus->manager;
+
+ sailfish_manager_dbus_append_version(it, dbus);
+ sailfish_manager_dbus_append_available_modems(it, dbus);
+ sailfish_manager_dbus_append_enabled_modems(it, dbus);
+ sailfish_manager_dbus_append_imsi(it, manager->default_data_imsi);
+ sailfish_manager_dbus_append_imsi(it, manager->default_voice_imsi);
+ sailfish_manager_dbus_append_path(it, manager->default_data_path);
+ sailfish_manager_dbus_append_path(it, manager->default_voice_path);
+}
+
+static void sailfish_manager_dbus_append_all2(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_all(it, dbus);
+ sailfish_manager_dbus_append_present_sims(it, dbus);
+}
+
+static void sailfish_manager_dbus_append_all3(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_all2(it, dbus);
+ sailfish_manager_dbus_append_imei_array(it, dbus);
+}
+
+static void sailfish_manager_dbus_append_all4(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ struct sailfish_manager *manager = dbus->manager;
+
+ sailfish_manager_dbus_append_all3(it, dbus);
+ sailfish_manager_dbus_append_string(it, manager->mms_imsi);
+ sailfish_manager_dbus_append_path(it, manager->mms_path);
+}
+
+static void sailfish_manager_dbus_append_all5(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_all4(it, dbus);
+ sailfish_manager_dbus_append_boolean(it, dbus->manager->ready);
+}
+
+static void sailfish_manager_dbus_append_all6(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_all5(it, dbus);
+ sailfish_manager_dbus_append_modem_errors(it, dbus);
+}
+
+static void sailfish_manager_dbus_append_all7(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_all6(it, dbus);
+ sailfish_manager_dbus_append_imeisv_array(it, dbus);
+}
+
+static void sailfish_manager_dbus_append_all8(DBusMessageIter *it,
+ struct sailfish_manager_dbus *dbus)
+{
+ sailfish_manager_dbus_append_all7(it, dbus);
+ sailfish_manager_dbus_append_errors(it, dbus);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_all(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_modem_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_all);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_all2(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_modem_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_all2);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_all3(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_imei_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_all3);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_all4(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_imei_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_all4);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_all5(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_imei_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_all5);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_all6(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_imei_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_all6);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_all7(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_imei_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_all7);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_all8(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_imei_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_all8);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_interface_version
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_version);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_available_modems
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_modem_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_available_modems);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_enabled_modems
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_modem_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_enabled_modems);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_present_sims
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_imei_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_present_sims);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_imei(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_imei_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_imei_array);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_imeisv(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_imei_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_imeisv_array);
+}
+
+static DBusMessage *sailfish_manager_dbus_reply_with_string(DBusMessage *msg,
+ const char *str)
+{
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append(reply, &iter);
+ sailfish_manager_dbus_append_string(&iter, str);
+ return reply;
+}
+
+static DBusMessage *sailfish_manager_dbus_reply_with_imsi(DBusMessage *msg,
+ const char *imsi)
+{
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append(reply, &iter);
+ sailfish_manager_dbus_append_imsi(&iter, imsi);
+ return reply;
+}
+
+static DBusMessage *sailfish_manager_dbus_get_default_data_sim
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+
+ return sailfish_manager_dbus_reply_with_imsi(msg,
+ dbus->manager->default_data_imsi);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_default_voice_sim
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+
+ return sailfish_manager_dbus_reply_with_imsi(msg,
+ dbus->manager->default_voice_imsi);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_mms_sim(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+
+ return sailfish_manager_dbus_reply_with_string(msg,
+ dbus->manager->mms_imsi);
+}
+
+static DBusMessage *sailfish_manager_dbus_reply_with_path(DBusMessage *msg,
+ const char *path)
+{
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append(reply, &iter);
+ sailfish_manager_dbus_append_path(&iter, path);
+ return reply;
+}
+
+static DBusMessage *sailfish_manager_dbus_get_default_data_modem
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+
+ return sailfish_manager_dbus_reply_with_path(msg,
+ dbus->manager->default_data_path);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_default_voice_modem
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+
+ return sailfish_manager_dbus_reply_with_path(msg,
+ dbus->manager->default_voice_path);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_mms_modem(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+
+ return sailfish_manager_dbus_reply_with_path(msg,
+ dbus->manager->mms_path);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_ready(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ DBusMessageIter it;
+
+ dbus_message_iter_init_append(reply, &it);
+ sailfish_manager_dbus_append_boolean(&it, dbus->manager->ready);
+ return reply;
+}
+
+static DBusMessage *sailfish_manager_dbus_get_modem_errors
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_modem_errors);
+}
+
+static DBusMessage *sailfish_manager_dbus_get_errors(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return sailfish_manager_dbus_reply(msg,
+ (struct sailfish_manager_dbus *)data,
+ sailfish_manager_dbus_append_errors);
+}
+
+static DBusMessage *sailfish_manager_dbus_set_enabled_modems
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+ DBusMessageIter iter;
+
+ dbus_message_iter_init(msg, &iter);
+ if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
+ char **paths = NULL;
+ DBusMessageIter array;
+
+ dbus_message_iter_recurse(&iter, &array);
+ while (dbus_message_iter_get_arg_type(&array) ==
+ DBUS_TYPE_OBJECT_PATH) {
+ DBusBasicValue value;
+
+ dbus_message_iter_get_basic(&array, &value);
+ paths = gutil_strv_add(paths, value.str);
+ dbus_message_iter_next(&array);
+ }
+
+ dbus->cb->set_enabled_slots(dbus->manager, paths);
+ g_strfreev(paths);
+ return dbus_message_new_method_return(msg);
+ } else {
+ return __ofono_error_invalid_args(msg);
+ }
+}
+
+static DBusMessage *sailfish_manager_dbus_set_imsi
+ (struct sailfish_manager_dbus *dbus, DBusMessage *msg,
+ void (*apply)(struct sailfish_manager *manager, const char *imsi))
+{
+ DBusMessageIter iter;
+
+ dbus_message_iter_init(msg, &iter);
+ if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
+ DBusBasicValue value;
+ const char *imsi;
+
+ dbus_message_iter_get_basic(&iter, &value);
+ imsi = value.str;
+ if (!g_strcmp0(imsi, SF_DBUS_IMSI_AUTO)) imsi = NULL;
+ apply(dbus->manager, imsi);
+ return dbus_message_new_method_return(msg);
+ } else {
+ return __ofono_error_invalid_args(msg);
+ }
+}
+
+static DBusMessage *sailfish_manager_dbus_set_default_voice_sim
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+
+ GASSERT(conn == dbus->conn);
+ return sailfish_manager_dbus_set_imsi(dbus, msg,
+ dbus->cb->set_default_voice_imsi);
+}
+
+static DBusMessage *sailfish_manager_dbus_set_default_data_sim
+ (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+
+ GASSERT(conn == dbus->conn);
+ return sailfish_manager_dbus_set_imsi(dbus, msg,
+ dbus->cb->set_default_data_imsi);
+}
+
+static void sailfish_manager_dbus_mms_disconnect(DBusConnection *conn,
+ void *data)
+{
+ struct sailfish_manager_dbus *dbus = data;
+
+ dbus->mms_watch = 0;
+ if (dbus->manager->mms_imsi) {
+ DBG("MMS client is gone");
+ dbus->cb->set_mms_imsi(dbus->manager, NULL);
+ }
+}
+
+static DBusMessage *sailfish_manager_dbus_set_mms_sim(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter;
+ struct sailfish_manager_dbus *dbus = data;
+
+ GASSERT(conn == dbus->conn);
+ dbus_message_iter_init(msg, &iter);
+ if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
+ struct sailfish_manager *manager = dbus->manager;
+ DBusBasicValue value;
+ const char *imsi;
+
+ dbus_message_iter_get_basic(&iter, &value);
+ imsi = value.str;
+
+ /*
+ * MMS IMSI is not persistent and has to be eventually
+ * reset by the client or cleaned up if the client
+ * unexpectedly disappears.
+ */
+ if (dbus->cb->set_mms_imsi(manager, imsi)) {
+
+ /*
+ * Clear the previous MMS owner
+ */
+ if (dbus->mms_watch) {
+ g_dbus_remove_watch(dbus->conn,
+ dbus->mms_watch);
+ dbus->mms_watch = 0;
+ }
+
+ if (manager->mms_imsi && manager->mms_imsi[0]) {
+ /*
+ * This client becomes the owner
+ */
+ const char* sender =
+ dbus_message_get_sender(msg);
+
+ DBG("Owner: %s", sender);
+ dbus->mms_watch = g_dbus_add_disconnect_watch
+ (dbus->conn, sender,
+ sailfish_manager_dbus_mms_disconnect,
+ dbus, NULL);
+ }
+
+ return sailfish_manager_dbus_reply_with_string(msg,
+ manager->mms_path);
+ } else {
+ return __ofono_error_not_available(msg);
+ }
+ } else {
+ return __ofono_error_invalid_args(msg);
+ }
+}
+
+/*
+ * The client can call GetInterfaceVersion followed by the appropriate
+ * GetAllx call to get all settings in two steps. Alternatively, it can
+ * call GetAll followed by GetAllx based on the interface version returned
+ * by GetAll. In either case, two D-Bus calls are required, unless the
+ * client is willing to make the assumption about the ofono version it's
+ * talking to.
+ */
+
+#define SF_DBUS_VERSION_ARG {"version", "i"}
+#define SF_DBUS_AVAILABLE_MODEMS_ARG {"availableModems", "ao"}
+#define SF_DBUS_ENABLED_MODEMS_ARG {"enabledModems", "ao" }
+#define SF_DBUS_DEFAULT_DATA_SIM_ARG {"defaultDataSim", "s" }
+#define SF_DBUS_DEFAULT_VOICE_SIM_ARG {"defaultVoiceSim", "s" }
+#define SF_DBUS_DEFAULT_DATA_MODEM_ARG {"defaultDataModem", "s" }
+#define SF_DBUS_DEFAULT_VOICE_MODEM_ARG {"defaultVoiceModem" , "s"}
+#define SF_DBUS_PRESENT_SIMS_ARG {"presentSims" , "ab"}
+#define SF_DBUS_IMEI_ARG {"imei" , "as"}
+#define SF_DBUS_MMS_SIM_ARG {"mmsSim", "s"}
+#define SF_DBUS_MMS_MODEM_ARG {"mmsModem" , "s"}
+#define SF_DBUS_READY_ARG {"ready" , "b"}
+#define SF_DBUS_MODEM_ERRORS_ARG {"modemErrors" , \
+ "aa(" SF_DBUS_ERROR_SIGNATURE ")"}
+#define SF_DBUS_IMEISV_ARG {"imeisv" , "as"}
+#define SF_DBUS_ERRORS_ARG {"errors" , \
+ "a(" SF_DBUS_ERROR_SIGNATURE ")"}
+#define SF_DBUS_GET_ALL_ARGS \
+ SF_DBUS_VERSION_ARG, \
+ SF_DBUS_AVAILABLE_MODEMS_ARG, \
+ SF_DBUS_ENABLED_MODEMS_ARG, \
+ SF_DBUS_DEFAULT_DATA_SIM_ARG, \
+ SF_DBUS_DEFAULT_VOICE_SIM_ARG, \
+ SF_DBUS_DEFAULT_DATA_MODEM_ARG, \
+ SF_DBUS_DEFAULT_VOICE_MODEM_ARG
+#define SF_DBUS_GET_ALL2_ARGS \
+ SF_DBUS_GET_ALL_ARGS, \
+ SF_DBUS_PRESENT_SIMS_ARG
+#define SF_DBUS_GET_ALL3_ARGS \
+ SF_DBUS_GET_ALL2_ARGS, \
+ SF_DBUS_IMEI_ARG
+#define SF_DBUS_GET_ALL4_ARGS \
+ SF_DBUS_GET_ALL3_ARGS, \
+ SF_DBUS_MMS_SIM_ARG, \
+ SF_DBUS_MMS_MODEM_ARG
+#define SF_DBUS_GET_ALL5_ARGS \
+ SF_DBUS_GET_ALL4_ARGS, \
+ SF_DBUS_READY_ARG
+#define SF_DBUS_GET_ALL6_ARGS \
+ SF_DBUS_GET_ALL5_ARGS, \
+ SF_DBUS_MODEM_ERRORS_ARG
+#define SF_DBUS_GET_ALL7_ARGS \
+ SF_DBUS_GET_ALL6_ARGS, \
+ SF_DBUS_IMEISV_ARG
+#define SF_DBUS_GET_ALL8_ARGS \
+ SF_DBUS_GET_ALL7_ARGS, \
+ SF_DBUS_ERRORS_ARG
+static const GDBusMethodTable sailfish_manager_dbus_methods[] = {
+ { GDBUS_ASYNC_METHOD("GetAll",
+ NULL, GDBUS_ARGS(SF_DBUS_GET_ALL_ARGS),
+ sailfish_manager_dbus_get_all) },
+ { GDBUS_ASYNC_METHOD("GetAll2",
+ NULL, GDBUS_ARGS(SF_DBUS_GET_ALL2_ARGS),
+ sailfish_manager_dbus_get_all2) },
+ { GDBUS_ASYNC_METHOD("GetAll3",
+ NULL, GDBUS_ARGS(SF_DBUS_GET_ALL3_ARGS),
+ sailfish_manager_dbus_get_all3) },
+ { GDBUS_ASYNC_METHOD("GetAll4",
+ NULL, GDBUS_ARGS(SF_DBUS_GET_ALL4_ARGS),
+ sailfish_manager_dbus_get_all4) },
+ { GDBUS_ASYNC_METHOD("GetAll5",
+ NULL, GDBUS_ARGS(SF_DBUS_GET_ALL5_ARGS),
+ sailfish_manager_dbus_get_all5) },
+ { GDBUS_ASYNC_METHOD("GetAll6",
+ NULL, GDBUS_ARGS(SF_DBUS_GET_ALL6_ARGS),
+ sailfish_manager_dbus_get_all6) },
+ { GDBUS_ASYNC_METHOD("GetAll7",
+ NULL, GDBUS_ARGS(SF_DBUS_GET_ALL7_ARGS),
+ sailfish_manager_dbus_get_all7) },
+ { GDBUS_ASYNC_METHOD("GetAll8",
+ NULL, GDBUS_ARGS(SF_DBUS_GET_ALL8_ARGS),
+ sailfish_manager_dbus_get_all8) },
+ { GDBUS_ASYNC_METHOD("GetInterfaceVersion",
+ NULL, GDBUS_ARGS(SF_DBUS_VERSION_ARG),
+ sailfish_manager_dbus_get_interface_version) },
+ { GDBUS_ASYNC_METHOD("GetAvailableModems",
+ NULL, GDBUS_ARGS(SF_DBUS_AVAILABLE_MODEMS_ARG),
+ sailfish_manager_dbus_get_available_modems) },
+ { GDBUS_ASYNC_METHOD("GetEnabledModems",
+ NULL, GDBUS_ARGS(SF_DBUS_ENABLED_MODEMS_ARG),
+ sailfish_manager_dbus_get_enabled_modems) },
+ { GDBUS_ASYNC_METHOD("GetPresentSims",
+ NULL, GDBUS_ARGS(SF_DBUS_PRESENT_SIMS_ARG),
+ sailfish_manager_dbus_get_present_sims) },
+ { GDBUS_ASYNC_METHOD("GetIMEI",
+ NULL, GDBUS_ARGS(SF_DBUS_IMEI_ARG),
+ sailfish_manager_dbus_get_imei) },
+ { GDBUS_ASYNC_METHOD("GetIMEISV",
+ NULL, GDBUS_ARGS(SF_DBUS_IMEISV_ARG),
+ sailfish_manager_dbus_get_imeisv) },
+ { GDBUS_ASYNC_METHOD("GetDefaultDataSim",
+ NULL, GDBUS_ARGS(SF_DBUS_DEFAULT_DATA_SIM_ARG),
+ sailfish_manager_dbus_get_default_data_sim) },
+ { GDBUS_ASYNC_METHOD("GetDefaultVoiceSim",
+ NULL, GDBUS_ARGS(SF_DBUS_DEFAULT_VOICE_SIM_ARG),
+ sailfish_manager_dbus_get_default_voice_sim) },
+ { GDBUS_ASYNC_METHOD("GetMmsSim",
+ NULL, GDBUS_ARGS(SF_DBUS_MMS_SIM_ARG),
+ sailfish_manager_dbus_get_mms_sim) },
+ { GDBUS_ASYNC_METHOD("GetDefaultDataModem",
+ NULL, GDBUS_ARGS(SF_DBUS_DEFAULT_DATA_MODEM_ARG),
+ sailfish_manager_dbus_get_default_data_modem) },
+ { GDBUS_ASYNC_METHOD("GetDefaultVoiceModem",
+ NULL, GDBUS_ARGS(SF_DBUS_DEFAULT_VOICE_MODEM_ARG),
+ sailfish_manager_dbus_get_default_voice_modem) },
+ { GDBUS_ASYNC_METHOD("GetMmsModem",
+ NULL, GDBUS_ARGS(SF_DBUS_MMS_MODEM_ARG),
+ sailfish_manager_dbus_get_mms_modem) },
+ { GDBUS_ASYNC_METHOD("GetReady",
+ NULL, GDBUS_ARGS(SF_DBUS_READY_ARG),
+ sailfish_manager_dbus_get_ready) },
+ { GDBUS_ASYNC_METHOD("GetModemErrors",
+ NULL, GDBUS_ARGS(SF_DBUS_MODEM_ERRORS_ARG),
+ sailfish_manager_dbus_get_modem_errors) },
+ { GDBUS_ASYNC_METHOD("GetErrors",
+ NULL, GDBUS_ARGS(SF_DBUS_ERRORS_ARG),
+ sailfish_manager_dbus_get_errors) },
+ { GDBUS_ASYNC_METHOD("SetEnabledModems",
+ GDBUS_ARGS({ "modems", "ao" }), NULL,
+ sailfish_manager_dbus_set_enabled_modems) },
+ { GDBUS_ASYNC_METHOD("SetDefaultDataSim",
+ GDBUS_ARGS({ "imsi", "s" }), NULL,
+ sailfish_manager_dbus_set_default_data_sim) },
+ { GDBUS_ASYNC_METHOD("SetDefaultVoiceSim",
+ GDBUS_ARGS({ "imsi", "s" }), NULL,
+ sailfish_manager_dbus_set_default_voice_sim) },
+ { GDBUS_ASYNC_METHOD("SetMmsSim",
+ GDBUS_ARGS({ "imsi", "s" }), NULL,
+ sailfish_manager_dbus_set_mms_sim) },
+ { }
+};
+
+static const GDBusSignalTable sailfish_manager_dbus_signals[] = {
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
+ GDBUS_ARGS(SF_DBUS_ENABLED_MODEMS_ARG)) },
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
+ GDBUS_ARGS({"index", "i" },
+ {"present" , "b"})) },
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
+ GDBUS_ARGS(SF_DBUS_DEFAULT_DATA_SIM_ARG)) },
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
+ GDBUS_ARGS(SF_DBUS_DEFAULT_VOICE_SIM_ARG)) },
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
+ GDBUS_ARGS(SF_DBUS_DEFAULT_DATA_MODEM_ARG)) },
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
+ GDBUS_ARGS(SF_DBUS_DEFAULT_VOICE_MODEM_ARG)) },
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_MMS_SIM_CHANGED,
+ GDBUS_ARGS(SF_DBUS_MMS_SIM_ARG)) },
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_MMS_MODEM_CHANGED,
+ GDBUS_ARGS(SF_DBUS_MMS_MODEM_ARG)) },
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_READY_CHANGED,
+ GDBUS_ARGS(SF_DBUS_READY_ARG)) },
+ { GDBUS_SIGNAL(SF_DBUS_SIGNAL_MODEM_ERROR,
+ GDBUS_ARGS({"path","o"},
+ {"error_id", "s"},
+ {"message", "s"})) },
+ { }
+};
+
+struct sailfish_manager_dbus *sailfish_manager_dbus_new
+ (struct sailfish_manager *manager,
+ const struct sailfish_manager_dbus_cb *cb)
+{
+ struct sailfish_manager_dbus *dbus =
+ g_slice_new0(struct sailfish_manager_dbus);
+
+ dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
+ dbus->manager = manager;
+ dbus->cb = cb;
+ if (g_dbus_register_interface(dbus->conn, SF_DBUS_PATH,
+ SF_DBUS_INTERFACE, sailfish_manager_dbus_methods,
+ sailfish_manager_dbus_signals, NULL, dbus, NULL)) {
+ return dbus;
+ } else {
+ ofono_error("RIL D-Bus register failed");
+ sailfish_manager_dbus_free(dbus);
+ return NULL;
+ }
+}
+
+void sailfish_manager_dbus_free(struct sailfish_manager_dbus *dbus)
+{
+ if (dbus) {
+ if (dbus->mms_watch) {
+ g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
+ }
+
+ g_slist_free_full(dbus->blocked_req,
+ sailfish_manager_dbus_cancel_request);
+ g_dbus_unregister_interface(dbus->conn, SF_DBUS_PATH,
+ SF_DBUS_INTERFACE);
+ dbus_connection_unref(dbus->conn);
+ g_slice_free(struct sailfish_manager_dbus, dbus);
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_manager/sailfish_manager_dbus.h
^
|
@@ -0,0 +1,77 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2016-2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SAILFISH_MANAGER_DBUS_H
+#define SAILFISH_MANAGER_DBUS_H
+
+#include <sailfish_manager.h>
+
+struct sailfish_manager_dbus;
+
+enum sailfish_manager_dbus_block {
+ SAILFISH_MANAGER_DBUS_BLOCK_NONE = 0,
+ SAILFISH_MANAGER_DBUS_BLOCK_MODEM = 0x01,
+ SAILFISH_MANAGER_DBUS_BLOCK_IMEI = 0x02,
+ SAILFISH_MANAGER_DBUS_BLOCK_ALL = 0x03
+};
+
+enum sailfish_manager_dbus_signal {
+ SAILFISH_MANAGER_SIGNAL_NONE = 0,
+ SAILFISH_MANAGER_SIGNAL_VOICE_IMSI = 0x01,
+ SAILFISH_MANAGER_SIGNAL_DATA_IMSI = 0x02,
+ SAILFISH_MANAGER_SIGNAL_VOICE_PATH = 0x04,
+ SAILFISH_MANAGER_SIGNAL_DATA_PATH = 0x08,
+ SAILFISH_MANAGER_SIGNAL_ENABLED_SLOTS = 0x10,
+ SAILFISH_MANAGER_SIGNAL_MMS_IMSI = 0x20,
+ SAILFISH_MANAGER_SIGNAL_MMS_PATH = 0x40,
+ SAILFISH_MANAGER_SIGNAL_READY = 0x80
+};
+
+/* Functionality provided by sailfish_manager to sailfish_manager_dbus */
+struct sailfish_manager_dbus_cb {
+ GHashTable *(*get_errors)(struct sailfish_manager *m);
+ GHashTable *(*get_slot_errors)(const struct sailfish_slot *s);
+ void (*set_enabled_slots)(struct sailfish_manager *m, char **slots);
+ gboolean (*set_mms_imsi)(struct sailfish_manager *m, const char *imsi);
+ void (*set_default_voice_imsi)(struct sailfish_manager *m,
+ const char *imsi);
+ void (*set_default_data_imsi)(struct sailfish_manager *m,
+ const char *imsi);
+};
+
+struct sailfish_manager_dbus *sailfish_manager_dbus_new
+ (struct sailfish_manager *m,
+ const struct sailfish_manager_dbus_cb *cb);
+void sailfish_manager_dbus_free(struct sailfish_manager_dbus *d);
+void sailfish_manager_dbus_set_block(struct sailfish_manager_dbus *d,
+ enum sailfish_manager_dbus_block b);
+void sailfish_manager_dbus_signal(struct sailfish_manager_dbus *d,
+ enum sailfish_manager_dbus_signal m);
+void sailfish_manager_dbus_signal_sim(struct sailfish_manager_dbus *d,
+ int index, gboolean present);
+void sailfish_manager_dbus_signal_error(struct sailfish_manager_dbus *d,
+ const char *id, const char *message);
+void sailfish_manager_dbus_signal_modem_error(struct sailfish_manager_dbus *d,
+ int index, const char *id, const char *msg);
+
+#endif /* SAILFISH_MANAGER_DBUS_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_manager/sailfish_sim_info.c
^
|
@@ -0,0 +1,614 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "sailfish_sim_info.h"
+#include "sailfish_watch.h"
+
+#include <gutil_misc.h>
+#include <gutil_log.h>
+
+#include "ofono.h"
+#include "common.h"
+#include "storage.h"
+
+#define SAILFISH_SIM_INFO_STORE "cache"
+#define SAILFISH_SIM_INFO_STORE_GROUP "sim"
+#define SAILFISH_SIM_INFO_STORE_SPN "spn"
+
+/* ICCID -> IMSI map */
+#define SAILFISH_SIM_ICCID_MAP "iccidmap"
+#define SAILFISH_SIM_ICCID_MAP_IMSI "imsi"
+
+#define DEFAULT_SPN_BUFSIZE 8
+G_STATIC_ASSERT(DEFAULT_SPN_BUFSIZE >= \
+ OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1);
+
+typedef GObjectClass SailfishSimInfoClass;
+typedef struct sailfish_sim_info SailfishSimInfo;
+
+enum sailfish_watch_events {
+ WATCH_EVENT_SIM,
+ WATCH_EVENT_SIM_STATE,
+ WATCH_EVENT_ICCID,
+ WATCH_EVENT_IMSI,
+ WATCH_EVENT_SPN,
+ WATCH_EVENT_NETREG,
+ WATCH_EVENT_COUNT
+};
+
+struct sailfish_sim_info_priv {
+ struct sailfish_watch *watch;
+ struct ofono_netreg *netreg;
+ char *iccid;
+ char *imsi;
+ char *cached_spn;
+ char *sim_spn;
+ char *public_spn;
+ char default_spn[DEFAULT_SPN_BUFSIZE];
+ gulong watch_event_id[WATCH_EVENT_COUNT];
+ guint netreg_status_watch_id;
+ gboolean update_imsi_cache;
+ gboolean update_iccid_map;
+};
+
+enum sailfish_sim_info_signal {
+ SIGNAL_ICCID_CHANGED,
+ SIGNAL_IMSI_CHANGED,
+ SIGNAL_SPN_CHANGED,
+ SIGNAL_COUNT
+};
+
+#define SIGNAL_ICCID_CHANGED_NAME "sailfish-siminfo-iccid-changed"
+#define SIGNAL_IMSI_CHANGED_NAME "sailfish-siminfo-imsi-changed"
+#define SIGNAL_SPN_CHANGED_NAME "sailfish-siminfo-spn-changed"
+
+static guint sailfish_sim_info_signals[SIGNAL_COUNT] = { 0 };
+
+G_DEFINE_TYPE(SailfishSimInfo, sailfish_sim_info, G_TYPE_OBJECT)
+#define SAILFISH_SIMINFO_TYPE (sailfish_sim_info_get_type())
+#define SAILFISH_SIMINFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
+ SAILFISH_SIMINFO_TYPE, SailfishSimInfo))
+
+#define NEW_SIGNAL(klass,name) \
+ sailfish_sim_info_signals[SIGNAL_##name##_CHANGED] = \
+ g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
+ G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
+ 0, NULL, NULL, NULL, G_TYPE_NONE, 0)
+
+/* Skip the leading slash from the modem path: */
+#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
+
+static void sailfish_sim_info_signal_emit(struct sailfish_sim_info *self,
+ enum sailfish_sim_info_signal id)
+{
+ g_signal_emit(self, sailfish_sim_info_signals[id], 0);
+}
+
+static void sailfish_sim_info_update_imsi_cache(struct sailfish_sim_info *self)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ if (priv->update_imsi_cache && priv->imsi && priv->imsi[0] &&
+ priv->cached_spn && priv->cached_spn[0]) {
+ gboolean save = FALSE;
+ const char *store = SAILFISH_SIM_INFO_STORE;
+ GKeyFile *cache = storage_open(priv->imsi, store);
+ char *spn = g_key_file_get_string(cache,
+ SAILFISH_SIM_INFO_STORE_GROUP,
+ SAILFISH_SIM_INFO_STORE_SPN, NULL);
+
+ if (g_strcmp0(priv->cached_spn, spn)) {
+ save = TRUE;
+ g_key_file_set_string(cache,
+ SAILFISH_SIM_INFO_STORE_GROUP,
+ SAILFISH_SIM_INFO_STORE_SPN,
+ priv->cached_spn);
+ }
+
+ /*
+ * Since we are most likely running on flash which
+ * supports a limited number of writes, don't overwrite
+ * the file unless something has actually changed.
+ */
+ if (save) {
+ DBG_(self, "updating " STORAGEDIR "/%s/%s",
+ priv->imsi, store);
+ storage_close(priv->imsi, store, cache, TRUE);
+ } else {
+ g_key_file_free(cache);
+ }
+
+ g_free(spn);
+ priv->update_imsi_cache = FALSE;
+ }
+}
+
+static void sailfish_sim_info_update_iccid_map(struct sailfish_sim_info *self)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ if (priv->update_iccid_map && priv->iccid && priv->iccid[0] &&
+ priv->imsi && priv->imsi[0]) {
+ const char *store = SAILFISH_SIM_ICCID_MAP;
+ GKeyFile *map = storage_open(NULL, store);
+ char *imsi = g_key_file_get_string(map,
+ SAILFISH_SIM_ICCID_MAP_IMSI, priv->iccid, NULL);
+
+ /*
+ * Since we are most likely running on flash which
+ * supports a limited number of writes, don't overwrite
+ * the file unless something has actually changed.
+ */
+ if (g_strcmp0(imsi, priv->imsi)) {
+ DBG_(self, "updating " STORAGEDIR "/%s", store);
+ g_key_file_set_string(map, SAILFISH_SIM_ICCID_MAP_IMSI,
+ priv->iccid, priv->imsi);
+ storage_close(NULL, store, map, TRUE);
+ } else {
+ g_key_file_free(map);
+ }
+
+ g_free(imsi);
+ priv->update_iccid_map = FALSE;
+ }
+}
+
+static void sailfish_sim_info_update_public_spn(struct sailfish_sim_info *self)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+ const char *spn = priv->sim_spn ? priv->sim_spn :
+ priv->cached_spn ? priv->cached_spn :
+ priv->default_spn;
+
+ if (g_strcmp0(priv->public_spn, spn)) {
+ g_free(priv->public_spn);
+ self->spn = priv->public_spn = g_strdup(spn);
+ sailfish_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
+ }
+}
+
+static void sailfish_sim_info_set_cached_spn(struct sailfish_sim_info *self,
+ const char *spn)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->cached_spn, spn)) {
+ g_free(priv->cached_spn);
+ if (spn) {
+ DBG_(self, "cached spn \"%s\"", spn);
+ priv->cached_spn = g_strdup(spn);
+ priv->update_imsi_cache = TRUE;
+ sailfish_sim_info_update_imsi_cache(self);
+ } else {
+ priv->cached_spn = NULL;
+ }
+ sailfish_sim_info_update_public_spn(self);
+ }
+}
+
+static void sailfish_sim_info_set_spn(struct sailfish_sim_info *self,
+ const char *spn)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->sim_spn, spn)) {
+ DBG_(self, "%s", spn);
+ g_free(priv->sim_spn);
+ priv->sim_spn = g_strdup(spn);
+ priv->update_imsi_cache = TRUE;
+ sailfish_sim_info_set_cached_spn(self, spn);
+ sailfish_sim_info_update_imsi_cache(self);
+ sailfish_sim_info_update_public_spn(self);
+ }
+}
+
+static void sailfish_sim_info_update_spn(struct sailfish_sim_info *self)
+{
+ struct sailfish_watch *watch = self->priv->watch;
+
+ if (watch->spn && watch->spn[0]) {
+ sailfish_sim_info_set_spn(self, watch->spn);
+ }
+}
+
+static void sailfish_sim_info_update_default_spn(struct sailfish_sim_info *self)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+ struct ofono_sim *sim = priv->watch->sim;
+ char buf[DEFAULT_SPN_BUFSIZE];
+ const char *mcc = NULL;
+ const char *mnc = NULL;
+
+ if (sim && ofono_sim_get_state(sim) == OFONO_SIM_STATE_READY) {
+ mcc = ofono_sim_get_mcc(sim);
+ mnc = ofono_sim_get_mnc(sim);
+ }
+
+ if (mcc && mnc) {
+ snprintf(buf, DEFAULT_SPN_BUFSIZE, "%s%s", mcc, mnc);
+ buf[DEFAULT_SPN_BUFSIZE - 1] = 0;
+ } else {
+ buf[0] = 0;
+ }
+
+ if (strcmp(buf, priv->default_spn)) {
+ strncpy(priv->default_spn, buf, DEFAULT_SPN_BUFSIZE);
+ DBG_(self, "default spn \"%s\"", priv->default_spn);
+ sailfish_sim_info_update_public_spn(self);
+ }
+}
+
+static void sailfish_sim_info_set_imsi(struct sailfish_sim_info *self,
+ const char *imsi)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->imsi, imsi)) {
+ DBG_(self, "%s", imsi);
+ g_free(priv->imsi);
+ self->imsi = priv->imsi = g_strdup(imsi);
+ priv->update_iccid_map = TRUE;
+ sailfish_sim_info_update_iccid_map(self);
+ sailfish_sim_info_update_imsi_cache(self);
+ sailfish_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
+ }
+}
+
+static void sailfish_sim_info_update_imsi(struct sailfish_sim_info *self)
+{
+ struct sailfish_watch *watch = self->priv->watch;
+
+ if (watch->imsi && watch->imsi[0]) {
+ sailfish_sim_info_set_imsi(self, watch->imsi);
+ }
+}
+
+static void sailfish_sim_info_network_check(struct sailfish_sim_info *self)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+ struct ofono_sim *sim = priv->watch->sim;
+ enum network_registration_status reg_status =
+ ofono_netreg_get_status(priv->netreg);
+
+ if (sim && ofono_sim_get_state(sim) == OFONO_SIM_STATE_READY &&
+ (reg_status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
+ reg_status == NETWORK_REGISTRATION_STATUS_ROAMING)) {
+ const char *sim_mcc = ofono_sim_get_mcc(sim);
+ const char *sim_mnc = ofono_sim_get_mnc(sim);
+ const char *net_mcc = ofono_netreg_get_mcc(priv->netreg);
+ const char *net_mnc = ofono_netreg_get_mnc(priv->netreg);
+ const char *name = ofono_netreg_get_name(priv->netreg);
+
+ if (sim_mcc && sim_mcc[0] && sim_mnc && sim_mnc[0] &&
+ net_mcc && net_mcc[0] && net_mnc && net_mnc[0] &&
+ name && name[0] && !strcmp(sim_mcc, net_mcc) &&
+ !strcmp(sim_mnc, net_mnc)) {
+
+ /*
+ * If EFspn is present then sim_spn should be set
+ * before we get registered with the network.
+ */
+ DBG_(self, "home network \"%s\"", name);
+ if (!priv->sim_spn) {
+ sailfish_sim_info_set_cached_spn(self, name);
+ }
+ }
+ }
+}
+
+static void sailfish_sim_info_load_cache(struct sailfish_sim_info *self)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ if (priv->iccid && priv->iccid[0]) {
+ GKeyFile *map = storage_open(NULL, SAILFISH_SIM_ICCID_MAP);
+ char *imsi = g_key_file_get_string(map,
+ SAILFISH_SIM_ICCID_MAP_IMSI, priv->iccid, NULL);
+ g_key_file_free(map);
+
+ if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
+ if (priv->imsi && priv->imsi[0]) {
+ /* Need to update ICCID -> IMSI map */
+ DBG_(self, "IMSI changed %s -> %s",
+ priv->imsi, imsi);
+ priv->update_imsi_cache = TRUE;
+ }
+ g_free(priv->imsi);
+ self->imsi = priv->imsi = imsi;
+ DBG_(self, "imsi[%s] = %s", priv->iccid, imsi);
+ sailfish_sim_info_update_iccid_map(self);
+ sailfish_sim_info_signal_emit(self,
+ SIGNAL_IMSI_CHANGED);
+ } else if (imsi) {
+ g_free(imsi);
+ } else {
+ DBG_(self, "no imsi for iccid %s", priv->iccid);
+ }
+ }
+
+ if (priv->imsi && priv->imsi[0]) {
+ GKeyFile *cache = storage_open(priv->imsi,
+ SAILFISH_SIM_INFO_STORE);
+ char *spn = g_key_file_get_string(cache,
+ SAILFISH_SIM_INFO_STORE_GROUP,
+ SAILFISH_SIM_INFO_STORE_SPN, NULL);
+ g_key_file_free(cache);
+
+ if (spn && spn[0] && g_strcmp0(priv->cached_spn, spn)) {
+ if (priv->cached_spn && priv->cached_spn[0]) {
+ /* Need to update the cache file */
+ DBG_(self, "spn changing %s -> %s",
+ priv->cached_spn, spn);
+ priv->update_imsi_cache = TRUE;
+ }
+ g_free(priv->cached_spn);
+ priv->cached_spn = spn;
+ DBG_(self, "spn[%s] = \"%s\"", priv->imsi, spn);
+ sailfish_sim_info_update_imsi_cache(self);
+ sailfish_sim_info_update_public_spn(self);
+ } else if (spn) {
+ g_free(spn);
+ } else {
+ DBG_(self, "no spn for imsi %s", priv->imsi);
+ }
+ }
+}
+
+static void sailfish_sim_info_set_iccid(struct sailfish_sim_info *self,
+ const char *iccid)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->iccid, iccid)) {
+ g_free(priv->iccid);
+ self->iccid = priv->iccid = g_strdup(iccid);
+ sailfish_sim_info_signal_emit(self, SIGNAL_ICCID_CHANGED);
+ if (iccid) {
+ sailfish_sim_info_load_cache(self);
+ } else {
+ if (priv->imsi) {
+ g_free(priv->imsi);
+ self->imsi = priv->imsi = NULL;
+ sailfish_sim_info_signal_emit(self,
+ SIGNAL_IMSI_CHANGED);
+ }
+ if (priv->sim_spn) {
+ g_free(priv->sim_spn);
+ priv->sim_spn = NULL;
+ sailfish_sim_info_set_cached_spn(self, NULL);
+ }
+ }
+ }
+}
+
+static void sailfish_sim_info_sim_watch_cb(struct sailfish_watch *watch,
+ void *data)
+{
+ struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
+ struct ofono_sim *sim = self->priv->watch->sim;
+
+ sailfish_sim_info_update_default_spn(self);
+ if (ofono_sim_get_state(sim) == OFONO_SIM_STATE_NOT_PRESENT) {
+ sailfish_sim_info_set_iccid(self, NULL);
+ }
+ sailfish_sim_info_network_check(self);
+}
+
+static void sailfish_sim_info_iccid_watch_cb(struct sailfish_watch *watch,
+ void *data)
+{
+ struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
+
+ DBG_(self, "%s", watch->iccid);
+ sailfish_sim_info_set_iccid(self, watch->iccid);
+}
+
+static void sailfish_sim_info_imsi_watch_cb(struct sailfish_watch *watch,
+ void *data)
+{
+ sailfish_sim_info_update_imsi(SAILFISH_SIMINFO(data));
+}
+
+static void sailfish_sim_info_spn_watch_cb(struct sailfish_watch *watch,
+ void *data)
+{
+ sailfish_sim_info_update_spn(SAILFISH_SIMINFO(data));
+}
+
+static void sailfish_sim_info_netreg_watch(int status, int lac, int ci,
+ int tech, const char *mcc, const char *mnc, void *data)
+{
+ sailfish_sim_info_network_check(SAILFISH_SIMINFO(data));
+}
+
+static void sailfish_sim_info_netreg_watch_done(void *data)
+{
+ struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ GASSERT(priv->netreg_status_watch_id);
+ priv->netreg_status_watch_id = 0;
+}
+
+static void sailfish_sim_info_set_netreg(struct sailfish_sim_info *self,
+ struct ofono_netreg *netreg)
+{
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ if (priv->netreg != netreg) {
+ if (netreg) {
+ DBG_(self, "netreg attached");
+ priv->netreg = netreg;
+ priv->netreg_status_watch_id =
+ __ofono_netreg_add_status_watch(netreg,
+ sailfish_sim_info_netreg_watch, self,
+ sailfish_sim_info_netreg_watch_done);
+ sailfish_sim_info_network_check(self);
+ } else if (priv->netreg) {
+ if (priv->netreg_status_watch_id) {
+ __ofono_netreg_remove_status_watch(priv->netreg,
+ priv->netreg_status_watch_id);
+ GASSERT(!priv->netreg_status_watch_id);
+ }
+ DBG_(self, "netreg detached");
+ priv->netreg = NULL;
+ }
+ }
+}
+
+static void sailfish_sim_info_netreg_changed(struct sailfish_watch *watch,
+ void *data)
+{
+ sailfish_sim_info_set_netreg(SAILFISH_SIMINFO(data), watch->netreg);
+}
+
+struct sailfish_sim_info *sailfish_sim_info_new(const char *path)
+{
+ struct sailfish_sim_info *self = NULL;
+
+ if (path) {
+ struct sailfish_watch *watch = sailfish_watch_new(path);
+ struct sailfish_sim_info_priv *priv;
+
+ self = g_object_new(SAILFISH_SIMINFO_TYPE, NULL);
+ priv = self->priv;
+ priv->watch = watch;
+ self->path = watch->path;
+ priv->watch_event_id[WATCH_EVENT_SIM] =
+ sailfish_watch_add_sim_changed_handler(watch,
+ sailfish_sim_info_sim_watch_cb, self);
+ priv->watch_event_id[WATCH_EVENT_SIM_STATE] =
+ sailfish_watch_add_sim_state_changed_handler(watch,
+ sailfish_sim_info_sim_watch_cb, self);
+ priv->watch_event_id[WATCH_EVENT_ICCID] =
+ sailfish_watch_add_iccid_changed_handler(watch,
+ sailfish_sim_info_iccid_watch_cb, self);
+ priv->watch_event_id[WATCH_EVENT_IMSI] =
+ sailfish_watch_add_imsi_changed_handler(watch,
+ sailfish_sim_info_imsi_watch_cb, self);
+ priv->watch_event_id[WATCH_EVENT_SPN] =
+ sailfish_watch_add_spn_changed_handler(watch,
+ sailfish_sim_info_spn_watch_cb, self);
+ priv->watch_event_id[WATCH_EVENT_NETREG] =
+ sailfish_watch_add_netreg_changed_handler(watch,
+ sailfish_sim_info_netreg_changed, self);
+ sailfish_sim_info_set_iccid(self, watch->iccid);
+ sailfish_sim_info_set_netreg(self, watch->netreg);
+ sailfish_sim_info_update_imsi(self);
+ sailfish_sim_info_update_spn(self);
+ sailfish_sim_info_network_check(self);
+ }
+ return self;
+}
+
+struct sailfish_sim_info *sailfish_sim_info_ref(struct sailfish_sim_info *self)
+{
+ if (self) {
+ g_object_ref(SAILFISH_SIMINFO(self));
+ return self;
+ } else {
+ return NULL;
+ }
+}
+
+void sailfish_sim_info_unref(struct sailfish_sim_info *self)
+{
+ if (self) {
+ g_object_unref(SAILFISH_SIMINFO(self));
+ }
+}
+
+void sailfish_sim_info_invalidate(struct sailfish_sim_info *self)
+{
+ if (self) {
+ sailfish_sim_info_set_iccid(self, NULL);
+ }
+}
+
+gulong sailfish_sim_info_add_iccid_changed_handler(struct sailfish_sim_info *s,
+ sailfish_sim_info_cb_t cb, void *arg)
+{
+ return (s && cb) ? g_signal_connect(s, SIGNAL_ICCID_CHANGED_NAME,
+ G_CALLBACK(cb), arg) : 0;
+}
+
+gulong sailfish_sim_info_add_imsi_changed_handler(struct sailfish_sim_info *s,
+ sailfish_sim_info_cb_t cb, void *arg)
+{
+ return (s && cb) ? g_signal_connect(s, SIGNAL_IMSI_CHANGED_NAME,
+ G_CALLBACK(cb), arg) : 0;
+}
+
+gulong sailfish_sim_info_add_spn_changed_handler(struct sailfish_sim_info *s,
+ sailfish_sim_info_cb_t cb, void *arg)
+{
+ return (s && cb) ? g_signal_connect(s, SIGNAL_SPN_CHANGED_NAME,
+ G_CALLBACK(cb), arg) : 0;
+}
+
+void sailfish_sim_info_remove_handler(struct sailfish_sim_info *s, gulong id)
+{
+ if (s && id) {
+ g_signal_handler_disconnect(s, id);
+ }
+}
+
+void sailfish_sim_info_remove_handlers(struct sailfish_sim_info *self,
+ gulong *ids, int count)
+{
+ gutil_disconnect_handlers(self, ids, count);
+}
+
+static void sailfish_sim_info_init(struct sailfish_sim_info *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SAILFISH_SIMINFO_TYPE,
+ struct sailfish_sim_info_priv);
+}
+
+static void sailfish_sim_info_finalize(GObject *object)
+{
+ struct sailfish_sim_info *self = SAILFISH_SIMINFO(object);
+ struct sailfish_sim_info_priv *priv = self->priv;
+
+ sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
+ sailfish_watch_unref(priv->watch);
+ g_free(priv->iccid);
+ g_free(priv->imsi);
+ g_free(priv->sim_spn);
+ g_free(priv->cached_spn);
+ g_free(priv->public_spn);
+ G_OBJECT_CLASS(sailfish_sim_info_parent_class)->finalize(object);
+}
+
+static void sailfish_sim_info_class_init(SailfishSimInfoClass *klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = sailfish_sim_info_finalize;
+ g_type_class_add_private(klass, sizeof(struct sailfish_sim_info_priv));
+ NEW_SIGNAL(klass, ICCID);
+ NEW_SIGNAL(klass, IMSI);
+ NEW_SIGNAL(klass, SPN);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_manager/sailfish_sim_info.h
^
|
@@ -0,0 +1,81 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SAILFISH_SIM_INFO_H
+#define SAILFISH_SIM_INFO_H
+
+#include <ofono/types.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+/*
+ * Note that iccid, imsi and spn provided by this class can be cached,
+ * i.e. become available before the pin code is entered and before those
+ * are known to the ofono core. That's the whole purpose of this thing.
+ *
+ * If you need to follow imsi known to the ofono core, you can use
+ * sailfish_sim_settings for that (or fight with ofono imsi watchers
+ * directly).
+ */
+struct ofono_modem;
+struct sailfish_sim_info_priv;
+struct sailfish_sim_info {
+ GObject object;
+ struct sailfish_sim_info_priv *priv;
+ const char *path;
+ const char *iccid;
+ const char *imsi;
+ const char *spn;
+};
+
+typedef void (*sailfish_sim_info_cb_t)(struct sailfish_sim_info *si,
+ void *user_data);
+
+/* SIM info object associated with the particular slot */
+struct sailfish_sim_info *sailfish_sim_info_new(const char *path);
+struct sailfish_sim_info *sailfish_sim_info_ref(struct sailfish_sim_info *si);
+void sailfish_sim_info_unref(struct sailfish_sim_info *si);
+void sailfish_sim_info_invalidate(struct sailfish_sim_info *si);
+gulong sailfish_sim_info_add_iccid_changed_handler(struct sailfish_sim_info *si,
+ sailfish_sim_info_cb_t cb, void *user_data);
+gulong sailfish_sim_info_add_imsi_changed_handler(struct sailfish_sim_info *si,
+ sailfish_sim_info_cb_t cb, void *user_data);
+gulong sailfish_sim_info_add_spn_changed_handler(struct sailfish_sim_info *si,
+ sailfish_sim_info_cb_t cb, void *user_data);
+void sailfish_sim_info_remove_handler(struct sailfish_sim_info *si, gulong id);
+void sailfish_sim_info_remove_handlers(struct sailfish_sim_info *si,
+ gulong *ids, int count);
+
+#define sailfish_sim_info_remove_all_handlers(si,ids) \
+ sailfish_sim_info_remove_handlers(si, ids, G_N_ELEMENTS(ids))
+
+/* And the D-Bus interface for it */
+struct sailfish_sim_info_dbus;
+struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new
+ (struct sailfish_sim_info *si);
+struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new_path
+ (const char *path);
+void sailfish_sim_info_dbus_free(struct sailfish_sim_info_dbus *dbus);
+
+#endif /* SAILFISH_SIM_INFO_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_manager/sailfish_sim_info_dbus.c
^
|
@@ -0,0 +1,296 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sailfish_sim_info.h"
+#include "sailfish_watch.h"
+
+#include <ofono/dbus.h>
+
+#include <gdbus.h>
+
+#include "ofono.h"
+
+enum watch_event_id {
+ WATCH_EVENT_MODEM,
+ WATCH_EVENT_COUNT
+};
+
+enum sim_info_event_id {
+ SIM_INFO_EVENT_ICCID,
+ SIM_INFO_EVENT_IMSI,
+ SIM_INFO_EVENT_SPN,
+ SIM_INFO_EVENT_COUNT
+};
+
+struct sailfish_sim_info_dbus {
+ struct sailfish_sim_info *info;
+ struct sailfish_watch *watch;
+ DBusConnection *conn;
+ gulong watch_event_id[WATCH_EVENT_COUNT];
+ gulong info_event_id[SIM_INFO_EVENT_COUNT];
+};
+
+#define SIM_INFO_DBUS_INTERFACE "org.nemomobile.ofono.SimInfo"
+#define SIM_INFO_DBUS_INTERFACE_VERSION (1)
+
+#define SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL "CardIdentifierChanged"
+#define SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL "SubscriberIdentityChanged"
+#define SIM_INFO_DBUS_SPN_CHANGED_SIGNAL "ServiceProviderNameChanged"
+
+static void sailfish_sim_info_dbus_append_version(DBusMessageIter *it)
+{
+ const dbus_int32_t version = SIM_INFO_DBUS_INTERFACE_VERSION;
+
+ dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
+}
+
+static void sailfish_sim_info_dbus_append_string(DBusMessageIter *it,
+ const char *str)
+{
+ if (!str) str = "";
+ dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
+}
+
+static DBusMessage *sailfish_sim_info_dbus_reply_with_string(DBusMessage *msg,
+ const char *str)
+{
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append(reply, &iter);
+ sailfish_sim_info_dbus_append_string(&iter, str);
+ return reply;
+}
+
+static DBusMessage *sailfish_sim_info_dbus_get_all(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sailfish_sim_info_dbus *dbus = data;
+ struct sailfish_sim_info *info = dbus->info;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ DBusMessageIter it;
+
+ dbus_message_iter_init_append(reply, &it);
+ sailfish_sim_info_dbus_append_version(&it);
+ sailfish_sim_info_dbus_append_string(&it, info->iccid);
+ sailfish_sim_info_dbus_append_string(&it, info->imsi);
+ sailfish_sim_info_dbus_append_string(&it, info->spn);
+ return reply;
+}
+
+static DBusMessage *sailfish_sim_info_dbus_get_version(DBusConnection *dc,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ DBusMessageIter it;
+
+ dbus_message_iter_init_append(reply, &it);
+ sailfish_sim_info_dbus_append_version(&it);
+ return reply;
+}
+
+static DBusMessage *sailfish_sim_info_dbus_get_iccid(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sailfish_sim_info_dbus *dbus = data;
+
+ return sailfish_sim_info_dbus_reply_with_string(msg, dbus->info->iccid);
+}
+
+static DBusMessage *sailfish_sim_info_dbus_get_imsi(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sailfish_sim_info_dbus *dbus = data;
+
+ return sailfish_sim_info_dbus_reply_with_string(msg, dbus->info->imsi);
+}
+
+static DBusMessage *sailfish_sim_info_dbus_get_spn(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct sailfish_sim_info_dbus *dbus = data;
+
+ return sailfish_sim_info_dbus_reply_with_string(msg, dbus->info->spn);
+}
+
+#define SIM_INFO_DBUS_VERSION_ARG {"version", "i"}
+#define SIM_INFO_DBUS_ICCID_ARG {"iccid", "s"}
+#define SIM_INFO_DBUS_IMSI_ARG {"imsi", "s"}
+#define SIM_INFO_DBUS_SPN_ARG {"spn" , "s"}
+
+#define SIM_INFO_DBUS_GET_ALL_ARGS \
+ SIM_INFO_DBUS_VERSION_ARG, \
+ SIM_INFO_DBUS_ICCID_ARG, \
+ SIM_INFO_DBUS_IMSI_ARG, \
+ SIM_INFO_DBUS_SPN_ARG
+
+static const GDBusMethodTable sailfish_sim_info_dbus_methods[] = {
+ { GDBUS_METHOD("GetAll",
+ NULL, GDBUS_ARGS(SIM_INFO_DBUS_GET_ALL_ARGS),
+ sailfish_sim_info_dbus_get_all) },
+ { GDBUS_METHOD("GetInterfaceVersion",
+ NULL, GDBUS_ARGS(SIM_INFO_DBUS_VERSION_ARG),
+ sailfish_sim_info_dbus_get_version) },
+ { GDBUS_METHOD("GetCardIdentifier",
+ NULL, GDBUS_ARGS(SIM_INFO_DBUS_ICCID_ARG),
+ sailfish_sim_info_dbus_get_iccid) },
+ { GDBUS_METHOD("GetSubscriberIdentity",
+ NULL, GDBUS_ARGS(SIM_INFO_DBUS_IMSI_ARG),
+ sailfish_sim_info_dbus_get_imsi) },
+ { GDBUS_METHOD("GetServiceProviderName",
+ NULL, GDBUS_ARGS(SIM_INFO_DBUS_SPN_ARG),
+ sailfish_sim_info_dbus_get_spn) },
+ { }
+};
+
+static const GDBusSignalTable sailfish_sim_info_dbus_signals[] = {
+ { GDBUS_SIGNAL(SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
+ GDBUS_ARGS(SIM_INFO_DBUS_ICCID_ARG)) },
+ { GDBUS_SIGNAL(SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
+ GDBUS_ARGS(SIM_INFO_DBUS_IMSI_ARG)) },
+ { GDBUS_SIGNAL(SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
+ GDBUS_ARGS(SIM_INFO_DBUS_SPN_ARG)) },
+ { }
+};
+
+static void sailfish_sim_info_dbus_modem_cb(struct sailfish_watch *watch,
+ void *data)
+{
+ if (watch->modem) {
+ ofono_modem_add_interface(watch->modem,
+ SIM_INFO_DBUS_INTERFACE);
+ }
+}
+
+static void sailfish_sim_info_dbus_emit(struct sailfish_sim_info_dbus *dbus,
+ const char *signal, const char *value)
+{
+ const char *arg = value;
+
+ if (!arg) arg = "";
+ g_dbus_emit_signal(dbus->conn, dbus->info->path,
+ SIM_INFO_DBUS_INTERFACE, signal,
+ DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
+}
+
+static void sailfish_sim_info_dbus_iccid_cb(struct sailfish_sim_info *info,
+ void *data)
+{
+ sailfish_sim_info_dbus_emit((struct sailfish_sim_info_dbus *)data,
+ SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL, info->iccid);
+}
+
+static void sailfish_sim_info_dbus_imsi_cb(struct sailfish_sim_info *info,
+ void *data)
+{
+ sailfish_sim_info_dbus_emit((struct sailfish_sim_info_dbus *)data,
+ SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL, info->imsi);
+}
+
+static void sailfish_sim_info_dbus_spn_cb(struct sailfish_sim_info *info,
+ void *data)
+{
+ sailfish_sim_info_dbus_emit((struct sailfish_sim_info_dbus *)data,
+ SIM_INFO_DBUS_SPN_CHANGED_SIGNAL, info->spn);
+}
+
+struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new
+ (struct sailfish_sim_info *info)
+{
+ struct sailfish_sim_info_dbus *dbus =
+ g_slice_new0(struct sailfish_sim_info_dbus);
+
+ DBG("%s", info->path);
+ dbus->info = sailfish_sim_info_ref(info);
+ dbus->watch = sailfish_watch_new(info->path);
+ dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
+
+ /* Register D-Bus interface */
+ if (g_dbus_register_interface(dbus->conn, dbus->info->path,
+ SIM_INFO_DBUS_INTERFACE,
+ sailfish_sim_info_dbus_methods,
+ sailfish_sim_info_dbus_signals,
+ NULL, dbus, NULL)) {
+ if (dbus->watch->modem) {
+ ofono_modem_add_interface(dbus->watch->modem,
+ SIM_INFO_DBUS_INTERFACE);
+ }
+
+ dbus->watch_event_id[WATCH_EVENT_MODEM] =
+ sailfish_watch_add_modem_changed_handler(dbus->watch,
+ sailfish_sim_info_dbus_modem_cb, dbus);
+ dbus->info_event_id[SIM_INFO_EVENT_ICCID] =
+ sailfish_sim_info_add_iccid_changed_handler(info,
+ sailfish_sim_info_dbus_iccid_cb, dbus);
+ dbus->info_event_id[SIM_INFO_EVENT_IMSI] =
+ sailfish_sim_info_add_imsi_changed_handler(info,
+ sailfish_sim_info_dbus_imsi_cb, dbus);
+ dbus->info_event_id[SIM_INFO_EVENT_SPN] =
+ sailfish_sim_info_add_spn_changed_handler(info,
+ sailfish_sim_info_dbus_spn_cb, dbus);
+
+ return dbus;
+ } else {
+ ofono_error("SimInfo D-Bus register failed");
+ sailfish_sim_info_dbus_free(dbus);
+ return NULL;
+ }
+}
+
+struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new_path
+ (const char *path)
+{
+ struct sailfish_sim_info_dbus *dbus = NULL;
+ struct sailfish_sim_info *info = sailfish_sim_info_new(path);
+
+ if (info) {
+ dbus = sailfish_sim_info_dbus_new(info);
+ sailfish_sim_info_unref(info);
+ }
+
+ return dbus;
+}
+
+void sailfish_sim_info_dbus_free(struct sailfish_sim_info_dbus *dbus)
+{
+ if (dbus) {
+ DBG("%s", dbus->info->path);
+ g_dbus_unregister_interface(dbus->conn, dbus->info->path,
+ SIM_INFO_DBUS_INTERFACE);
+ if (dbus->watch->modem) {
+ ofono_modem_remove_interface(dbus->watch->modem,
+ SIM_INFO_DBUS_INTERFACE);
+ }
+ dbus_connection_unref(dbus->conn);
+
+ sailfish_watch_remove_all_handlers(dbus->watch,
+ dbus->watch_event_id);
+ sailfish_watch_unref(dbus->watch);
+
+ sailfish_sim_info_remove_all_handlers(dbus->info,
+ dbus->info_event_id);
+ sailfish_sim_info_unref(dbus->info);
+
+ g_slice_free(struct sailfish_sim_info_dbus, dbus);
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_manager/sailfish_watch.c
^
|
@@ -0,0 +1,680 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sailfish_watch.h"
+
+#include <gutil_misc.h>
+#include <gutil_log.h>
+
+#include "ofono.h"
+
+typedef GObjectClass SailfishWatchClass;
+typedef struct sailfish_watch SailfishWatch;
+
+struct sailfish_watch_priv {
+ char *path;
+ char *iccid;
+ char *imsi;
+ char *spn;
+ int signals_suspended;
+ int queued_signals;
+ guint modem_watch_id;
+ guint online_watch_id;
+ guint sim_watch_id;
+ guint sim_state_watch_id;
+ guint iccid_watch_id;
+ guint imsi_watch_id;
+ guint spn_watch_id;
+ guint netreg_watch_id;
+};
+
+enum sailfish_watch_signal {
+ SIGNAL_MODEM_CHANGED,
+ SIGNAL_ONLINE_CHANGED,
+ SIGNAL_SIM_CHANGED,
+ SIGNAL_SIM_STATE_CHANGED,
+ SIGNAL_ICCID_CHANGED,
+ SIGNAL_IMSI_CHANGED,
+ SIGNAL_SPN_CHANGED,
+ SIGNAL_NETREG_CHANGED,
+ SIGNAL_COUNT
+};
+
+#define SIGNAL_MODEM_CHANGED_NAME "sailfish-watch-modem-changed"
+#define SIGNAL_ONLINE_CHANGED_NAME "sailfish-watch-online-changed"
+#define SIGNAL_SIM_CHANGED_NAME "sailfish-watch-sim-changed"
+#define SIGNAL_SIM_STATE_CHANGED_NAME "sailfish-watch-sim-state-changed"
+#define SIGNAL_ICCID_CHANGED_NAME "sailfish-watch-iccid-changed"
+#define SIGNAL_IMSI_CHANGED_NAME "sailfish-watch-imsi-changed"
+#define SIGNAL_SPN_CHANGED_NAME "sailfish-watch-spn-changed"
+#define SIGNAL_NETREG_CHANGED_NAME "sailfish-watch-netreg-changed"
+
+static guint sailfish_watch_signals[SIGNAL_COUNT] = { 0 };
+static GHashTable* sailfish_watch_table = NULL;
+
+G_DEFINE_TYPE(SailfishWatch, sailfish_watch, G_TYPE_OBJECT)
+#define SAILFISH_WATCH_TYPE (sailfish_watch_get_type())
+#define SAILFISH_WATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
+ SAILFISH_WATCH_TYPE, SailfishWatch))
+
+#define NEW_SIGNAL(klass,name) \
+ sailfish_watch_signals[SIGNAL_##name##_CHANGED] = \
+ g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
+ G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
+ 0, NULL, NULL, NULL, G_TYPE_NONE, 0)
+
+/* Skip the leading slash from the modem path: */
+#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
+
+static inline int sailfish_watch_signal_bit(enum sailfish_watch_signal id)
+{
+ return (1 << id);
+}
+
+static inline void sailfish_watch_signal_emit(struct sailfish_watch *self,
+ enum sailfish_watch_signal id)
+{
+ self->priv->queued_signals &= ~sailfish_watch_signal_bit(id);
+ g_signal_emit(self, sailfish_watch_signals[id], 0);
+}
+
+static inline void sailfish_watch_signal_queue(struct sailfish_watch *self,
+ enum sailfish_watch_signal id)
+{
+ self->priv->queued_signals |= sailfish_watch_signal_bit(id);
+}
+
+static void sailfish_watch_emit_queued_signals(struct sailfish_watch *self)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (priv->signals_suspended < 1) {
+ int i;
+
+ for (i = 0; priv->queued_signals && i < SIGNAL_COUNT; i++) {
+ if (priv->queued_signals &
+ sailfish_watch_signal_bit(i)) {
+ sailfish_watch_signal_emit(self, i);
+ }
+ }
+ }
+}
+
+static inline void sailfish_watch_suspend_signals(struct sailfish_watch *self)
+{
+ self->priv->signals_suspended++;
+}
+
+static inline void sailfish_watch_resume_signals(struct sailfish_watch *self)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ GASSERT(priv->signals_suspended > 0);
+ priv->signals_suspended--;
+ sailfish_watch_emit_queued_signals(self);
+}
+
+static void sailfish_watch_sim_state_notify(enum ofono_sim_state new_state,
+ void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ sailfish_watch_signal_queue(self, SIGNAL_SIM_STATE_CHANGED);
+ sailfish_watch_emit_queued_signals(self);
+}
+
+static void sailfish_watch_sim_state_destroy(void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+ struct sailfish_watch_priv *priv = self->priv;
+
+ GASSERT(priv->sim_state_watch_id);
+ priv->sim_state_watch_id = 0;
+}
+
+static void sailfish_watch_iccid_update(struct sailfish_watch *self,
+ const char *iccid)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->iccid, iccid)) {
+ g_free(priv->iccid);
+ self->iccid = priv->iccid = g_strdup(iccid);
+ sailfish_watch_signal_queue(self, SIGNAL_ICCID_CHANGED);
+ }
+}
+
+static void sailfish_watch_iccid_notify(const char *iccid, void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ sailfish_watch_iccid_update(self, iccid);
+ sailfish_watch_emit_queued_signals(self);
+}
+
+static void sailfish_watch_iccid_destroy(void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+ struct sailfish_watch_priv *priv = self->priv;
+
+ GASSERT(priv->iccid_watch_id);
+ priv->iccid_watch_id = 0;
+}
+
+static void sailfish_watch_spn_update(struct sailfish_watch *self,
+ const char *spn)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->spn, spn)) {
+ g_free(priv->spn);
+ self->spn = priv->spn = g_strdup(spn);
+ sailfish_watch_signal_queue(self, SIGNAL_SPN_CHANGED);
+ }
+}
+
+static void sailfish_watch_spn_notify(const char *spn, const char *dc,
+ void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ sailfish_watch_spn_update(self, spn);
+ sailfish_watch_emit_queued_signals(self);
+}
+
+static void sailfish_watch_spn_destroy(void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+ struct sailfish_watch_priv *priv = self->priv;
+
+ GASSERT(priv->spn_watch_id);
+ priv->spn_watch_id = 0;
+}
+
+static void sailfish_watch_imsi_update(struct sailfish_watch *self,
+ const char *imsi)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->imsi, imsi)) {
+ g_free(priv->imsi);
+ self->imsi = priv->imsi = g_strdup(imsi);
+ sailfish_watch_signal_queue(self, SIGNAL_IMSI_CHANGED);
+ /* ofono core crashes if we add spn watch too early */
+ if (imsi) {
+ ofono_sim_add_spn_watch(self->sim, &priv->spn_watch_id,
+ sailfish_watch_spn_notify, self,
+ sailfish_watch_spn_destroy);
+ }
+ }
+}
+
+static void sailfish_watch_imsi_notify(const char *imsi, void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ sailfish_watch_imsi_update(self, imsi);
+ sailfish_watch_emit_queued_signals(self);
+}
+
+static void sailfish_watch_imsi_destroy(void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+ struct sailfish_watch_priv *priv = self->priv;
+
+ GASSERT(priv->imsi_watch_id);
+ priv->imsi_watch_id = 0;
+}
+
+static void sailfish_watch_set_sim(struct sailfish_watch *self,
+ struct ofono_sim *sim)
+{
+ if (self->sim != sim) {
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (priv->sim_state_watch_id) {
+ ofono_sim_remove_state_watch(self->sim,
+ priv->sim_state_watch_id);
+ /* The destroy callback clears it */
+ GASSERT(!priv->sim_state_watch_id);
+ }
+ if (priv->iccid_watch_id) {
+ ofono_sim_remove_iccid_watch(self->sim,
+ priv->iccid_watch_id);
+ /* The destroy callback clears it */
+ GASSERT(!priv->iccid_watch_id);
+ }
+ if (priv->imsi_watch_id) {
+ ofono_sim_remove_imsi_watch(self->sim,
+ priv->imsi_watch_id);
+ /* The destroy callback clears it */
+ GASSERT(!priv->imsi_watch_id);
+ }
+ if (priv->spn_watch_id) {
+ ofono_sim_remove_spn_watch(self->sim,
+ &priv->spn_watch_id);
+ /* The destroy callback clears it */
+ GASSERT(!priv->spn_watch_id);
+ }
+ self->sim = sim;
+ sailfish_watch_signal_queue(self, SIGNAL_SIM_CHANGED);
+ sailfish_watch_suspend_signals(self);
+ if (sim) {
+ priv->sim_state_watch_id =
+ ofono_sim_add_state_watch(sim,
+ sailfish_watch_sim_state_notify, self,
+ sailfish_watch_sim_state_destroy);
+ /*
+ * Unlike ofono_sim_add_state_watch, the rest
+ * of ofono_sim_add_xxx_watch functions call the
+ * notify callback if the value is already known
+ * to the ofono core.
+ *
+ * Also note that ofono core crashes if we add
+ * spn watch too early.
+ */
+ priv->iccid_watch_id =
+ ofono_sim_add_iccid_watch(self->sim,
+ sailfish_watch_iccid_notify, self,
+ sailfish_watch_iccid_destroy);
+ priv->imsi_watch_id =
+ ofono_sim_add_imsi_watch(self->sim,
+ sailfish_watch_imsi_notify, self,
+ sailfish_watch_imsi_destroy);
+ } else {
+ /* And these will just queue the signals
+ * if necessary */
+ sailfish_watch_iccid_update(self, NULL);
+ sailfish_watch_imsi_update(self, NULL);
+ sailfish_watch_spn_update(self, NULL);
+ }
+
+ /* Emit the pending signals. */
+ sailfish_watch_resume_signals(self);
+ }
+}
+
+static void sailfish_watch_sim_notify(struct ofono_atom *atom,
+ enum ofono_atom_watch_condition cond, void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
+ struct ofono_sim *sim = __ofono_atom_get_data(atom);
+
+ DBG_(self, "sim registered");
+ sailfish_watch_set_sim(self, sim);
+ } else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+ DBG_(self, "sim unregistered");
+ sailfish_watch_set_sim(self, NULL);
+ }
+}
+
+static void sailfish_watch_sim_destroy(void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ self->priv->sim_watch_id = 0;
+}
+
+static void sailfish_watch_set_netreg(struct sailfish_watch *self,
+ struct ofono_netreg *netreg)
+{
+ if (self->netreg != netreg) {
+ self->netreg = netreg;
+ sailfish_watch_signal_emit(self, SIGNAL_NETREG_CHANGED);
+ }
+}
+
+static void sailfish_watch_netreg_notify(struct ofono_atom *atom,
+ enum ofono_atom_watch_condition cond, void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
+ struct ofono_netreg *netreg = __ofono_atom_get_data(atom);
+
+ DBG_(self, "netreg registered");
+ sailfish_watch_set_netreg(self, netreg);
+ } else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+ DBG_(self, "netreg unregistered");
+ sailfish_watch_set_netreg(self, NULL);
+ }
+}
+
+static void sailfish_watch_netreg_destroy(void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ self->priv->netreg_watch_id = 0;
+}
+
+static void sailfish_watch_online_update(struct sailfish_watch *self,
+ gboolean online)
+{
+ if (self->online != online) {
+ self->online = online;
+ sailfish_watch_signal_queue(self, SIGNAL_ONLINE_CHANGED);
+ }
+}
+
+static void sailfish_watch_online_notify(struct ofono_modem *modem,
+ ofono_bool_t online, void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ GASSERT(self->modem == modem);
+ GASSERT(online == ofono_modem_get_online(modem));
+ sailfish_watch_online_update(self, online);
+ sailfish_watch_emit_queued_signals(self);
+}
+
+static void sailfish_watch_online_destroy(void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ self->priv->online_watch_id = 0;
+}
+
+static void sailfish_watch_setup_modem(struct sailfish_watch *self)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ GASSERT(!priv->online_watch_id);
+ priv->online_watch_id =
+ __ofono_modem_add_online_watch(self->modem,
+ sailfish_watch_online_notify, self,
+ sailfish_watch_online_destroy);
+
+ /* __ofono_modem_add_atom_watch() calls the notify callback if the
+ * atom is already registered */
+ GASSERT(!priv->sim_watch_id);
+ priv->sim_watch_id = __ofono_modem_add_atom_watch(self->modem,
+ OFONO_ATOM_TYPE_SIM, sailfish_watch_sim_notify,
+ self, sailfish_watch_sim_destroy);
+
+ GASSERT(!priv->netreg_watch_id);
+ priv->netreg_watch_id = __ofono_modem_add_atom_watch(self->modem,
+ OFONO_ATOM_TYPE_NETREG, sailfish_watch_netreg_notify,
+ self, sailfish_watch_netreg_destroy);
+}
+
+static void sailfish_watch_cleanup_modem(struct sailfish_watch *self,
+ struct ofono_modem *modem)
+{
+ /* Caller checks the self->modem isn't NULL */
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (priv->online_watch_id) {
+ __ofono_modem_remove_online_watch(modem,
+ priv->online_watch_id);
+ GASSERT(!priv->online_watch_id);
+ }
+
+ if (priv->sim_watch_id) {
+ __ofono_modem_remove_atom_watch(modem, priv->sim_watch_id);
+ GASSERT(!priv->sim_watch_id);
+ }
+
+ if (priv->netreg_watch_id) {
+ __ofono_modem_remove_atom_watch(modem, priv->netreg_watch_id);
+ GASSERT(!priv->netreg_watch_id);
+ }
+
+ sailfish_watch_set_sim(self, NULL);
+ sailfish_watch_set_netreg(self, NULL);
+}
+
+static void sailfish_watch_set_modem(struct sailfish_watch *self,
+ struct ofono_modem *modem)
+{
+ if (self->modem != modem) {
+ struct ofono_modem *old_modem = self->modem;
+
+ self->modem = modem;
+ sailfish_watch_signal_queue(self, SIGNAL_MODEM_CHANGED);
+ if (old_modem) {
+ sailfish_watch_cleanup_modem(self, old_modem);
+ }
+ if (modem) {
+ sailfish_watch_setup_modem(self);
+ }
+ sailfish_watch_emit_queued_signals(self);
+ }
+}
+
+static void sailfish_watch_modem_notify(struct ofono_modem *modem,
+ gboolean added, void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ if (added) {
+ if (!g_strcmp0(self->path, ofono_modem_get_path(modem))) {
+ sailfish_watch_set_modem(self, modem);
+ }
+ } else if (self->modem == modem) {
+ sailfish_watch_set_modem(self, NULL);
+ }
+}
+
+static void sailfish_watch_modem_destroy(void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ self->priv->modem_watch_id = 0;
+}
+
+static ofono_bool_t sailfish_watch_modem_find(struct ofono_modem *modem,
+ void *user_data)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(user_data);
+
+ if (!g_strcmp0(self->path, ofono_modem_get_path(modem))) {
+ self->modem = modem;
+ sailfish_watch_setup_modem(self);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static void sailfish_watch_initialize(struct sailfish_watch *self,
+ const char *path)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ self->path = priv->path = g_strdup(path);
+ ofono_modem_find(sailfish_watch_modem_find, self);
+ self->online = ofono_modem_get_online(self->modem);
+ priv->modem_watch_id =
+ __ofono_modemwatch_add(sailfish_watch_modem_notify, self,
+ sailfish_watch_modem_destroy);
+}
+
+static void sailfish_watch_destroyed(gpointer key, GObject* obj)
+{
+ GASSERT(sailfish_watch_table);
+ DBG("%s", (char*)key);
+ if (sailfish_watch_table) {
+ GASSERT(g_hash_table_lookup(sailfish_watch_table, key) == obj);
+ g_hash_table_remove(sailfish_watch_table, key);
+ if (g_hash_table_size(sailfish_watch_table) == 0) {
+ g_hash_table_unref(sailfish_watch_table);
+ sailfish_watch_table = NULL;
+ }
+ }
+}
+
+struct sailfish_watch *sailfish_watch_new(const char *path)
+{
+ struct sailfish_watch *watch = NULL;
+
+ if (path) {
+ if (sailfish_watch_table) {
+ watch = sailfish_watch_ref(g_hash_table_lookup(
+ sailfish_watch_table, path));
+ }
+ if (!watch) {
+ char* key = g_strdup(path);
+
+ watch = g_object_new(SAILFISH_WATCH_TYPE, NULL);
+ sailfish_watch_initialize(watch, path);
+ if (!sailfish_watch_table) {
+ /* Create the table on demand */
+ sailfish_watch_table =
+ g_hash_table_new_full(g_str_hash,
+ g_str_equal, g_free, NULL);
+ }
+ g_hash_table_replace(sailfish_watch_table, key, watch);
+ g_object_weak_ref(G_OBJECT(watch),
+ sailfish_watch_destroyed, key);
+ DBG_(watch, "created");
+ }
+ }
+ return watch;
+}
+
+struct sailfish_watch *sailfish_watch_ref(struct sailfish_watch *self)
+{
+ if (self) {
+ g_object_ref(SAILFISH_WATCH(self));
+ return self;
+ } else {
+ return NULL;
+ }
+}
+
+void sailfish_watch_unref(struct sailfish_watch *self)
+{
+ if (self) {
+ g_object_unref(SAILFISH_WATCH(self));
+ }
+}
+
+gulong sailfish_watch_add_modem_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_MODEM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_online_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_sim_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_SIM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_sim_state_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_SIM_STATE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_iccid_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_imsi_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_spn_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_netreg_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_NETREG_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+void sailfish_watch_remove_handler(struct sailfish_watch *self, gulong id)
+{
+ if (self && id) {
+ g_signal_handler_disconnect(self, id);
+ }
+}
+
+void sailfish_watch_remove_handlers(struct sailfish_watch *self, gulong *ids,
+ int count)
+{
+ gutil_disconnect_handlers(self, ids, count);
+}
+
+static void sailfish_watch_init(struct sailfish_watch *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SAILFISH_WATCH_TYPE,
+ struct sailfish_watch_priv);
+}
+
+static void sailfish_watch_finalize(GObject *object)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(object);
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (self->modem) {
+ struct ofono_modem *modem = self->modem;
+
+ self->modem = NULL;
+ sailfish_watch_cleanup_modem(self, modem);
+ }
+ if (priv->modem_watch_id) {
+ __ofono_modemwatch_remove(priv->modem_watch_id);
+ GASSERT(!priv->modem_watch_id);
+ }
+ g_free(priv->path);
+ G_OBJECT_CLASS(sailfish_watch_parent_class)->finalize(object);
+}
+
+static void sailfish_watch_class_init(SailfishWatchClass *klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = sailfish_watch_finalize;
+ g_type_class_add_private(klass, sizeof(struct sailfish_watch_priv));
+ NEW_SIGNAL(klass, MODEM);
+ NEW_SIGNAL(klass, ONLINE);
+ NEW_SIGNAL(klass, SIM);
+ NEW_SIGNAL(klass, SIM_STATE);
+ NEW_SIGNAL(klass, ICCID);
+ NEW_SIGNAL(klass, IMSI);
+ NEW_SIGNAL(klass, SPN);
+ NEW_SIGNAL(klass, NETREG);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_provision.c
^
|
@@ -0,0 +1,251 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2013-2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/log.h>
+#include <ofono/plugin.h>
+#include <ofono/modem.h>
+#include <ofono/gprs-provision.h>
+
+#include "provision.h"
+#include "mbpi.h"
+
+struct provision_ap_defaults {
+ enum ofono_gprs_context_type type;
+ const char *name;
+ const char *apn;
+};
+
+static gint provision_match_strings(const char *s1, const char *s2)
+{
+ gint match = 0;
+
+ /* Caller checks s2 for NULL */
+ if (s1) {
+ const gssize len1 = strlen(s1);
+ const gssize len2 = strlen(s2);
+
+ if (len1 == len2 && !strcmp(s1, s2)) {
+ /* Best match ever */
+ match = 3;
+ } else if (g_utf8_validate(s1, len1, NULL) &&
+ g_utf8_validate(s2, len2, NULL)) {
+ char *d1 = g_utf8_strdown(s1, len1);
+ char *d2 = g_utf8_strdown(s2, len2);
+
+ if (len1 == len2 && !strcmp(d1, d2)) {
+ /* Case insensitive match */
+ match = 2;
+ } else if ((len1 > len2 && strstr(d1, d2)) ||
+ (len2 > len1 && strstr(d2, d1))) {
+ /* Partial case insensitive match */
+ match = 1;
+ }
+
+ g_free(d1);
+ g_free(d2);
+ }
+ }
+
+ return match;
+}
+static gint provision_match_spn(const struct ofono_gprs_provision_data *ap,
+ const char *spn)
+{
+ return provision_match_strings(ap->provider_name, spn) * 4 +
+ provision_match_strings(ap->name, spn);
+}
+
+static void provision_free_ap(gpointer data)
+{
+ mbpi_ap_free(data);
+}
+
+static gint provision_compare_ap(gconstpointer a, gconstpointer b,
+ gpointer data)
+{
+ const struct ofono_gprs_provision_data *ap1 = a;
+ const struct ofono_gprs_provision_data *ap2 = b;
+ const char *spn = data;
+
+ if (spn) {
+ const gint result = provision_match_spn(ap2, spn) -
+ provision_match_spn(ap1, spn);
+
+ if (result) {
+ return result;
+ }
+ }
+
+ if (ap1->provider_primary && !ap2->provider_primary) {
+ return -1;
+ } else if (ap2->provider_primary && !ap1->provider_primary) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Picks best ap, deletes the rest. Creates one if necessary */
+static GSList *provision_pick_best_ap(GSList *list, const char *spn,
+ const enum ofono_gprs_proto default_proto,
+ const struct provision_ap_defaults *defaults)
+{
+ /* Sort the list */
+ list = g_slist_sort_with_data(list, provision_compare_ap, (void*)spn);
+ if (list) {
+ /* Pick the best one, delete the rest */
+ GSList *best = list;
+ g_slist_free_full(g_slist_remove_link(list, best),
+ provision_free_ap);
+ return best;
+ } else {
+ /* or create one from the default data */
+ struct ofono_gprs_provision_data *ap =
+ g_new0(struct ofono_gprs_provision_data, 1);
+
+ ap->proto = default_proto;
+ ap->type = defaults->type;
+ ap->name = g_strdup(defaults->name);
+ ap->apn = g_strdup(defaults->apn);
+ ap->auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
+ return g_slist_append(NULL, ap);
+ }
+}
+
+/* Returns the list containing exactly one INTERNET and one MMS access point */
+static GSList *provision_normalize_apn_list(GSList *apns, const char *spn)
+{
+ static const struct provision_ap_defaults internet_defaults =
+ { OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
+ static const struct provision_ap_defaults mms_defaults =
+ { OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
+
+ GSList *internet_apns = NULL;
+ GSList *mms_apns = NULL;
+
+ /* Split internet and mms apns, delete all others */
+ while (apns) {
+ GSList *link = apns;
+ struct ofono_gprs_provision_data *ap = link->data;
+
+ apns = g_slist_remove_link(apns, link);
+ if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
+ internet_apns = g_slist_concat(internet_apns, link);
+ } else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
+ mms_apns = g_slist_concat(mms_apns, link);
+ } else {
+ g_slist_free_full(link, provision_free_ap);
+ }
+ }
+
+ /* Pick the best ap of each type and concatenate them */
+ return g_slist_concat(
+ provision_pick_best_ap(internet_apns, spn,
+ mbpi_default_internet_proto, &internet_defaults),
+ provision_pick_best_ap(mms_apns, spn,
+ mbpi_default_mms_proto, &mms_defaults));
+}
+
+int provision_get_settings(const char *mcc, const char *mnc,
+ const char *spn,
+ struct ofono_gprs_provision_data **settings,
+ int *count)
+{
+ GSList *l;
+ GSList *apns;
+ GError *error = NULL;
+ int ap_count;
+ int i;
+
+ ofono_info("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
+
+ /*
+ * Passing FALSE to mbpi_lookup_apn() would return
+ * an empty list if duplicates are found.
+ */
+ apns = mbpi_lookup_apn(mcc, mnc, TRUE, &error);
+ if (error != NULL) {
+ ofono_error("%s", error->message);
+ g_error_free(error);
+ }
+
+ DBG("Found %d APs in MBPI", g_slist_length(apns));
+ apns = provision_normalize_apn_list(apns, spn);
+ ap_count = g_slist_length(apns);
+
+ DBG("Provisioning %d APs", ap_count);
+ *settings = g_new0(struct ofono_gprs_provision_data, ap_count);
+ *count = ap_count;
+
+ for (l = apns, i = 0; l; l = l->next, i++) {
+ struct ofono_gprs_provision_data *ap = l->data;
+
+ ofono_info("Name: '%s'", ap->name);
+ ofono_info(" APN: '%s'", ap->apn);
+ ofono_info(" Type: %s", mbpi_ap_type(ap->type));
+ ofono_info(" Username: '%s'", ap->username);
+ ofono_info(" Password: '%s'", ap->password);
+
+ memcpy(*settings + i, ap,
+ sizeof(struct ofono_gprs_provision_data));
+
+ g_free(ap);
+ }
+
+ g_slist_free(apns);
+
+ return 0;
+}
+
+static struct ofono_gprs_provision_driver provision_driver = {
+ .name = "Provisioning",
+ .get_settings = provision_get_settings
+};
+
+static int provision_init(void)
+{
+ DBG("");
+ return ofono_gprs_provision_driver_register(&provision_driver);
+}
+
+static void provision_exit(void)
+{
+ DBG("");
+ ofono_gprs_provision_driver_unregister(&provision_driver);
+}
+
+OFONO_PLUGIN_DEFINE(provision, "Provisioning Plugin", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT,
+ provision_init, provision_exit)
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/plugins/sailfish_pushforwarder.c
^
|
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2013-2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gutil_inotify.h>
+#include <sys/inotify.h>
+#include <wspcodec.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono.h>
+#include <plugin.h>
+
+/*
+ * Push forwarder plugin is looking for configuration files in
+ * /etc/ofono/push_forwarder.d directory. Confiration files are
+ * glib key files that look like this:
+ *
+ * [Jolla MMS Handler]
+ * ContentType = application/vnd.wap.mms-message
+ * Interface = com.jolla.MmsEngine.
+ * Service = com.jolla.MmsEngine
+ * Method = HandlePush
+ * Path = /
+ *
+ * Only files with .conf suffix are loaded. In addition to the keys
+ * from the above example, SourcePort and DestinationPort port keys
+ * are supported. All other keys are ignored. One file may describe
+ * several push handlers. See pf_parse_config() function for details.
+ *
+ * When push fowarder receives a WAP push, it goes through the list
+ * of registered handlers and invokes all of them that match content
+ * type and/or port numbers. The rest is up to the D-Bus service
+ * handling the call.
+ */
+
+#define PF_CONFIG_DIR CONFIGDIR "/push_forwarder.d"
+
+struct pf_modem {
+ struct ofono_modem *modem;
+ struct ofono_sms *sms;
+ struct ofono_sim *sim;
+ unsigned int sim_watch_id;
+ unsigned int sms_watch_id;
+ unsigned int push_watch_id;
+};
+
+struct push_datagram_handler {
+ char *name;
+ char *content_type;
+ char *interface;
+ char *service;
+ char *method;
+ char *path;
+ int dst_port;
+ int src_port;
+};
+
+static GSList *handlers;
+static GSList *modems;
+static unsigned int modem_watch_id;
+static GUtilInotifyWatchCallback *inotify_cb;
+
+static void pf_notify_handler(struct push_datagram_handler *h,
+ const char *imsi, const char *from, const struct tm *remote,
+ const struct tm *local, int dst, int src,
+ const char *ct, const void *data, unsigned int len)
+{
+ struct tm remote_tm = *remote;
+ struct tm local_tm = *local;
+ dbus_uint32_t remote_time_arg = mktime(&remote_tm);
+ dbus_uint32_t local_time_arg = mktime(&local_tm);
+ dbus_int32_t dst_arg = dst;
+ dbus_int32_t src_arg = src;
+ DBusMessageIter iter, array;
+ DBusMessage *msg = dbus_message_new_method_call(h->service,
+ h->path, h->interface, h->method);
+
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &imsi,
+ DBUS_TYPE_STRING, &from,
+ DBUS_TYPE_UINT32, &remote_time_arg,
+ DBUS_TYPE_UINT32, &local_time_arg,
+ DBUS_TYPE_INT32, &dst_arg,
+ DBUS_TYPE_INT32, &src_arg,
+ DBUS_TYPE_STRING, &ct,
+ DBUS_TYPE_INVALID);
+ dbus_message_iter_init_append(msg, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING, &array);
+ dbus_message_iter_append_fixed_array(&array,
+ DBUS_TYPE_BYTE, &data, len);
+ dbus_message_iter_close_container(&iter, &array);
+ dbus_message_set_no_reply(msg, TRUE);
+ dbus_connection_send(ofono_dbus_get_connection(), msg, NULL);
+ dbus_message_unref(msg);
+}
+
+static gboolean pf_match_port(int port, int expected_port)
+{
+ if (expected_port < 0)
+ return TRUE;
+
+ if (expected_port == port)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean pf_match_handler(struct push_datagram_handler *h,
+ const char *ct, int dst, int src)
+{
+ if (pf_match_port(dst, h->dst_port) == FALSE)
+ return FALSE;
+
+ if (pf_match_port(src, h->src_port) == FALSE)
+ return FALSE;
+
+ if (h->content_type == NULL)
+ return TRUE;
+
+ if (strcmp(h->content_type, ct) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void pf_handle_datagram(const char *from,
+ const struct tm *remote, const struct tm *local, int dst,
+ int src, const unsigned char *buffer, unsigned int len,
+ void *userdata)
+{
+ struct pf_modem *pm = userdata;
+ guint remain;
+ const guint8 *data;
+ unsigned int hdrlen;
+ unsigned int off;
+ const void *ct;
+ const char *imsi;
+ GSList *link;
+
+ DBG("received push of size: %u", len);
+
+ if (pm->sim == NULL)
+ return;
+
+ imsi = ofono_sim_get_imsi(pm->sim);
+ if (len < 3)
+ return;
+
+ if (buffer[1] != 6)
+ return;
+
+ remain = len - 2;
+ data = buffer + 2;
+
+ if (wsp_decode_uintvar(data, remain, &hdrlen, &off) == FALSE)
+ return;
+
+ if ((off + hdrlen) > remain)
+ return;
+
+ data += off;
+ remain -= off;
+
+ DBG(" WAP header %u bytes", hdrlen);
+
+ if (wsp_decode_content_type(data, hdrlen, &ct, &off, NULL) == FALSE)
+ return;
+
+ data += hdrlen;
+ remain -= hdrlen;
+
+ DBG(" content type %s", (char *)ct);
+ DBG(" imsi %s", imsi);
+ DBG(" data size %u", remain);
+
+ link = handlers;
+
+ while (link) {
+ struct push_datagram_handler *h = link->data;
+
+ if (pf_match_handler(h, ct, dst, src) != FALSE) {
+ DBG("notifying %s", h->name);
+ pf_notify_handler(h, imsi, from, remote, local, dst,
+ src, ct, data, remain);
+ }
+ link = link->next;
+ }
+}
+
+static void pf_sms_watch(struct ofono_atom *atom,
+ enum ofono_atom_watch_condition cond, void *userdata)
+{
+ struct pf_modem *pm = userdata;
+
+ if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
+ DBG("registered");
+ pm->sms = __ofono_atom_get_data(atom);
+ pm->push_watch_id = __ofono_sms_datagram_watch_add(pm->sms,
+ pf_handle_datagram, -1, -1, pm, NULL);
+ } else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+ DBG("unregistered");
+ pm->sms = NULL;
+ pm->push_watch_id = 0;
+ }
+}
+
+static void pf_sms_watch_done(void *userdata)
+{
+ struct pf_modem *pm = userdata;
+
+ pm->sms_watch_id = 0;
+}
+
+static void pf_sim_watch(struct ofono_atom *atom,
+ enum ofono_atom_watch_condition cond, void *userdata)
+{
+ struct pf_modem *pm = userdata;
+
+ if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
+ DBG("registered");
+ pm->sim = __ofono_atom_get_data(atom);
+ } else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+ DBG("unregistered");
+ pm->sim = NULL;
+ }
+}
+
+static void pf_sim_watch_done(void *userdata)
+{
+ struct pf_modem *pm = userdata;
+
+ pm->sim_watch_id = 0;
+}
+
+static void pf_free_modem(struct pf_modem *pm)
+{
+ if (pm == NULL)
+ return;
+
+ if (pm->push_watch_id != 0)
+ __ofono_sms_datagram_watch_remove(pm->sms, pm->push_watch_id);
+
+ if (pm->sim_watch_id != 0)
+ __ofono_modem_remove_atom_watch(pm->modem, pm->sim_watch_id);
+
+ if (pm->sms_watch_id != 0)
+ __ofono_modem_remove_atom_watch(pm->modem, pm->sms_watch_id);
+
+ g_free(pm);
+}
+
+static void pf_modem_watch(struct ofono_modem *modem,
+ gboolean added, void *userdata)
+{
+ DBG("modem: %p, added: %d", modem, added);
+ if (added != FALSE) {
+ struct pf_modem *pm;
+
+ pm = g_new0(struct pf_modem, 1);
+ pm->modem = modem;
+ pm->sms_watch_id = __ofono_modem_add_atom_watch(modem,
+ OFONO_ATOM_TYPE_SMS, pf_sms_watch, pm,
+ pf_sms_watch_done);
+ pm->sim_watch_id = __ofono_modem_add_atom_watch(modem,
+ OFONO_ATOM_TYPE_SIM, pf_sim_watch, pm,
+ pf_sim_watch_done);
+ modems = g_slist_append(modems, pm);
+ } else {
+ GSList *link = modems;
+
+ while (link) {
+ struct pf_modem *pm = link->data;
+
+ if (pm->modem == modem) {
+ modems = g_slist_delete_link(modems, link);
+ pf_free_modem(pm);
+ break;
+ }
+ link = link->next;
+ }
+ }
+}
+
+static void pf_modem_init(struct ofono_modem *modem,
+ void *userdata)
+{
+ pf_modem_watch(modem, TRUE, NULL);
+}
+
+static void pf_free_handler(void *data)
+{
+ struct push_datagram_handler *h = data;
+
+ g_free(h->content_type);
+ g_free(h->interface);
+ g_free(h->service);
+ g_free(h->method);
+ g_free(h->path);
+ g_free(h->name);
+ g_free(h);
+}
+
+static void pf_parse_handler(GKeyFile *conf, const char *g)
+{
+ GError *err = NULL;
+ struct push_datagram_handler *h;
+ char *interface;
+ char *service;
+ char *method;
+ char *path;
+
+ interface = g_key_file_get_string(conf, g, "Interface", NULL);
+ if (interface == NULL)
+ goto no_interface;
+
+ service = g_key_file_get_string(conf, g, "Service", NULL);
+ if (service == NULL)
+ goto no_service;
+
+ method = g_key_file_get_string(conf, g, "Method", NULL);
+ if (method == NULL)
+ goto no_method;
+
+ path = g_key_file_get_string(conf, g, "Path", NULL);
+ if (path == NULL)
+ goto no_path;
+
+ h = g_new0(struct push_datagram_handler, 1);
+ h->name = g_strdup(g);
+ h->interface = interface;
+ h->service = service;
+ h->method = method;
+ h->path = path;
+ h->content_type = g_key_file_get_string(conf, g, "ContentType", NULL);
+ h->dst_port = g_key_file_get_integer(conf, g, "DestinationPort", &err);
+ if (h->dst_port == 0 && err != NULL) {
+ h->dst_port = -1;
+ g_error_free(err);
+ err = NULL;
+ }
+ h->src_port = g_key_file_get_integer(conf, g, "SourcePort", &err);
+ if (h->src_port == 0 && err != NULL) {
+ h->src_port = -1;
+ g_error_free(err);
+ err = NULL;
+ }
+ DBG("registered %s", h->name);
+ if (h->content_type != NULL)
+ DBG(" ContentType: %s", h->content_type);
+ if (h->dst_port >= 0)
+ DBG(" DestinationPort: %d", h->dst_port);
+ if (h->src_port >= 0)
+ DBG(" SourcePort: %d", h->src_port);
+ DBG(" Interface: %s", interface);
+ DBG(" Service: %s", service);
+ DBG(" Method: %s", method);
+ DBG(" Path: %s", path);
+ handlers = g_slist_append(handlers, h);
+ return;
+
+no_path:
+ g_free(method);
+
+no_method:
+ g_free(service);
+
+no_service:
+ g_free(interface);
+
+no_interface:
+ return;
+}
+
+static void pf_parse_config(void)
+{
+ GDir *dir;
+ const gchar *file;
+
+ g_slist_free_full(handlers, pf_free_handler);
+ handlers = NULL;
+
+ dir = g_dir_open(PF_CONFIG_DIR, 0, NULL);
+ if (dir == NULL) {
+ DBG(PF_CONFIG_DIR " not found.");
+ return;
+ }
+
+ DBG("loading configuration from " PF_CONFIG_DIR);
+ while ((file = g_dir_read_name(dir)) != NULL) {
+ GError *err;
+ GKeyFile *conf;
+ char *path;
+
+ if (g_str_has_suffix(file, ".conf") == FALSE)
+ continue;
+
+ err = NULL;
+ conf = g_key_file_new();
+ path = g_strconcat(PF_CONFIG_DIR "/", file, NULL);
+ DBG("reading %s", file);
+
+ if (g_key_file_load_from_file(conf, path, 0, &err) != FALSE) {
+ gsize i, n;
+ char **names = g_key_file_get_groups(conf, &n);
+
+ for (i = 0; i < n; i++)
+ pf_parse_handler(conf, names[i]);
+ g_strfreev(names);
+ } else {
+ ofono_warn("%s", err->message);
+ g_error_free(err);
+ }
+
+ g_key_file_free(conf);
+ g_free(path);
+ }
+
+ g_dir_close(dir);
+}
+
+static void pf_inotify(GUtilInotifyWatch *watch, guint mask, guint cookie,
+ const char *name, void *user_data)
+{
+ DBG("'%s' changed (0x%04x)", name, mask);
+ pf_parse_config();
+}
+
+static int pf_plugin_init(void)
+{
+ DBG("");
+ pf_parse_config();
+ modem_watch_id = __ofono_modemwatch_add(pf_modem_watch, NULL, NULL);
+ __ofono_modem_foreach(pf_modem_init, NULL);
+ inotify_cb = gutil_inotify_watch_callback_new(PF_CONFIG_DIR,
+ IN_CLOSE_WRITE | IN_DELETE | IN_MOVE, pf_inotify, NULL);
+ return 0;
+}
+
+static void pf_plugin_exit(void)
+{
+ DBG("");
+ __ofono_modemwatch_remove(modem_watch_id);
+ modem_watch_id = 0;
+ g_slist_free_full(modems, (GDestroyNotify)pf_free_modem);
+ modems = NULL;
+ g_slist_free_full(handlers, pf_free_handler);
+ handlers = NULL;
+ gutil_inotify_watch_callback_free(inotify_cb);
+ inotify_cb = NULL;
+}
+
+OFONO_PLUGIN_DEFINE(pushforwarder, "Push Forwarder Plugin", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, pf_plugin_init,
+ pf_plugin_exit)
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/src/gprs.c
^
|
@@ -34,6 +34,7 @@
#include <net/route.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <ctype.h>
#include <glib.h>
#include <gdbus.h>
@@ -258,6 +259,10 @@
static const char *gprs_auth_method_to_string(enum ofono_gprs_auth_method auth)
{
switch (auth) {
+ case OFONO_GPRS_AUTH_METHOD_ANY:
+ return "any";
+ case OFONO_GPRS_AUTH_METHOD_NONE:
+ return "none";
case OFONO_GPRS_AUTH_METHOD_CHAP:
return "chap";
case OFONO_GPRS_AUTH_METHOD_PAP:
@@ -276,6 +281,12 @@
} else if (g_str_equal(str, "pap")) {
*auth = OFONO_GPRS_AUTH_METHOD_PAP;
return TRUE;
+ } else if (g_str_equal(str, "any")) {
+ *auth = OFONO_GPRS_AUTH_METHOD_ANY;
+ return TRUE;
+ } else if (g_str_equal(str, "none")) {
+ *auth = OFONO_GPRS_AUTH_METHOD_NONE;
+ return TRUE;
}
return FALSE;
@@ -641,7 +652,48 @@
}
g_free(ctx->proxy_host);
- ctx->proxy_host = g_strdup(host);
+ ctx->proxy_host = NULL;
+
+ if (host[0] == '0' || strstr(host, ".0")) {
+ /*
+ * Some operators provide IP address of the MMS proxy
+ * prepending zeros to each number shorter then 3 digits,
+ * e.g. "192.168.094.023" instead of "192.168.94.23".
+ * That may look nicer but it's actually wrong because
+ * the numbers starting with zeros are interpreted as
+ * octal numbers. In the example above 023 actually means
+ * 16 and 094 is not a valid number at all.
+ *
+ * In addition to publishing these broken settings on their
+ * web sites, some of the operators send them over the air,
+ * in which case we can't even blame the user for entering
+ * an invalid IP address. We better be prepared to deal with
+ * those.
+ *
+ * Since nobody in the world seems to be actually using the
+ * octal notation to write an IP address, let's remove the
+ * leading zeros if we find them in the host part of the MMS
+ * proxy URL.
+ */
+ char** parts = g_strsplit(host, ".", -1);
+ guint count = g_strv_length(parts);
+ if (count == 4) {
+ char** ptr = parts;
+ while (*ptr) {
+ char* part = *ptr;
+ while (part[0] == '0' && isdigit(part[1])) {
+ memmove(part, part+1, strlen(part));
+ }
+ *ptr++ = part;
+ }
+ ctx->proxy_host = g_strjoinv(".", parts);
+ DBG("%s => %s", host, ctx->proxy_host);
+ }
+ g_strfreev(parts);
+ }
+
+ if (!ctx->proxy_host)
+ ctx->proxy_host = g_strdup(host);
g_free(scheme);
return TRUE;
@@ -892,6 +944,13 @@
gprs_proto_to_string(ctx->context.proto));
}
+ if (ctx->context.auth_method != ap->auth_method) {
+ ctx->context.auth_method = ap->auth_method;
+ changed = TRUE;
+ pri_str_signal_change(ctx, "AuthenticationMethod",
+ gprs_auth_method_to_string(ctx->context.auth_method));
+ }
+
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
if (pri_str_update(ctx->message_proxy, ap->message_proxy,
sizeof(ctx->message_proxy))) {
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/src/mtu-watch.c
^
|
@@ -0,0 +1,219 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2016-2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "mtu-watch.h"
+
+#include <ofono/log.h>
+
+#include <glib.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <net/if.h>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+struct mtu_watch {
+ int max_mtu;
+ char *ifname;
+ void *buf;
+ int bufsize;
+ GIOChannel *channel;
+ guint io_watch;
+ int fd;
+};
+
+static void mtu_watch_limit_mtu(struct mtu_watch *self)
+{
+ int fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd >= 0) {
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, self->ifname, IFNAMSIZ);
+ if (ioctl(fd, SIOCGIFMTU, &ifr) < 0 ||
+ ifr.ifr_mtu > self->max_mtu) {
+ DBG("%s mtu %d => %d", self->ifname, ifr.ifr_mtu,
+ self->max_mtu);
+ ifr.ifr_mtu = self->max_mtu;
+ if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
+ ofono_error("Failed to set MTU");
+ }
+ }
+ close(fd);
+ }
+}
+
+static void mtu_watch_handle_rtattr(struct mtu_watch *self,
+ const struct rtattr *rta, int len)
+{
+ int mtu = 0;
+ const char *ifname = NULL;
+ while (len > 0 && RTA_OK(rta, len) && (!mtu || !ifname)) {
+ switch (rta->rta_type) {
+ case IFLA_IFNAME:
+ ifname = RTA_DATA(rta);
+ break;
+ case IFLA_MTU:
+ mtu = *((int*)RTA_DATA(rta));
+ break;
+ }
+ rta = RTA_NEXT(rta, len);
+ }
+ if (mtu > self->max_mtu && !g_strcmp0(ifname, self->ifname)) {
+ DBG("%s %d", ifname, mtu);
+ mtu_watch_limit_mtu(self);
+ }
+}
+
+static void mtu_watch_handle_ifinfomsg(struct mtu_watch *self,
+ const struct ifinfomsg *ifi, int len)
+{
+ if (ifi->ifi_flags & IFF_UP) {
+ const struct rtattr *rta = IFLA_RTA(ifi);
+ mtu_watch_handle_rtattr(self, rta,
+ len - ((char*)rta - (char*)ifi));
+ }
+}
+
+static void mtu_watch_handle_nlmsg(struct mtu_watch *self,
+ const struct nlmsghdr *hdr, int len)
+{
+ while (len > 0 && NLMSG_OK(hdr, len)) {
+ if (hdr->nlmsg_type == RTM_NEWLINK) {
+ mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr),
+ IFLA_PAYLOAD(hdr));
+ }
+ hdr = NLMSG_NEXT(hdr, len);
+ }
+}
+
+static gboolean mtu_watch_event(GIOChannel *ch, GIOCondition cond,
+ gpointer data)
+{
+ struct mtu_watch *self = data;
+ struct sockaddr_nl addr;
+ socklen_t addrlen = sizeof(addr);
+ ssize_t result = recvfrom(self->fd, self->buf, self->bufsize, 0,
+ (struct sockaddr *)&addr, &addrlen);
+ if (result > 0) {
+ if (!addr.nl_pid) {
+ mtu_watch_handle_nlmsg(self, self->buf, result);
+ }
+ return G_SOURCE_CONTINUE;
+ } else if (result == 0 || errno == EINTR || errno == EAGAIN) {
+ return G_SOURCE_CONTINUE;
+ } else {
+ DBG("%s error %d", self->ifname, errno);
+ self->io_watch = 0;
+ return G_SOURCE_REMOVE;
+ }
+}
+
+static gboolean mtu_watch_open_socket(struct mtu_watch *self)
+{
+ self->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (self->fd >= 0) {
+ struct sockaddr_nl nl;
+ memset(&nl, 0, sizeof(nl));
+ nl.nl_pid = getpid();
+ nl.nl_family = AF_NETLINK;
+ nl.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
+ RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE |
+ RTMGRP_LINK;
+
+ if (bind(self->fd, (struct sockaddr*)&nl, sizeof(nl)) >= 0) {
+ return TRUE;
+ }
+ close(self->fd);
+ self->fd = -1;
+ }
+ return FALSE;
+}
+
+static gboolean mtu_watch_start(struct mtu_watch *self)
+{
+ if (self->fd >= 0) {
+ return TRUE;
+ } else if (mtu_watch_open_socket(self)) {
+ self->channel = g_io_channel_unix_new(self->fd);
+ if (self->channel) {
+ g_io_channel_set_encoding(self->channel, NULL, NULL);
+ g_io_channel_set_buffered(self->channel, FALSE);
+ self->io_watch = g_io_add_watch(self->channel,
+ G_IO_IN | G_IO_NVAL | G_IO_HUP,
+ mtu_watch_event, self);
+ return TRUE;
+ }
+ close(self->fd);
+ self->fd = -1;
+ }
+ return FALSE;
+}
+
+static void mtu_watch_stop(struct mtu_watch *self)
+{
+ if (self->io_watch) {
+ g_source_remove(self->io_watch);
+ self->io_watch = 0;
+ }
+ if (self->channel) {
+ g_io_channel_shutdown(self->channel, TRUE, NULL);
+ g_io_channel_unref(self->channel);
+ self->channel = NULL;
+ }
+ if (self->fd >= 0) {
+ close(self->fd);
+ self->fd = -1;
+ }
+}
+
+struct mtu_watch *mtu_watch_new(int max_mtu)
+{
+ struct mtu_watch *self = g_new0(struct mtu_watch, 1);
+ self->fd = -1;
+ self->max_mtu = max_mtu;
+ self->bufsize = 4096;
+ self->buf = g_malloc(self->bufsize);
+ return self;
+}
+
+void mtu_watch_free(struct mtu_watch *self)
+{
+ if (self) {
+ mtu_watch_stop(self);
+ g_free(self->ifname);
+ g_free(self->buf);
+ g_free(self);
+ }
+}
+
+void mtu_watch_set_ifname(struct mtu_watch *self, const char *ifname)
+{
+ if (self && g_strcmp0(self->ifname, ifname)) {
+ g_free(self->ifname);
+ if (ifname) {
+ self->ifname = g_strdup(ifname);
+ mtu_watch_limit_mtu(self);
+ mtu_watch_start(self);
+ } else {
+ self->ifname = NULL;
+ mtu_watch_stop(self);
+ }
+ }
+}
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/src/mtu-watch.h
^
|
@@ -0,0 +1,25 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2016-2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MTU_WATCH_H
+#define MTU_WATCH_H
+
+struct mtu_watch;
+
+struct mtu_watch *mtu_watch_new(int max_mtu);
+void mtu_watch_free(struct mtu_watch *mw);
+void mtu_watch_set_ifname(struct mtu_watch *mw, const char *ifname);
+
+#endif /* MTU_WATCH_H */
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/src/network.c
^
|
@@ -1828,6 +1828,17 @@
return netreg->current_operator->mnc;
}
+const char *ofono_netreg_get_name(struct ofono_netreg *netreg)
+{
+ if (netreg == NULL)
+ return NULL;
+
+ if (netreg->current_operator == NULL)
+ return NULL;
+
+ return netreg->current_operator->name;
+}
+
struct sim_spdi *ofono_netreg_get_spdi(struct ofono_netreg *netreg)
{
if (netreg == NULL)
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/src/radio-settings.c
^
|
@@ -889,9 +889,13 @@
"GsmBand", rs->band_gsm);
}
+ if (error) {
+ g_error_free(error);
+ error = NULL;
+ }
+
rs->pending_band_gsm = rs->band_gsm;
- error = NULL;
rs->band_umts = g_key_file_get_integer(rs->settings, SETTINGS_GROUP,
"UmtsBand", &error);
@@ -901,9 +905,13 @@
"UmtsBand", rs->band_umts);
}
+ if (error) {
+ g_error_free(error);
+ error = NULL;
+ }
+
rs->pending_band_umts = rs->band_umts;
- error = NULL;
rs->mode = g_key_file_get_integer(rs->settings, SETTINGS_GROUP,
"TechnologyPreference", &error);
@@ -913,6 +921,11 @@
"TechnologyPreference", rs->mode);
}
+ if (error) {
+ g_error_free(error);
+ error = NULL;
+ }
+
DBG("TechnologyPreference: %d", rs->mode);
DBG("GsmBand: %d", rs->band_gsm);
DBG("UmtsBand: %d", rs->band_umts);
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/src/storage.h
^
|
@@ -28,6 +28,11 @@
#include <fcntl.h>
#include <sys/types.h>
+/* STORAGEDIR may need to be redefined in unit tests */
+#ifndef STORAGEDIR
+# define STORAGEDIR DEFAULT_STORAGEDIR
+#endif
+
int create_dirs(const char *filename, const mode_t mode);
ssize_t read_file(unsigned char *buffer, size_t len,
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/src/ussd.c
^
|
@@ -515,6 +515,20 @@
ussd_change_state(ussd, new_state);
goto free;
+ } else if (ussd->state == USSD_STATE_USER_ACTION &&
+ status != OFONO_USSD_STATUS_ACTION_REQUIRED) {
+ ussd_change_state(ussd, USSD_STATE_IDLE);
+
+ if (status == OFONO_USSD_STATUS_NOTIFY && str && str[0]) {
+ const char *path = __ofono_atom_get_path(ussd->atom);
+
+ g_dbus_emit_signal(conn, path,
+ OFONO_SUPPLEMENTARY_SERVICES_INTERFACE,
+ "NotificationReceived", DBUS_TYPE_STRING,
+ &str, DBUS_TYPE_INVALID);
+ }
+
+ goto free;
} else {
ofono_error("Received an unsolicited USSD but can't handle.");
DBG("USSD is: status: %d, %s", status, str);
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/unit/coverage
^
|
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# Script to generate unit test coverage report, requires lcov:
+#
+# http://ltp.sourceforge.net/coverage/lcov.php
+#
+
+# Tests with coverage enabled:
+TESTS="\
+ test-common \
+ test-util \
+ test-idmap \
+ test-simutil \
+ test-stkutil \
+ test-sms \
+ test-cdmasms \
+ test-sms-root \
+ test-caif \
+ test-provision \
+ test-sailfish_manager \
+ test-sailfish_sim_info"
+
+pushd `dirname $0` > /dev/null
+TEST_DIR="$PWD"
+pushd .. > /dev/null
+BASE_DIR="$PWD"
+popd > /dev/null
+popd > /dev/null
+
+FULL_COV="$TEST_DIR/full.gcov"
+PLUGINS_COV="$TEST_DIR/plugins.gcov"
+SRC_COV="$TEST_DIR/src.gcov"
+OUT="$TEST_DIR/html"
+
+# Clean everything up
+find "$BASE_DIR" -name "*.gcda" -exec rm {} \;
+rm -f "$FULL_COV" "$PLUGINS_COV" "$SRC_COV"
+rm -fr "$OUT"
+
+# Run the tests
+for t in $TESTS ; do
+ pushd "$TEST_DIR" > /dev/null
+ "$TEST_DIR/$t"
+ RC=$?
+ popd > /dev/null
+ [ $RC = 0 ] || exit 1
+done
+
+# LCOV 1.10 has branch coverage disabled per default
+LCOV_OPT="--rc lcov_branch_coverage=1"
+GENHTML_OPT="--branch-coverage"
+
+lcov $LCOV_OPT -c -d "$BASE_DIR" -o "$FULL_COV" || exit 1
+lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/plugins/*" -o "$PLUGINS_COV" || exit 1
+lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/src/*" -o "$SRC_COV" || exit 1
+genhtml $GENHTML_OPT -t ofono "$PLUGINS_COV" "$SRC_COV" --output-directory "$OUT" || exit 1
+
+echo Coverage report: $OUT/index.html
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/unit/fake_sailfish_watch.c
^
|
@@ -0,0 +1,326 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "fake_sailfish_watch.h"
+
+#include <gutil_misc.h>
+#include <gutil_log.h>
+
+#include "ofono.h"
+
+typedef GObjectClass SailfishWatchClass;
+typedef struct sailfish_watch SailfishWatch;
+
+struct sailfish_watch_priv {
+ char *path;
+ char *iccid;
+ char *imsi;
+ char *spn;
+ int queued_signals;
+};
+
+#define SIGNAL_MODEM_CHANGED_NAME "sailfish-watch-modem-changed"
+#define SIGNAL_ONLINE_CHANGED_NAME "sailfish-watch-online-changed"
+#define SIGNAL_SIM_CHANGED_NAME "sailfish-watch-sim-changed"
+#define SIGNAL_SIM_STATE_CHANGED_NAME "sailfish-watch-sim-state-changed"
+#define SIGNAL_ICCID_CHANGED_NAME "sailfish-watch-iccid-changed"
+#define SIGNAL_IMSI_CHANGED_NAME "sailfish-watch-imsi-changed"
+#define SIGNAL_SPN_CHANGED_NAME "sailfish-watch-spn-changed"
+#define SIGNAL_NETREG_CHANGED_NAME "sailfish-watch-netreg-changed"
+
+static guint sailfish_watch_signals[WATCH_SIGNAL_COUNT] = { 0 };
+static GHashTable* sailfish_watch_table = NULL;
+
+G_DEFINE_TYPE(SailfishWatch, sailfish_watch, G_TYPE_OBJECT)
+#define SAILFISH_WATCH_TYPE (sailfish_watch_get_type())
+#define SAILFISH_WATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
+ SAILFISH_WATCH_TYPE, SailfishWatch))
+
+#define NEW_SIGNAL(klass,name) \
+ sailfish_watch_signals[WATCH_SIGNAL_##name##_CHANGED] = \
+ g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
+ G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
+ 0, NULL, NULL, NULL, G_TYPE_NONE, 0)
+
+#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
+
+static inline int sailfish_watch_signal_bit(enum sailfish_watch_signal id)
+{
+ return (1 << id);
+}
+
+static inline void sailfish_watch_signal_emit(struct sailfish_watch *self,
+ enum sailfish_watch_signal id)
+{
+ self->priv->queued_signals &= ~sailfish_watch_signal_bit(id);
+ g_signal_emit(self, sailfish_watch_signals[id], 0);
+}
+
+void fake_sailfish_watch_signal_queue(struct sailfish_watch *self,
+ enum sailfish_watch_signal id)
+{
+ self->priv->queued_signals |= sailfish_watch_signal_bit(id);
+}
+
+void fake_sailfish_watch_emit_queued_signals(struct sailfish_watch *self)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+ int i;
+
+ for (i = 0; priv->queued_signals && i < WATCH_SIGNAL_COUNT; i++) {
+ if (priv->queued_signals & sailfish_watch_signal_bit(i)) {
+ sailfish_watch_signal_emit(self, i);
+ }
+ }
+}
+
+void fake_sailfish_watch_set_ofono_iccid(struct sailfish_watch *self,
+ const char *iccid)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->iccid, iccid)) {
+ g_free(priv->iccid);
+ self->iccid = priv->iccid = g_strdup(iccid);
+ fake_sailfish_watch_signal_queue(self,
+ WATCH_SIGNAL_ICCID_CHANGED);
+ }
+}
+
+void fake_sailfish_watch_set_ofono_imsi(struct sailfish_watch *self,
+ const char *imsi)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->imsi, imsi)) {
+ g_free(priv->imsi);
+ self->imsi = priv->imsi = g_strdup(imsi);
+ fake_sailfish_watch_signal_queue(self,
+ WATCH_SIGNAL_IMSI_CHANGED);
+ }
+}
+
+void fake_sailfish_watch_set_ofono_spn(struct sailfish_watch *self,
+ const char *spn)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ if (g_strcmp0(priv->spn, spn)) {
+ g_free(priv->spn);
+ self->spn = priv->spn = g_strdup(spn);
+ fake_sailfish_watch_signal_queue(self,
+ WATCH_SIGNAL_SPN_CHANGED);
+ }
+}
+
+void fake_sailfish_watch_set_ofono_sim(struct sailfish_watch *self,
+ struct ofono_sim *sim)
+{
+ if (self->sim != sim) {
+ self->sim = sim;
+ fake_sailfish_watch_signal_queue(self,
+ WATCH_SIGNAL_SIM_CHANGED);
+ if (!sim) {
+ fake_sailfish_watch_set_ofono_iccid(self, NULL);
+ fake_sailfish_watch_set_ofono_imsi(self, NULL);
+ fake_sailfish_watch_set_ofono_spn(self, NULL);
+ }
+ }
+}
+
+void fake_sailfish_watch_set_ofono_netreg(struct sailfish_watch *self,
+ struct ofono_netreg *netreg)
+{
+ if (self->netreg != netreg) {
+ self->netreg = netreg;
+ fake_sailfish_watch_signal_queue(self,
+ WATCH_SIGNAL_NETREG_CHANGED);
+ }
+}
+
+static void sailfish_watch_initialize(struct sailfish_watch *self,
+ const char *path)
+{
+ struct sailfish_watch_priv *priv = self->priv;
+
+ self->path = priv->path = g_strdup(path);
+}
+
+static void sailfish_watch_destroyed(gpointer key, GObject* obj)
+{
+ GASSERT(sailfish_watch_table);
+ DBG("%s", (char*)key);
+ if (sailfish_watch_table) {
+ GASSERT(g_hash_table_lookup(sailfish_watch_table, key) == obj);
+ g_hash_table_remove(sailfish_watch_table, key);
+ if (g_hash_table_size(sailfish_watch_table) == 0) {
+ g_hash_table_unref(sailfish_watch_table);
+ sailfish_watch_table = NULL;
+ }
+ }
+}
+
+struct sailfish_watch *sailfish_watch_new(const char *path)
+{
+ struct sailfish_watch *watch = NULL;
+
+ if (path) {
+ if (sailfish_watch_table) {
+ watch = sailfish_watch_ref(g_hash_table_lookup(
+ sailfish_watch_table, path));
+ }
+ if (!watch) {
+ char* key = g_strdup(path);
+
+ watch = g_object_new(SAILFISH_WATCH_TYPE, NULL);
+ sailfish_watch_initialize(watch, path);
+ if (!sailfish_watch_table) {
+ /* Create the table on demand */
+ sailfish_watch_table =
+ g_hash_table_new_full(g_str_hash,
+ g_str_equal, g_free, NULL);
+ }
+ g_hash_table_replace(sailfish_watch_table, key, watch);
+ g_object_weak_ref(G_OBJECT(watch),
+ sailfish_watch_destroyed, key);
+ DBG_(watch, "created");
+ }
+ }
+ return watch;
+}
+
+struct sailfish_watch *sailfish_watch_ref(struct sailfish_watch *self)
+{
+ if (self) {
+ g_object_ref(SAILFISH_WATCH(self));
+ }
+ return self;
+}
+
+void sailfish_watch_unref(struct sailfish_watch *self)
+{
+ if (self) {
+ g_object_unref(SAILFISH_WATCH(self));
+ }
+}
+
+gulong sailfish_watch_add_modem_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_MODEM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_online_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_sim_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_SIM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_sim_state_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_SIM_STATE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_iccid_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_imsi_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_spn_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+gulong sailfish_watch_add_netreg_changed_handler(struct sailfish_watch *self,
+ sailfish_watch_cb_t cb, void *user_data)
+{
+ return (self && cb) ? g_signal_connect(self,
+ SIGNAL_NETREG_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
+}
+
+void sailfish_watch_remove_handler(struct sailfish_watch *self, gulong id)
+{
+ if (self && id) {
+ g_signal_handler_disconnect(self, id);
+ }
+}
+
+void sailfish_watch_remove_handlers(struct sailfish_watch *self, gulong *ids,
+ int count)
+{
+ gutil_disconnect_handlers(self, ids, count);
+}
+
+static void sailfish_watch_init(struct sailfish_watch *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SAILFISH_WATCH_TYPE,
+ struct sailfish_watch_priv);
+}
+
+static void sailfish_watch_finalize(GObject *object)
+{
+ struct sailfish_watch *self = SAILFISH_WATCH(object);
+ struct sailfish_watch_priv *priv = self->priv;
+
+ g_free(priv->path);
+ g_free(priv->iccid);
+ g_free(priv->imsi);
+ g_free(priv->spn);
+ G_OBJECT_CLASS(sailfish_watch_parent_class)->finalize(object);
+}
+
+static void sailfish_watch_class_init(SailfishWatchClass *klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = sailfish_watch_finalize;
+ g_type_class_add_private(klass, sizeof(struct sailfish_watch_priv));
+ NEW_SIGNAL(klass, MODEM);
+ NEW_SIGNAL(klass, ONLINE);
+ NEW_SIGNAL(klass, SIM);
+ NEW_SIGNAL(klass, SIM_STATE);
+ NEW_SIGNAL(klass, ICCID);
+ NEW_SIGNAL(klass, IMSI);
+ NEW_SIGNAL(klass, SPN);
+ NEW_SIGNAL(klass, NETREG);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/unit/fake_sailfish_watch.h
^
|
@@ -0,0 +1,55 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SAILFISH_FAKE_WATCH_H
+#define SAILFISH_FAKE_WATCH_H
+
+#include "sailfish_watch.h"
+
+enum sailfish_watch_signal {
+ WATCH_SIGNAL_MODEM_CHANGED,
+ WATCH_SIGNAL_ONLINE_CHANGED,
+ WATCH_SIGNAL_SIM_CHANGED,
+ WATCH_SIGNAL_SIM_STATE_CHANGED,
+ WATCH_SIGNAL_ICCID_CHANGED,
+ WATCH_SIGNAL_IMSI_CHANGED,
+ WATCH_SIGNAL_SPN_CHANGED,
+ WATCH_SIGNAL_NETREG_CHANGED,
+ WATCH_SIGNAL_COUNT
+};
+
+void fake_sailfish_watch_signal_queue(struct sailfish_watch *watch,
+ enum sailfish_watch_signal id);
+void fake_sailfish_watch_emit_queued_signals(struct sailfish_watch *watch);
+void fake_sailfish_watch_set_ofono_sim(struct sailfish_watch *watch,
+ struct ofono_sim *sim);
+void fake_sailfish_watch_set_ofono_iccid(struct sailfish_watch *watch,
+ const char *iccid);
+void fake_sailfish_watch_set_ofono_imsi(struct sailfish_watch *watch,
+ const char *imsi);
+void fake_sailfish_watch_set_ofono_spn(struct sailfish_watch *watch,
+ const char *spn);
+void fake_sailfish_watch_set_ofono_netreg(struct sailfish_watch *watch,
+ struct ofono_netreg *netreg);
+
+#endif /* FAKE_SAILFISH_WATCH_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/unit/test-provision.c
^
|
@@ -1,8 +1,7 @@
/*
- *
* oFono - Open Source Telephony
*
- * Copyright (C) 2014 Jolla. All rights reserved.
+ * Copyright (C) 2014-2017 Jolla. 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
@@ -12,11 +11,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#ifdef HAVE_CONFIG_H
@@ -24,76 +18,1106 @@
#endif
#include <glib.h>
-struct ofono_modem;
-#include <gprs-provision.h>
+#include <gio/gio.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include "ofono.h"
#include "plugins/mbpi.h"
#include "plugins/provision.h"
+#include <string.h>
-void get_and_print_settings(const char *mcc, const char *mnc,
- const char *spn)
-{
- struct ofono_gprs_provision_data *settings;
+#define TEST_SUITE "/provision/"
+
+extern struct ofono_plugin_desc __ofono_builtin_provision;
+
+struct provision_test_case {
+ const char *name;
+ const char *xml;
+ const char *mcc;
+ const char *mnc;
+ const char *spn;
+ const struct ofono_gprs_provision_data *settings;
int count;
- int i;
- provision_get_settings(mcc, mnc, spn, &settings, &count);
- g_print("Found %d contexts for (%s/%s/%s):\n", count, mcc, mnc, spn);
- for (i = 0; i < count; i++){
- struct ofono_gprs_provision_data ap = settings[i];
- g_print(" Name: %s\n", ap.name);
- g_print(" APN: %s\n", ap.apn);
- g_print(" Type: %s\n", mbpi_ap_type(ap.type));
- if (ap.username)
- g_print(" Username: %s\n", ap.username);
- if (ap.password)
- g_print(" Password: %s\n", ap.password);
- if (ap.message_proxy)
- g_print(" MMS proxy: %s\n", ap.message_proxy);
- if (ap.message_center)
- g_print(" MMS center: %s\n", ap.message_center);
- g_print("----------\n");
+};
+
+static GFile *test_write_tmp_file(const char* text, const char *suffix)
+{
+ char *tmpl = g_strconcat("provisionXXXXXX", suffix, NULL);
+ GFileIOStream *io = NULL;
+ GFile *file = g_file_new_tmp(tmpl, &io, NULL);
+ GOutputStream *out = g_io_stream_get_output_stream(G_IO_STREAM(io));
+ gsize len = strlen(text), nout;
+
+ g_assert(file);
+ g_assert(g_output_stream_write_all(out, text, len, &nout, NULL, NULL));
+ g_output_stream_close(out, NULL, NULL);
+ g_object_unref(io);
+ g_free(tmpl);
+
+ if (g_test_verbose()) {
+ char *path = g_file_get_path(file);
+
+ g_print("Created %s\n", path);
+ g_free(path);
}
+
+ return file;
+}
+
+static void test_provision(gconstpointer test_data)
+{
+ const struct provision_test_case *test = test_data;
+ struct ofono_gprs_provision_data *settings = NULL;
+ int i, count = 0;
+ GFile *file;
+ char *path;
+
+ if (test->xml) {
+ file = test_write_tmp_file(test->xml, ".xml");
+ path = g_file_get_path(file);
+ } else {
+ /*
+ * Create and delete a temporary file to end up
+ * with the path pointing to a non-existent file.
+ */
+ GFileIOStream *io = NULL;
+ file = g_file_new_tmp("provisionXXXXXX.xml", &io, NULL);
+ path = g_file_get_path(file);
+ g_file_delete(file, NULL, NULL);
+ g_object_unref(io);
+ g_object_unref(file);
+ file = NULL;
+ }
+
+ mbpi_database = path;
+ g_assert(__ofono_builtin_provision.init() == 0);
+
+ if (test->settings) {
+ g_assert(__ofono_gprs_provision_get_settings(test->mcc,
+ test->mnc, test->spn, &settings, &count));
+ g_assert(count == test->count);
+ for (i = 0; i < count; i++) {
+ const struct ofono_gprs_provision_data *actual =
+ settings + i;
+ const struct ofono_gprs_provision_data *expected =
+ test->settings + i;
+
+ g_assert(actual->type == expected->type);
+ g_assert(actual->proto == expected->proto);
+ g_assert(!g_strcmp0(actual->provider_name,
+ expected->provider_name));
+ g_assert(!g_strcmp0(actual->name, expected->name));
+ g_assert(actual->provider_primary ==
+ expected->provider_primary);
+ g_assert(!g_strcmp0(actual->apn, expected->apn));
+ g_assert(!g_strcmp0(actual->username,
+ expected->username));
+ g_assert(!g_strcmp0(actual->password,
+ expected->password));
+ g_assert(actual->auth_method == expected->auth_method);
+ g_assert(!g_strcmp0(actual->message_proxy,
+ expected->message_proxy));
+ g_assert(!g_strcmp0(actual->message_center,
+ expected->message_center));
+ }
+ } else {
+ g_assert(!__ofono_gprs_provision_get_settings(test->mcc,
+ test->mnc, test->spn, &settings, &count));
+ }
+
+ __ofono_gprs_provision_free_settings(settings, count);
+ __ofono_builtin_provision.exit();
+ if (file) {
+ g_file_delete(file, NULL, NULL);
+ g_object_unref(file);
+ }
+ g_free(path);
+}
+
+static void test_no_driver()
+{
+ struct ofono_gprs_provision_data *settings = NULL;
+ int count = 0;
+
+ g_assert(!__ofono_gprs_provision_get_settings("000", "01", NULL,
+ &settings, &count));
}
-static void test_get_settings(void)
+static void test_no_mcc_mnc()
{
- /* not in database */
- get_and_print_settings("999", "999", NULL);
+ struct ofono_gprs_provision_data *settings = NULL;
+ int count = 0;
- /* partial and case-insensitive matching */
- get_and_print_settings("244", "91", "sonera");
- get_and_print_settings("244", "91", "sONErA");
- get_and_print_settings("244", "91", "sone");
- get_and_print_settings("244", "91", "nera");
-
- /* related to Sonera/Finland network */
- get_and_print_settings("244", "91", NULL);
- get_and_print_settings("244", "91", "sonera");
- get_and_print_settings("244", "91", "aina");
-
- /* related to DNA/Finland network */
- get_and_print_settings("244", "03", NULL);
- get_and_print_settings("244", "03", "dna");
- get_and_print_settings("244", "03", "aina");
- get_and_print_settings("244", "04", NULL);
- get_and_print_settings("244", "04", "dna");
- get_and_print_settings("244", "04", "aina");
-
- /* related to O2/UK network */
- get_and_print_settings("234", "10", NULL);
- get_and_print_settings("234", "10", "o2");
- get_and_print_settings("234", "10", "tesco");
- get_and_print_settings("234", "10", "giffgaff");
-
- /* related to E-Plus/Germany network */
- get_and_print_settings("262", "03", NULL);
- get_and_print_settings("262", "03", "E-Plus");
- get_and_print_settings("262", "03", "simyo");
+ g_assert(__ofono_builtin_provision.init() == 0);
+ g_assert(!__ofono_gprs_provision_get_settings(NULL, NULL, NULL,
+ &settings, &count));
+ g_assert(!__ofono_gprs_provision_get_settings("", NULL, NULL,
+ &settings, &count));
+ g_assert(!__ofono_gprs_provision_get_settings("123", NULL, NULL,
+ &settings, &count));
+ g_assert(!__ofono_gprs_provision_get_settings("123", "", NULL,
+ &settings, &count));
+ __ofono_builtin_provision.exit();
}
+static char telia_fi_provider_name [] = "Telia FI";
+static char telia_fi_name_internet [] = "Telia Internet";
+static char telia_fi_name_mms [] = "Telia MMS";
+static char telia_fi_apn_internet [] = "internet";
+static char telia_fi_apn_mms [] = "mms";
+static char telia_fi_message_proxy [] = "195.156.25.33:8080";
+static char telia_fi_message_center [] = "http://mms/";
+
+static const struct ofono_gprs_provision_data telia_fi_internet_mms_p[] = {
+ {
+ .type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
+ .proto = OFONO_GPRS_PROTO_IPV4V6,
+ .provider_name = telia_fi_provider_name,
+ .provider_primary = TRUE,
+ .name = telia_fi_name_internet,
+ .apn = telia_fi_apn_internet,
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
+ }, {
+ .type = OFONO_GPRS_CONTEXT_TYPE_MMS,
+ .proto = OFONO_GPRS_PROTO_IP,
+ .provider_name = telia_fi_provider_name,
+ .provider_primary = TRUE,
+ .name = telia_fi_name_mms,
+ .apn = telia_fi_apn_mms,
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE,
+ .message_proxy = telia_fi_message_proxy,
+ .message_center = telia_fi_message_center
+ }
+};
+
+static const struct ofono_gprs_provision_data telia_fi_internet_mms[] = {
+ {
+ .type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
+ .proto = OFONO_GPRS_PROTO_IPV4V6,
+ .provider_name = telia_fi_provider_name,
+ .name = telia_fi_name_internet,
+ .apn = telia_fi_apn_internet,
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
+ }, {
+ .type = OFONO_GPRS_CONTEXT_TYPE_MMS,
+ .proto = OFONO_GPRS_PROTO_IP,
+ .provider_name = telia_fi_provider_name,
+ .name = telia_fi_name_mms,
+ .apn = telia_fi_apn_mms,
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE,
+ .message_proxy = telia_fi_message_proxy,
+ .message_center = telia_fi_message_center
+ }
+};
+
+static const struct ofono_gprs_provision_data telia_fi_internet[] = {
+ {
+ .type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
+ .proto = OFONO_GPRS_PROTO_IPV4V6,
+ .provider_name = telia_fi_provider_name,
+ .name = telia_fi_name_internet,
+ .apn = telia_fi_apn_internet,
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
+ }, { /* Default MMS settings: */
+ .type = OFONO_GPRS_CONTEXT_TYPE_MMS,
+ .proto = OFONO_GPRS_PROTO_IP,
+ .name = "MMS",
+ .apn = "mms",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
+ }
+};
+
+static const struct ofono_gprs_provision_data telia_fi_mms[] = {
+ { /* Default Internet settings: */
+ .type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
+ .proto = OFONO_GPRS_PROTO_IPV4V6,
+ .name = "Internet",
+ .apn = "internet",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
+ }, {
+ .type = OFONO_GPRS_CONTEXT_TYPE_MMS,
+ .proto = OFONO_GPRS_PROTO_IP,
+ .provider_name = telia_fi_provider_name,
+ .name = telia_fi_name_mms,
+ .apn = telia_fi_apn_mms,
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE,
+ .message_proxy = telia_fi_message_proxy,
+ .message_center = telia_fi_message_center
+ }
+};
+
+static const struct ofono_gprs_provision_data default_settings[] = {
+ { /* Default Internet settings: */
+ .type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
+ .proto = OFONO_GPRS_PROTO_IPV4V6,
+ .name = "Internet",
+ .apn = "internet",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
+ }, { /* Default MMS settings: */
+ .type = OFONO_GPRS_CONTEXT_TYPE_MMS,
+ .proto = OFONO_GPRS_PROTO_IP,
+ .name = "MMS",
+ .apn = "mms",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
+ }
+};
+
+static const struct ofono_gprs_provision_data no_auth_settings[] = {
+ {
+ .type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
+ .proto = OFONO_GPRS_PROTO_IPV4V6,
+ .name = "Internet",
+ .apn = "internet",
+ .username = "",
+ .password = "",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
+ }, {
+ .type = OFONO_GPRS_CONTEXT_TYPE_MMS,
+ .proto = OFONO_GPRS_PROTO_IP,
+ .name = "MMS",
+ .apn = "mms",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_NONE
+ }
+};
+
+static const struct ofono_gprs_provision_data auth_settings[] = {
+ {
+ .type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
+ .proto = OFONO_GPRS_PROTO_IPV4V6,
+ .name = "Internet",
+ .apn = "internet",
+ .username = "username",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_ANY
+ }, {
+ .type = OFONO_GPRS_CONTEXT_TYPE_MMS,
+ .proto = OFONO_GPRS_PROTO_IP,
+ .name = "MMS",
+ .apn = "mms",
+ .password = "password",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_ANY
+ }
+};
+
+static char test_provider_name[] = "Test provider";
+static char test_message_proxy[] = "192.168.0.1:8888";
+static char test_message_center[] = "http://mms/";
+static const struct ofono_gprs_provision_data test_username_password[] = {
+ {
+ .type = OFONO_GPRS_CONTEXT_TYPE_INTERNET,
+ .proto = OFONO_GPRS_PROTO_IPV4V6,
+ .provider_name = test_provider_name,
+ .name = "Test Internet",
+ .apn = "test.internet.1",
+ .username = "username",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_PAP
+ }, {
+ .type = OFONO_GPRS_CONTEXT_TYPE_MMS,
+ .proto = OFONO_GPRS_PROTO_IP,
+ .provider_name = test_provider_name,
+ .name = "Test MMS",
+ .apn = "test.mms",
+ .username = "username",
+ .password = "password",
+ .auth_method = OFONO_GPRS_AUTH_METHOD_CHAP,
+ .message_proxy = test_message_proxy,
+ .message_center = test_message_center
+ }
+};
+
+static const char telia_fi_internet_xml[] =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider>\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n";
+
+static const struct provision_test_case test_cases[] = {
+ {
+ .name = TEST_SUITE "no_file",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "primary_both",
+ /* Both providers primaries, the first one is taken */
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider primary=\"true\">\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+ <provider primary=\"true\">\n\
+ <name>Other provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"other.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Other Internet</name>\n\
+ </apn>\n\
+ <apn value=\"other.mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Other MMS</name>\n\
+ <mmsc>http://mms</mmsc>\n\
+ <mmsproxy>192.168.0.1</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .spn = "Doesn't match",
+ .settings = telia_fi_internet_mms_p,
+ .count = G_N_ELEMENTS(telia_fi_internet_mms_p)
+ },{
+ .name = TEST_SUITE "primary_match1",
+ /* The first provider is primary, the second one is not: */
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider primary=\"true\">\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+ <provider>\n\
+ <name>Other provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"other.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Other Internet</name>\n\
+ </apn>\n\
+ <apn value=\"other.mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Other MMS</name>\n\
+ <mmsc>http://mms</mmsc>\n\
+ <mmsproxy>192.168.0.1</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .settings = telia_fi_internet_mms_p,
+ .count = G_N_ELEMENTS(telia_fi_internet_mms_p)
+ },{
+ .name = TEST_SUITE "primary_match2",
+ /* The second provider is primary, the first one is not */
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider>\n\
+ <name>Other provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"other.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Other Internet</name>\n\
+ </apn>\n\
+ <apn value=\"other.mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Other MMS</name>\n\
+ <mmsc>http://mms</mmsc>\n\
+ <mmsproxy>192.168.0.1</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+ <provider primary=\"true\">\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .settings = telia_fi_internet_mms_p,
+ .count = G_N_ELEMENTS(telia_fi_internet_mms_p)
+ },{
+ .name = TEST_SUITE "spn_match1",
+ /* The first provider matches, the second one doesn't */
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider>\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+ <provider>\n\
+ <name>Other provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"other.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Other Internet</name>\n\
+ </apn>\n\
+ <apn value=\"other.mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Other MMS</name>\n\
+ <mmsc>http://mms</mmsc>\n\
+ <mmsproxy>192.168.0.1</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .spn = "Telia FI",
+ .settings = telia_fi_internet_mms,
+ .count = G_N_ELEMENTS(telia_fi_internet_mms)
+ },{
+ .name = TEST_SUITE "spn_match2",
+ /* The first provider doesn't match, the second one does */
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider>\n\
+ <name>Other provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"other.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Other Internet</name>\n\
+ </apn>\n\
+ <apn value=\"other.mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Other MMS</name>\n\
+ <mmsc>http://mms</mmsc>\n\
+ <mmsproxy>192.168.0.1</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+ <provider>\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .spn = "Telia FI",
+ .settings = telia_fi_internet_mms,
+ .count = G_N_ELEMENTS(telia_fi_internet_mms)
+ },{
+ .name = TEST_SUITE "spn_match_case",
+ /* Case insensitive match */
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider>\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+ <provider>\n\
+ <name>Other provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"other.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Other Internet</name>\n\
+ </apn>\n\
+ <apn value=\"other.mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Other MMS</name>\n\
+ <mmsc>http://mms</mmsc>\n\
+ <mmsproxy>192.168.0.1</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .spn = "telia fi",
+ .settings = telia_fi_internet_mms,
+ .count = G_N_ELEMENTS(telia_fi_internet_mms)
+ },{
+ .name = TEST_SUITE "spn_partial_unnamed",
+ /* The second provider matches partially, first has no name */
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"other.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Other Internet</name>\n\
+ </apn>\n\
+ <apn value=\"other.mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Other MMS</name>\n\
+ <mmsc>http://mms</mmsc>\n\
+ <mmsproxy>192.168.0.1</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+ <provider>\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .spn = "Telia",
+ .settings = telia_fi_internet_mms,
+ .count = G_N_ELEMENTS(telia_fi_internet_mms)
+ },{
+ .name = TEST_SUITE "internet_mms_primary",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider primary=\"true\">\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .spn = "Telia FI",
+ .settings = telia_fi_internet_mms_p,
+ .count = G_N_ELEMENTS(telia_fi_internet_mms_p)
+ },{
+ .name = TEST_SUITE "internet_mms",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider>\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Telia Internet</name>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .spn = "Telia FI",
+ .settings = telia_fi_internet_mms,
+ .count = G_N_ELEMENTS(telia_fi_internet_mms)
+ },{
+ .name = TEST_SUITE "internet",
+ .xml = telia_fi_internet_xml,
+ .mcc = "244",
+ .mnc = "91",
+ .settings = telia_fi_internet,
+ .count = G_N_ELEMENTS(telia_fi_internet)
+ },{
+ .name = TEST_SUITE "mms",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider>\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Telia MMS</name>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>195.156.25.33:8080</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .settings = telia_fi_mms,
+ .count = G_N_ELEMENTS(telia_fi_mms)
+ },{
+ .name = TEST_SUITE "not_found_mcc",
+ .xml = telia_fi_internet_xml,
+ .mcc = "245", /* Wrong MCC */
+ .mnc = "91",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "not_found_mnc",
+ .xml = telia_fi_internet_xml,
+ .mcc = "244",
+ .mnc = "90", /* Wrong MNC */
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "apn_error",
+ .xml = "<serviceproviders format=\"2.0\">\n\
+<country code=\"fi\">\n\
+ <provider>\n\
+ <name>Telia FI</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"244\" mnc=\"91\"/>\n\
+ <apn value=\"mms\">\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "244",
+ .mnc = "91",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "username_password",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"45\"/>\n\
+ <apn value=\"test.internet.1\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Test Internet</name>\n\
+ <authentication method=\"pap\"/>\n\
+ <username>username</username>\n\
+ </apn>\n\
+ <apn value=\"test.internet.2\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Test Internet</name>\n\
+ <authentication method=\"any\"/>\n\
+ <password>password</password>\n\
+ <garbage/>\n\
+ </apn>\n\
+ <apn value=\"test.mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Test MMS</name>\n\
+ <authentication method=\"chap\"/>\n\
+ <username>username</username>\n\
+ <password>password</password>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>192.168.0.1:8888</mmsproxy>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "45",
+ .spn = test_provider_name,
+ .settings = test_username_password,
+ .count = G_N_ELEMENTS(test_username_password)
+ },{
+ .name = TEST_SUITE "no_auth",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"45\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Internet</name>\n\
+ <username></username>\n\
+ <password></password>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>MMS</name>\n\
+ <authentication method=\"none\"/>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "45",
+ .settings = no_auth_settings,
+ .count = G_N_ELEMENTS(no_auth_settings)
+ },{
+ .name = TEST_SUITE "auth",
+ .xml = /* With username and password auth defaults to ANY */
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"45\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Internet</name>\n\
+ <username>username</username>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>MMS</name>\n\
+ <password>password</password>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "45",
+ .settings = auth_settings,
+ .count = G_N_ELEMENTS(auth_settings)
+ },{
+ .name = TEST_SUITE "duplicate_network",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"45\"/>\n\
+ <apn value=\"test.internet.1\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Test Internet</name>\n\
+ <authentication method=\"pap\"/>\n\
+ <username>username</username>\n\
+ </apn>\n\
+ <apn value=\"test.mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>Test MMS</name>\n\
+ <authentication method=\"chap\"/>\n\
+ <username>username</username>\n\
+ <password>password</password>\n\
+ <mmsc>http://mms/</mmsc>\n\
+ <mmsproxy>192.168.0.1:8888</mmsproxy>\n\
+ </apn>\n\
+ <network-id mcc=\"123\" mnc=\"45\"/>\n\
+ <apn value=\"test.internet.2\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Test Internet</name>\n\
+ <authentication method=\"any\"/>\n\
+ <password>password</password>\n\
+ <garbage/>\n\
+ </apn>\n\
+ <apn value=\"test.wap\">\n\
+ <usage type=\"wap\"/>\n\
+ </apn>\n\
+ <garbage/>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "45",
+ .spn = test_provider_name,
+ .settings = test_username_password,
+ .count = G_N_ELEMENTS(test_username_password)
+ },{
+ .name = TEST_SUITE "missing_mcc",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <gsm>\n\
+ <network-id mnc=\"34\"/>\n\
+ <apn value=\"test.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Test Internet</name>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "missing_mnc",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\"/>\n\
+ <apn value=\"test.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Test Internet</name>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "missing_auth_method",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"34\"/>\n\
+ <apn value=\"test.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Test Internet</name>\n\
+ <authentication garbage=\"junk\"/>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "invalid_auth_method",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"34\"/>\n\
+ <apn value=\"test.internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Test Internet</name>\n\
+ <authentication method=\"invalid\"/>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "missing_usage_type",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"34\"/>\n\
+ <apn value=\"test.internet\">\n\
+ <usage garbage=\"junk\"/>\n\
+ <name>Test Internet</name>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "invalid_usage_type",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"34\"/>\n\
+ <apn value=\"test.internet\">\n\
+ <usage type=\"invalid\"/>\n\
+ <name>Test Internet</name>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "missing_apn_value",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"34\"/>\n\
+ <apn garbage=\"junk\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Test Internet</name>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "missing_gsm",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <name>Test provider</name>\n\
+ <whatever/>\n\
+ </provider>\n\
+</country>\n\
+</serviceproviders>\n",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ },{
+ .name = TEST_SUITE "invalid_xml",
+ .xml =
+"<serviceproviders format=\"2.0\">\n\
+<country code=\"xx\">\n\
+ <provider>\n\
+ <gsm>\n\
+ <network-id mcc=\"123\" mnc=\"45\"/>\n\
+ <apn value=\"internet\">\n\
+ <usage type=\"internet\"/>\n\
+ <name>Internet</name>\n\
+ <authentication method=\"none\"/>\n\
+ </apn>\n\
+ <apn value=\"mms\">\n\
+ <usage type=\"mms\"/>\n\
+ <name>MMS</name>\n\
+ <authentication method=\"none\"/>\n\
+ </apn>\n\
+ </gsm>\n\
+ </provider>\n\
+</country>\n\
+</se",
+ .mcc = "123",
+ .mnc = "34",
+ .settings = default_settings,
+ .count = G_N_ELEMENTS(default_settings)
+ }
+};
+
int main(int argc, char **argv)
{
+ guint i;
+
g_test_init(&argc, &argv, NULL);
- g_test_add_func("/testprovision/get_settings", test_get_settings);
+ g_test_add_func(TEST_SUITE "no_driver", test_no_driver);
+ g_test_add_func(TEST_SUITE "no_mcc_mnc", test_no_mcc_mnc);
+ for (i = 0; i < G_N_ELEMENTS(test_cases); i++) {
+ const struct provision_test_case *test = test_cases + i;
+ g_test_add_data_func(test->name, test, test_provision);
+ }
return g_test_run();
}
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/unit/test-sailfish_manager.c
^
|
@@ -0,0 +1,1377 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <sailfish_manager.h>
+#include "sailfish_sim_info.h"
+#include "sailfish_manager_dbus.h"
+#include "fake_sailfish_watch.h"
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include "ofono.h"
+
+#include <gutil_log.h>
+#include <gutil_strv.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define TEST_TIMEOUT_SEC (20)
+#define TEST_IDLE_WAIT_COUNT (10) /* Should be > SF_INIT_IDLE_COUNT */
+#define TEST_PATH "/test_0"
+#define TEST_PATH_1 "/test_1"
+#define TEST_ICCID "1111111111111111111"
+#define TEST_ICCID_1 "1111111111111111112"
+#define TEST_IMEI "222222222222222"
+#define TEST_IMEI_1 "222222222222223"
+#define TEST_IMEISV "33"
+#define TEST_IMSI "244120000000000"
+#define TEST_IMSI_1 "244120000000001"
+#define TEST_MCC "244"
+#define TEST_MNC "12"
+#define TEST_SPN "Test"
+#define TEST_ERROR_KEY "Error"
+#define TEST_SLOT_ERROR_KEY "SlotError"
+
+extern struct ofono_plugin_desc __ofono_builtin_sailfish_manager;
+static GMainLoop *test_loop = NULL;
+static guint test_timeout_id = 0;
+
+/* Fake ofono_modem */
+
+struct ofono_modem {
+ int unused;
+};
+
+/* Fake ofono_sim */
+
+struct ofono_sim {
+ const char *mcc;
+ const char *mnc;
+ enum ofono_sim_state state;
+};
+
+enum ofono_sim_state ofono_sim_get_state(struct ofono_sim *sim)
+{
+ return sim ? sim->state : OFONO_SIM_STATE_NOT_PRESENT;
+}
+
+const char *ofono_sim_get_mcc(struct ofono_sim *sim)
+{
+ return sim ? sim->mcc : NULL;
+}
+
+const char *ofono_sim_get_mnc(struct ofono_sim *sim)
+{
+ return sim ? sim->mnc : NULL;
+}
+
+/* Fake ofono_netreg */
+
+struct ofono_netreg {
+ const char *mcc;
+ const char *mnc;
+ const char *name;
+ int status;
+};
+
+int ofono_netreg_get_status(struct ofono_netreg *netreg)
+{
+ return netreg ? netreg->status : -1;
+}
+
+const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg)
+{
+ return netreg ? netreg->mcc : NULL;
+}
+
+const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg)
+{
+ return netreg ? netreg->mnc : NULL;
+}
+
+const char *ofono_netreg_get_name(struct ofono_netreg *netreg)
+{
+ return netreg ? netreg->name : NULL;
+}
+
+unsigned int __ofono_netreg_add_status_watch(struct ofono_netreg *netreg,
+ ofono_netreg_status_notify_cb_t notify,
+ void *data, ofono_destroy_func destroy)
+{
+ return 1;
+}
+
+gboolean __ofono_netreg_remove_status_watch(struct ofono_netreg *netreg,
+ unsigned int id)
+{
+ return TRUE;
+}
+
+/* Fake sailfish_manager_dbus */
+
+static struct sailfish_manager_dbus {
+ struct sailfish_manager *m;
+ struct sailfish_manager_dbus_cb cb;
+ enum sailfish_manager_dbus_block block;
+ void (*fn_block_changed)(struct sailfish_manager_dbus *d);
+ int signals;
+} fake_sailfish_manager_dbus;
+
+struct sailfish_manager_dbus *sailfish_manager_dbus_new
+ (struct sailfish_manager *m,
+ const struct sailfish_manager_dbus_cb *cb)
+{
+ memset(&fake_sailfish_manager_dbus, 0,
+ sizeof(fake_sailfish_manager_dbus));
+ fake_sailfish_manager_dbus.m = m;
+ fake_sailfish_manager_dbus.cb = *cb;
+ return &fake_sailfish_manager_dbus;
+}
+
+void sailfish_manager_dbus_free(struct sailfish_manager_dbus *d)
+{
+ g_assert(d == &fake_sailfish_manager_dbus);
+ g_assert(fake_sailfish_manager_dbus.m);
+ memset(&fake_sailfish_manager_dbus, 0,
+ sizeof(fake_sailfish_manager_dbus));
+}
+
+void sailfish_manager_dbus_set_block(struct sailfish_manager_dbus *d,
+ enum sailfish_manager_dbus_block b)
+{
+ if (d->block != b) {
+ DBG("0x%02x", (int)b);
+ d->block = b;
+ if (d->fn_block_changed) {
+ d->fn_block_changed(d);
+ }
+ }
+}
+void sailfish_manager_dbus_signal(struct sailfish_manager_dbus *d,
+ enum sailfish_manager_dbus_signal m)
+{
+ d->signals |= m;
+}
+
+void sailfish_manager_dbus_signal_sim(struct sailfish_manager_dbus *d,
+ int index, gboolean present) {}
+void sailfish_manager_dbus_signal_error(struct sailfish_manager_dbus *d,
+ const char *id, const char *message) {}
+void sailfish_manager_dbus_signal_modem_error(struct sailfish_manager_dbus *d,
+ int index, const char *id, const char *msg) {}
+
+/* Fake sailfish_sim_info_dbus */
+
+struct sailfish_sim_info_dbus {
+ int unused;
+};
+
+struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new
+ (struct sailfish_sim_info *info)
+{
+ static struct sailfish_sim_info_dbus fake_sailfish_sim_info_dbus;
+ return &fake_sailfish_sim_info_dbus;
+}
+
+void sailfish_sim_info_dbus_free(struct sailfish_sim_info_dbus *dbus) {}
+
+/* Code shared by all tests */
+
+typedef struct sailfish_slot_impl {
+ struct sailfish_slot *handle;
+ enum sailfish_data_role data_role;
+ int enabled_changed;
+} test_slot;
+
+typedef struct sailfish_slot_manager_impl {
+ struct sailfish_slot_manager *handle;
+ test_slot *slot;
+ test_slot *slot2;
+ int counter;
+} test_slot_manager;
+
+static int rmdir_r(const char *path)
+{
+ DIR *d = opendir(path);
+
+ if (d) {
+ const struct dirent *p;
+ int r = 0;
+
+ while (!r && (p = readdir(d))) {
+ char *buf;
+ struct stat st;
+
+ if (!strcmp(p->d_name, ".") ||
+ !strcmp(p->d_name, "..")) {
+ continue;
+ }
+
+ buf = g_strdup_printf("%s/%s", path, p->d_name);
+ if (!stat(buf, &st)) {
+ r = S_ISDIR(st.st_mode) ? rmdir_r(buf) :
+ unlink(buf);
+ }
+ g_free(buf);
+ }
+ closedir(d);
+ return r ? r : rmdir(path);
+ } else {
+ return -1;
+ }
+}
+
+static gboolean test_timeout_cb(gpointer user_data)
+{
+ ofono_error("Timeout!");
+ g_main_loop_quit(test_loop);
+ test_timeout_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+static void test_quit_loop_when_unblocked(struct sailfish_manager_dbus *d)
+{
+ if (d->block == SAILFISH_MANAGER_DBUS_BLOCK_NONE) {
+ g_main_loop_quit(test_loop);
+ }
+}
+
+static void test_common_init()
+{
+ rmdir_r(STORAGEDIR);
+ __ofono_builtin_sailfish_manager.init();
+ test_loop = g_main_loop_new(NULL, FALSE);
+ test_timeout_id = g_timeout_add_seconds(TEST_TIMEOUT_SEC,
+ test_timeout_cb, NULL);
+}
+
+static void test_common_deinit()
+{
+ __ofono_builtin_sailfish_manager.exit();
+ g_assert(test_timeout_id);
+ g_source_remove(test_timeout_id);
+ g_main_loop_unref(test_loop);
+ test_timeout_id = 0;
+ test_loop = NULL;
+}
+
+static gboolean test_done_cb(gpointer user_data)
+{
+ g_main_loop_quit(test_loop);
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean test_done_when_zero(gpointer user_data)
+{
+ int* count = user_data;
+
+ if (*count > 0) {
+ (*count)--;
+ return G_SOURCE_CONTINUE;
+ } else {
+ g_main_loop_quit(test_loop);
+ return G_SOURCE_REMOVE;
+ }
+}
+
+static test_slot_manager *test_slot_manager_create
+ (struct sailfish_slot_manager *handle)
+{
+ test_slot_manager *sm = g_new0(test_slot_manager, 1);
+
+ DBG("");
+ sm->handle = handle;
+ return sm;
+}
+
+static void test_slot_manager_free(test_slot_manager *sm)
+{
+ g_free(sm);
+}
+
+static void test_slot_enabled_changed(test_slot *s)
+{
+ s->enabled_changed++;
+}
+
+static void test_slot_set_data_role(test_slot *s, enum sailfish_data_role role)
+{
+ s->data_role = role;
+}
+
+static void test_slot_free(test_slot *s)
+{
+ g_free(s);
+}
+
+static void test_slot_manager_count_cb(test_slot_manager *sm, void *user_data)
+{
+ (*((int *)user_data))++;
+}
+
+/* Test cases */
+
+/* ==== basic ==== */
+
+static void test_basic(void)
+{
+ static const struct sailfish_slot_driver dummy1 = {
+ .name = "Dummy1",
+ .priority = 1
+ };
+ static const struct sailfish_slot_driver dummy2 = { .name = "Dummy2" };
+ static const struct sailfish_slot_driver dummy3 = { .name = "Dummy3" };
+ static const struct sailfish_slot_driver dummy4 = { .name = "Dummy4" };
+ struct sailfish_slot_driver_reg *r1, *r2, *r3, *r4;
+ int count = 0;
+
+ test_common_init();
+
+ /* NULL resistance */
+ g_assert(!sailfish_slot_driver_register(NULL));
+ sailfish_slot_driver_unregister(NULL);
+ sailfish_manager_foreach_slot_manager(NULL, NULL, NULL);
+ sailfish_manager_imei_obtained(NULL, NULL);
+ sailfish_manager_imeisv_obtained(NULL, NULL);
+ sailfish_manager_set_sim_state(NULL, SAILFISH_SIM_STATE_UNKNOWN);
+ sailfish_manager_slot_error(NULL, NULL, NULL);
+ sailfish_manager_error(NULL, NULL, NULL);
+
+ /* Register dummy driver */
+ g_assert((r2 = sailfish_slot_driver_register(&dummy2)));
+ g_assert((r1 = sailfish_slot_driver_register(&dummy1)));
+ g_assert((r4 = sailfish_slot_driver_register(&dummy4)));
+ g_assert((r3 = sailfish_slot_driver_register(&dummy3)));
+ sailfish_manager_foreach_slot_manager(r1, NULL, &count);
+ g_assert(!count);
+ sailfish_manager_foreach_slot_manager(r1,
+ test_slot_manager_count_cb, &count);
+ g_assert(!count);
+
+ /* Run the main loop to make sure that sailfish_manager handles
+ * drivers without manager_start callback (even though it makes
+ * little or no sense). */
+ count = 1;
+ g_idle_add(test_done_when_zero, &count);
+ g_main_loop_run(test_loop);
+
+ sailfish_slot_driver_unregister(r3);
+ sailfish_slot_driver_unregister(r4);
+ sailfish_slot_driver_unregister(r2);
+ sailfish_slot_driver_unregister(r1);
+
+ /* This one will get destroyed by sailfish_manager_exit */
+ g_assert(sailfish_slot_driver_register(&dummy1));
+ test_common_deinit();
+
+ /* Double exit is fine */
+ __ofono_builtin_sailfish_manager.exit();
+}
+
+/* ==== early_init ==== */
+
+static guint test_early_init_start(test_slot_manager *sm)
+{
+ DBG("");
+ g_main_loop_quit(test_loop);
+ return 0;
+}
+
+static void test_early_init(void)
+{
+ static const struct sailfish_slot_driver early_init_driver = {
+ .name = "early_init",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_early_init_start,
+ .manager_free = test_slot_manager_free
+ };
+ struct sailfish_slot_driver_reg *reg;
+ int count = 0;
+
+ /* Register before sailfish_manager_init */
+ g_assert((reg = sailfish_slot_driver_register(&early_init_driver)));
+
+ test_common_init();
+ g_main_loop_run(test_loop);
+ sailfish_manager_foreach_slot_manager(reg,
+ test_slot_manager_count_cb, &count);
+ g_assert(count == 1);
+ test_common_deinit();
+}
+
+/* ==== too_late ==== */
+
+static gboolean test_too_late_cb(gpointer user_data)
+{
+ guint* counter = user_data;
+
+ (*counter)--;
+ DBG("%u", *counter);
+ if (!(*counter)) {
+ static const struct sailfish_slot_driver too_late_driver = {
+ .name = "too_late",
+ .manager_create = test_slot_manager_create,
+ };
+
+ g_assert(!sailfish_slot_driver_register(&too_late_driver));
+ g_assert(fake_sailfish_manager_dbus.block ==
+ SAILFISH_MANAGER_DBUS_BLOCK_NONE);
+ g_main_loop_quit(test_loop);
+ return G_SOURCE_REMOVE;
+ } else {
+ return G_SOURCE_CONTINUE;
+ }
+}
+
+static void test_too_late(void)
+{
+ guint counter = TEST_IDLE_WAIT_COUNT;
+
+ test_common_init();
+ g_idle_add(test_too_late_cb, &counter);
+ g_main_loop_run(test_loop);
+
+ g_assert(!counter);
+ test_common_deinit();
+}
+
+/* ==== create_fail ==== */
+
+static test_slot_manager *test_create_fail_manager_create
+ (struct sailfish_slot_manager *m)
+{
+ DBG("");
+ g_main_loop_quit(test_loop);
+ return NULL;
+}
+
+static void test_create_fail(void)
+{
+ static const struct sailfish_slot_driver create_fail_driver = {
+ .name = "create_fail",
+ .manager_create = test_create_fail_manager_create,
+ };
+ struct sailfish_slot_driver_reg *reg;
+ int count = 0;
+
+ test_common_init();
+ g_assert((reg = sailfish_slot_driver_register(&create_fail_driver)));
+ g_main_loop_run(test_loop);
+ sailfish_manager_foreach_slot_manager(reg,
+ test_slot_manager_count_cb, &count);
+ g_assert(!count);
+ test_common_deinit();
+}
+
+/* ==== no_slots ==== */
+
+static guint test_no_slots_start(test_slot_manager *sm)
+{
+ DBG("");
+ g_main_loop_quit(test_loop);
+ return 0;
+}
+
+static void test_no_slots(void)
+{
+ static const struct sailfish_slot_driver no_slots_driver = {
+ .name = "no_slots",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_no_slots_start,
+ .manager_free = test_slot_manager_free
+ };
+
+ test_common_init();
+ g_assert(sailfish_slot_driver_register(&no_slots_driver));
+ g_main_loop_run(test_loop);
+ g_assert(fake_sailfish_manager_dbus.m);
+ g_assert(fake_sailfish_manager_dbus.m->ready);
+
+ test_common_deinit();
+}
+
+/* ==== sync_start ==== */
+
+static gboolean test_sync_start_done(gpointer user_data)
+{
+ test_slot_manager *sm = user_data;
+ test_slot *s = sm->slot;
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+ char **slots;
+ GHashTable *errors;
+
+ g_assert(m);
+
+ /* Poke error counters */
+ sailfish_manager_error(sm->handle, TEST_ERROR_KEY, "Aaah!");
+ sailfish_manager_slot_error(s->handle, TEST_SLOT_ERROR_KEY, "Aaah!");
+
+ errors = fake_sailfish_manager_dbus.cb.get_errors(m);
+ g_assert(g_hash_table_size(errors) == 1);
+ g_assert(GPOINTER_TO_INT(g_hash_table_lookup(errors,
+ TEST_ERROR_KEY)) == 1);
+
+ errors = fake_sailfish_manager_dbus.cb.get_slot_errors(s->handle);
+ g_assert(g_hash_table_size(errors) == 1);
+ g_assert(GPOINTER_TO_INT(g_hash_table_lookup(errors,
+ TEST_SLOT_ERROR_KEY)) == 1);
+
+ sailfish_manager_error(sm->handle, TEST_ERROR_KEY, "Aaah!");
+ sailfish_manager_slot_error(s->handle, TEST_SLOT_ERROR_KEY, "Aaah!");
+
+ errors = fake_sailfish_manager_dbus.cb.
+ get_errors(fake_sailfish_manager_dbus.m);
+ g_assert(g_hash_table_size(errors) == 1);
+ g_assert(GPOINTER_TO_INT(g_hash_table_lookup(errors,
+ TEST_ERROR_KEY)) == 2);
+
+ errors = fake_sailfish_manager_dbus.cb.get_slot_errors(s->handle);
+ g_assert(g_hash_table_size(errors) == 1);
+ g_assert(GPOINTER_TO_INT(g_hash_table_lookup(errors,
+ TEST_SLOT_ERROR_KEY)) == 2);
+
+ /* Enable/disable slots */
+ g_assert(m->slots[0]);
+ g_assert(!g_strcmp0(m->slots[0]->path, TEST_PATH));
+ g_assert(!g_strcmp0(m->slots[0]->imei, TEST_IMEI));
+ g_assert(!g_strcmp0(m->slots[0]->imeisv, TEST_IMEISV));
+ g_assert(!m->slots[0]->sim_present);
+ g_assert(m->slots[0]->enabled);
+ g_assert(!m->slots[1]);
+
+ slots = gutil_strv_add(NULL, TEST_PATH);
+ fake_sailfish_manager_dbus.cb.set_enabled_slots(m, slots);
+ g_assert(m->slots[0]->enabled);
+ g_assert(!s->enabled_changed);
+
+ fake_sailfish_manager_dbus.cb.set_enabled_slots(m, NULL);
+ g_assert(!m->slots[0]->enabled);
+ g_assert(s->enabled_changed == 1);
+ s->enabled_changed = 0;
+
+ sailfish_manager_set_sim_state(s->handle, SAILFISH_SIM_STATE_PRESENT);
+ fake_sailfish_manager_dbus.cb.set_enabled_slots(m, slots);
+ g_assert(m->slots[0]->sim_present);
+ g_assert(m->slots[0]->enabled);
+ g_assert(s->enabled_changed == 1);
+ s->enabled_changed = 0;
+ g_strfreev(slots);
+
+ sailfish_manager_set_sim_state(s->handle, SAILFISH_SIM_STATE_ABSENT);
+ g_assert(!m->slots[0]->sim_present);
+ sailfish_manager_set_sim_state(s->handle, SAILFISH_SIM_STATE_ERROR);
+ sailfish_manager_set_sim_state(s->handle, SAILFISH_SIM_STATE_ERROR);
+ g_assert(!m->slots[0]->sim_present);
+
+ /* D-Bus interface is still blocked, wait for it to get unblocked */
+ g_assert(fake_sailfish_manager_dbus.block ==
+ SAILFISH_MANAGER_DBUS_BLOCK_ALL);
+ fake_sailfish_manager_dbus.fn_block_changed =
+ test_quit_loop_when_unblocked;
+ return G_SOURCE_REMOVE;
+}
+
+static guint test_sync_start_start(test_slot_manager *sm)
+{
+ test_slot *slot = g_new0(test_slot, 1);
+
+ DBG("");
+
+ /* Create the slot */
+ slot->handle = sailfish_manager_slot_add(sm->handle, slot, TEST_PATH,
+ OFONO_RADIO_ACCESS_MODE_GSM, NULL, NULL,
+ SAILFISH_SIM_STATE_UNKNOWN);
+ sailfish_manager_imei_obtained(slot->handle, TEST_IMEI);
+ sailfish_manager_imeisv_obtained(slot->handle, TEST_IMEISV);
+
+ sm->slot = slot;
+ g_idle_add(test_sync_start_done, sm);
+ return 0;
+}
+
+static void test_sync_start_slot_manager_cb(test_slot_manager *sm, void *data)
+{
+ /* Initialization is done, can't add any more slots */
+ g_assert(!sailfish_manager_slot_add(sm->handle, NULL, TEST_PATH,
+ OFONO_RADIO_ACCESS_MODE_GSM, NULL, NULL,
+ SAILFISH_SIM_STATE_UNKNOWN));
+}
+
+static void test_sync_start(void)
+{
+ static const struct sailfish_slot_driver test_sync_start_driver = {
+ .name = "sync_start",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_sync_start_start,
+ .manager_free = test_slot_manager_free,
+ .slot_enabled_changed = test_slot_enabled_changed,
+ .slot_free = test_slot_free
+ };
+ struct sailfish_slot_driver_reg *reg;
+
+ test_common_init();
+ reg = sailfish_slot_driver_register(&test_sync_start_driver);
+ g_assert(reg);
+
+ g_main_loop_run(test_loop);
+
+ sailfish_manager_foreach_slot_manager(reg, NULL, NULL); /* nop */
+ sailfish_manager_foreach_slot_manager(reg,
+ test_sync_start_slot_manager_cb, NULL);
+ sailfish_slot_driver_unregister(reg);
+ test_common_deinit();
+}
+
+/* ==== async_start ==== */
+
+static void test_async_start_add_slot(test_slot_manager *sm)
+{
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+ test_slot *s = g_new0(test_slot, 1);
+
+ /* Create the slot */
+ DBG("");
+
+ g_assert(fake_sailfish_manager_dbus.block ==
+ SAILFISH_MANAGER_DBUS_BLOCK_ALL);
+
+ s->handle = sailfish_manager_slot_add(sm->handle, s, TEST_PATH,
+ OFONO_RADIO_ACCESS_MODE_GSM, NULL, NULL,
+ SAILFISH_SIM_STATE_UNKNOWN);
+ sm->slot = s;
+
+ g_assert(!m->ready);
+ sailfish_manager_set_sim_state(s->handle, SAILFISH_SIM_STATE_ABSENT);
+ sailfish_slot_manager_started(sm->handle);
+ sailfish_slot_manager_started(sm->handle); /* Second one is a nop */
+
+ /* D-Bus interface is still blocked because IMEI is not yet known */
+ g_assert(fake_sailfish_manager_dbus.block ==
+ SAILFISH_MANAGER_DBUS_BLOCK_IMEI);
+
+ g_assert(!m->ready);
+ sailfish_manager_imei_obtained(s->handle, TEST_IMEI);
+ sailfish_manager_imeisv_obtained(s->handle, TEST_IMEISV);
+ g_assert(m->ready);
+
+ /* Now D-Bus interface is completely unblocked */
+ g_assert(fake_sailfish_manager_dbus.block ==
+ SAILFISH_MANAGER_DBUS_BLOCK_NONE);
+
+ g_idle_add(test_done_cb, NULL);
+}
+
+static gboolean test_async_start_wait(gpointer user_data)
+{
+ test_slot_manager *sm = user_data;
+
+ sm->counter--;
+ if (sm->counter > 0) {
+ return G_SOURCE_CONTINUE;
+ } else {
+ test_async_start_add_slot(sm);
+ return G_SOURCE_REMOVE;
+ }
+}
+
+static guint test_async_start_start(test_slot_manager *sm)
+{
+ sm->counter = TEST_IDLE_WAIT_COUNT;
+ return g_idle_add(test_async_start_wait, sm);
+}
+
+static void test_async_start(void)
+{
+ static const struct sailfish_slot_driver test_async_start_driver = {
+ .name = "async_start",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_async_start_start,
+ .manager_free = test_slot_manager_free,
+ .slot_free = test_slot_free
+ };
+ struct sailfish_slot_driver_reg *reg;
+
+ test_common_init();
+ reg = sailfish_slot_driver_register(&test_async_start_driver);
+ g_assert(reg);
+
+ g_main_loop_run(test_loop);
+
+ sailfish_slot_driver_unregister(reg);
+ test_common_deinit();
+}
+
+/* ==== cancel_start ==== */
+
+static gboolean test_cancel_ok;
+static guint test_cancel_id = 123;
+
+static void test_cancel_start_cancel(test_slot_manager *sm, guint id)
+{
+ g_assert(id == test_cancel_id);
+ test_cancel_ok = TRUE;
+}
+
+static guint test_cancel_start_start(test_slot_manager *sm)
+{
+ g_main_loop_quit(test_loop);
+ return test_cancel_id;
+}
+
+static void test_cancel_start(void)
+{
+ static const struct sailfish_slot_driver test_cancel_start_driver = {
+ .name = "cancel_start",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_cancel_start_start,
+ .manager_cancel_start = test_cancel_start_cancel,
+ .manager_free = test_slot_manager_free,
+ };
+
+ test_cancel_ok = FALSE;
+ test_common_init();
+ g_assert(sailfish_slot_driver_register(&test_cancel_start_driver));
+ g_main_loop_run(test_loop);
+ test_common_deinit();
+ g_assert(test_cancel_ok);
+}
+
+/* ==== voice_sim ==== */
+
+static gboolean test_voice_sim_done(gpointer user_data)
+{
+ test_slot_manager *sm = user_data;
+ test_slot *s = sm->slot;
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+ struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
+ struct ofono_sim sim;
+
+ memset(&sim, 0, sizeof(sim));
+ sim.mcc = TEST_MCC;
+ sim.mnc = TEST_MNC;
+ sim.state = OFONO_SIM_STATE_READY;
+
+ /* No default voice modem yet */
+ g_assert(m);
+ g_assert(!m->default_voice_imsi);
+ g_assert(!m->default_voice_path);
+
+ /* Once IMSI is known, default voice modem will point to this slot */
+ fake_sailfish_watch_set_ofono_sim(w, &sim);
+ fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
+ fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
+ fake_sailfish_watch_emit_queued_signals(w);
+
+ g_assert(!m->default_voice_imsi);
+ g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
+
+ /* Point it to a non-existent SIM, it will still point to the
+ * existing one */
+ fake_sailfish_manager_dbus.cb.set_default_voice_imsi(m, TEST_IMSI_1);
+ g_assert(!g_strcmp0(m->default_voice_imsi, TEST_IMSI_1));
+ g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
+
+ /* And back to the right SIM */
+ fake_sailfish_manager_dbus.cb.set_default_voice_imsi(m, TEST_IMSI);
+ g_assert(!g_strcmp0(m->default_voice_imsi, TEST_IMSI));
+ g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
+
+ /* Remove the SIM */
+ fake_sailfish_watch_set_ofono_sim(w, NULL);
+ fake_sailfish_watch_emit_queued_signals(w);
+ sailfish_manager_set_sim_state(s->handle, SAILFISH_SIM_STATE_ABSENT);
+ g_assert(!m->slots[0]->sim_present);
+ g_assert(!g_strcmp0(m->default_voice_imsi, TEST_IMSI));
+ g_assert(!m->default_voice_path);
+
+ sailfish_watch_unref(w);
+ g_main_loop_quit(test_loop);
+ return G_SOURCE_REMOVE;
+}
+
+static guint test_voice_sim_start(test_slot_manager *sm)
+{
+ test_slot *slot = g_new0(test_slot, 1);
+
+ DBG("");
+
+ /* Create the slot */
+ slot->handle = sailfish_manager_slot_add(sm->handle, slot, TEST_PATH,
+ OFONO_RADIO_ACCESS_MODE_GSM, TEST_IMEI, TEST_IMEISV,
+ SAILFISH_SIM_STATE_PRESENT);
+
+ sm->slot = slot;
+ g_idle_add(test_voice_sim_done, sm);
+ return 0;
+}
+
+static void test_voice_sim(void)
+{
+ static const struct sailfish_slot_driver test_voice_sim_driver = {
+ .name = "voice_sim",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_voice_sim_start,
+ .manager_free = test_slot_manager_free,
+ .slot_free = test_slot_free
+ };
+ struct sailfish_slot_driver_reg *reg;
+
+ test_common_init();
+ reg = sailfish_slot_driver_register(&test_voice_sim_driver);
+ g_assert(reg);
+
+ g_main_loop_run(test_loop);
+
+ sailfish_slot_driver_unregister(reg);
+ test_common_deinit();
+}
+
+/* ==== data_sim ==== */
+
+static gboolean test_data_sim_done(gpointer user_data)
+{
+ test_slot_manager *sm = user_data;
+ test_slot *s = sm->slot;
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+ struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
+ struct ofono_modem modem;
+ struct ofono_sim sim;
+
+ memset(&modem, 0, sizeof(modem));
+ memset(&sim, 0, sizeof(sim));
+ sim.mcc = TEST_MCC;
+ sim.mnc = TEST_MNC;
+ sim.state = OFONO_SIM_STATE_READY;
+
+ /* No default voice or data modems yet */
+ g_assert(m);
+ g_assert(!m->default_voice_imsi);
+ g_assert(!m->default_voice_path);
+ g_assert(!m->default_data_imsi);
+ g_assert(!m->default_data_path);
+
+ /* Once IMSI is known, default voice modem will point to this slot */
+ fake_sailfish_watch_set_ofono_sim(w, &sim);
+ fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
+ fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
+ fake_sailfish_watch_emit_queued_signals(w);
+
+ g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
+ g_assert(!m->default_data_path); /* No default data slot */
+
+ /* Set data SIM IMSI */
+ fake_sailfish_manager_dbus.cb.set_default_data_imsi(m, TEST_IMSI);
+ g_assert(!g_strcmp0(m->default_data_imsi, TEST_IMSI));
+ g_assert(!m->default_data_path); /* Modem is offline */
+
+ /* Set modem online */
+ w->modem = &modem;
+ w->online = TRUE;
+ fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_ONLINE_CHANGED);
+ fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_MODEM_CHANGED);
+ fake_sailfish_watch_emit_queued_signals(w);
+ /* Now is should point to our slot */
+ g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
+
+ /* Point it to a non-existent SIM */
+ fake_sailfish_manager_dbus.cb.set_default_data_imsi(m, TEST_IMSI_1);
+ g_assert(!g_strcmp0(m->default_data_imsi, TEST_IMSI_1));
+ g_assert(!m->default_data_path);
+
+ /* Switch the SIM */
+ fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI_1);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
+
+ /* Remove the SIM */
+ fake_sailfish_watch_set_ofono_sim(w, NULL);
+ fake_sailfish_watch_emit_queued_signals(w);
+ sailfish_manager_set_sim_state(s->handle, SAILFISH_SIM_STATE_ABSENT);
+ g_assert(!m->slots[0]->sim_present);
+ g_assert(!g_strcmp0(m->default_data_imsi, TEST_IMSI_1));
+ g_assert(!m->default_data_path);
+
+ sailfish_watch_unref(w);
+ g_main_loop_quit(test_loop);
+ return G_SOURCE_REMOVE;
+}
+
+static guint test_data_sim_start(test_slot_manager *sm)
+{
+ test_slot *slot = g_new0(test_slot, 1);
+
+ DBG("");
+
+ /* Create the slot */
+ slot->handle = sailfish_manager_slot_add(sm->handle, slot, TEST_PATH,
+ OFONO_RADIO_ACCESS_MODE_GSM, TEST_IMEI, TEST_IMEISV,
+ SAILFISH_SIM_STATE_PRESENT);
+
+ sm->slot = slot;
+ g_idle_add(test_data_sim_done, sm);
+ return 0;
+}
+
+static void test_data_sim(void)
+{
+ static const struct sailfish_slot_driver test_data_sim_driver = {
+ .name = "data_sim",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_data_sim_start,
+ .manager_free = test_slot_manager_free,
+ .slot_enabled_changed = test_slot_enabled_changed,
+ .slot_free = test_slot_free
+ };
+ struct sailfish_slot_driver_reg *reg;
+
+ test_common_init();
+ reg = sailfish_slot_driver_register(&test_data_sim_driver);
+ g_assert(reg);
+
+ g_main_loop_run(test_loop);
+
+ sailfish_slot_driver_unregister(reg);
+ test_common_deinit();
+}
+
+/* ==== mms_sim ==== */
+
+static gboolean test_mms_sim_done(gpointer user_data)
+{
+ test_slot_manager *sm = user_data;
+ test_slot *s = sm->slot;
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+ struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
+ struct ofono_modem modem;
+ struct ofono_sim sim;
+
+ memset(&modem, 0, sizeof(modem));
+ memset(&sim, 0, sizeof(sim));
+ sim.mcc = TEST_MCC;
+ sim.mnc = TEST_MNC;
+ sim.state = OFONO_SIM_STATE_READY;
+
+ /* Nothing yet */
+ g_assert(m);
+ g_assert(!m->mms_imsi);
+ g_assert(!m->mms_path);
+ g_assert(!m->default_voice_imsi);
+ g_assert(!m->default_voice_path);
+ g_assert(!m->default_data_imsi);
+ g_assert(!m->default_data_path);
+
+ /* Make the test slot the default data modem */
+ w->modem = &modem;
+ w->online = TRUE;
+ fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_ONLINE_CHANGED);
+ fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_MODEM_CHANGED);
+ fake_sailfish_watch_set_ofono_sim(w, &sim);
+ fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
+ fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
+ fake_sailfish_watch_emit_queued_signals(w);
+
+ /* Data SIM gets automatically selected on a single-SIM phone */
+ g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
+ g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
+
+ /* Set data SIM IMSI (second time is a noop */
+ fake_sailfish_manager_dbus.cb.set_default_data_imsi(m, TEST_IMSI);
+ g_assert(!g_strcmp0(m->default_data_imsi, TEST_IMSI));
+ g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
+ fake_sailfish_manager_dbus.cb.set_default_data_imsi(m, TEST_IMSI);
+ g_assert(!g_strcmp0(m->default_data_imsi, TEST_IMSI));
+ g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
+ g_assert(s->data_role == SAILFISH_DATA_ROLE_INTERNET);
+
+ /* Reserve it for MMS */
+ g_assert(fake_sailfish_manager_dbus.cb.set_mms_imsi(m, TEST_IMSI));
+ g_assert(s->data_role == SAILFISH_DATA_ROLE_INTERNET); /* Not MMS! */
+ g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
+ g_assert(!g_strcmp0(m->mms_imsi, TEST_IMSI));
+ g_assert(!g_strcmp0(m->mms_path, TEST_PATH));
+
+ /* Try to point MMS IMSI to a non-existent SIM */
+ g_assert(!fake_sailfish_manager_dbus.cb.set_mms_imsi(m, TEST_IMSI_1));
+ g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
+ g_assert(!g_strcmp0(m->mms_imsi, TEST_IMSI));
+ g_assert(!g_strcmp0(m->mms_path, TEST_PATH));
+ g_assert(s->data_role == SAILFISH_DATA_ROLE_INTERNET);
+
+ /* Reset MMS IMSI */
+ g_assert(fake_sailfish_manager_dbus.cb.set_mms_imsi(m, NULL));
+ g_assert(!m->mms_imsi);
+ g_assert(!m->mms_path);
+
+ /* Second time is a noop, empty IMSI is the same as NULL */
+ g_assert(fake_sailfish_manager_dbus.cb.set_mms_imsi(m, ""));
+ g_assert(!m->mms_imsi);
+ g_assert(!m->mms_path);
+
+ sailfish_watch_unref(w);
+ g_main_loop_quit(test_loop);
+ return G_SOURCE_REMOVE;
+}
+
+static guint test_mms_sim_start(test_slot_manager *sm)
+{
+ test_slot *slot = g_new0(test_slot, 1);
+
+ DBG("");
+
+ /* Create the slot */
+ slot->handle = sailfish_manager_slot_add(sm->handle, slot, TEST_PATH,
+ OFONO_RADIO_ACCESS_MODE_GSM, TEST_IMEI, TEST_IMEISV,
+ SAILFISH_SIM_STATE_PRESENT);
+
+ sm->slot = slot;
+ g_idle_add(test_mms_sim_done, sm);
+ return 0;
+}
+
+static void test_mms_sim(void)
+{
+ static const struct sailfish_slot_driver test_mms_sim_driver = {
+ .name = "mms_sim",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_mms_sim_start,
+ .manager_free = test_slot_manager_free,
+ .slot_enabled_changed = test_slot_enabled_changed,
+ .slot_set_data_role = test_slot_set_data_role,
+ .slot_free = test_slot_free
+ };
+ struct sailfish_slot_driver_reg *reg;
+
+ test_common_init();
+ reg = sailfish_slot_driver_register(&test_mms_sim_driver);
+ g_assert(reg);
+
+ g_main_loop_run(test_loop);
+
+ sailfish_slot_driver_unregister(reg);
+ test_common_deinit();
+}
+
+/* ==== multisim ==== */
+
+static gboolean test_multisim_done(gpointer user_data)
+{
+ test_slot_manager *sm = user_data;
+ test_slot *s = sm->slot;
+ test_slot *s2 = sm->slot2;
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+ struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
+ struct sailfish_watch *w2 = sailfish_watch_new(TEST_PATH_1);
+ struct ofono_modem modem;
+ struct ofono_sim sim;
+ struct ofono_sim sim2;
+
+ memset(&modem, 0, sizeof(modem));
+ memset(&sim, 0, sizeof(sim));
+ sim.mcc = TEST_MCC;
+ sim.mnc = TEST_MNC;
+ sim.state = OFONO_SIM_STATE_READY;
+ sim2 = sim;
+
+ /* Assign IMSI to the SIMs */
+ w->modem = &modem;
+ w->online = TRUE;
+ fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_ONLINE_CHANGED);
+ fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_MODEM_CHANGED);
+ fake_sailfish_watch_set_ofono_sim(w, &sim);
+ fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
+ fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
+ fake_sailfish_watch_emit_queued_signals(w);
+
+ w2->modem = &modem;
+ w2->online = TRUE;
+ fake_sailfish_watch_signal_queue(w2, WATCH_SIGNAL_ONLINE_CHANGED);
+ fake_sailfish_watch_signal_queue(w2, WATCH_SIGNAL_MODEM_CHANGED);
+ fake_sailfish_watch_set_ofono_sim(w2, &sim2);
+ fake_sailfish_watch_set_ofono_iccid(w2, TEST_ICCID_1);
+ fake_sailfish_watch_set_ofono_imsi(w2, TEST_IMSI_1);
+ fake_sailfish_watch_emit_queued_signals(w2);
+
+ /* No automatic data SIM selection on a multisim phone */
+ g_assert(s->data_role == SAILFISH_DATA_ROLE_NONE);
+ g_assert(!m->default_voice_imsi);
+ g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
+ g_assert(!m->default_data_imsi);
+ g_assert(!m->default_data_path);
+
+ /* Reserve the first slot for data */
+ fake_sailfish_manager_dbus.cb.set_default_data_imsi(m, TEST_IMSI);
+ g_assert(s->data_role == SAILFISH_DATA_ROLE_INTERNET);
+ g_assert(!g_strcmp0(m->default_data_imsi, TEST_IMSI));
+ g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
+
+ /* Second slot for MMS */
+ g_assert(fake_sailfish_manager_dbus.cb.set_mms_imsi(m, TEST_IMSI_1));
+ g_assert(s->data_role == SAILFISH_DATA_ROLE_NONE);
+ g_assert(s2->data_role == SAILFISH_DATA_ROLE_MMS);
+ g_assert(!g_strcmp0(m->mms_path, TEST_PATH_1));
+ g_assert(!g_strcmp0(m->mms_imsi, TEST_IMSI_1));
+ g_assert(!g_strcmp0(m->default_data_imsi, TEST_IMSI));
+ g_assert(!m->default_data_path);
+
+ /* Cancel MMS reservation */
+ g_assert(fake_sailfish_manager_dbus.cb.set_mms_imsi(m, NULL));
+ g_assert(s->data_role == SAILFISH_DATA_ROLE_INTERNET);
+ g_assert(s2->data_role == SAILFISH_DATA_ROLE_NONE);
+ g_assert(!g_strcmp0(m->default_data_imsi, TEST_IMSI));
+ g_assert(!g_strcmp0(m->default_data_path, TEST_PATH));
+ g_assert(!m->mms_path);
+ g_assert(!m->mms_imsi);
+
+ sailfish_watch_unref(w);
+ sailfish_watch_unref(w2);
+ g_main_loop_quit(test_loop);
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean test_multisim_add_slots(gpointer user_data)
+{
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+ test_slot_manager *sm = user_data;
+ test_slot *s = g_new0(test_slot, 1);
+ test_slot *s2 = g_new0(test_slot, 1);
+
+ /* Create the slots */
+ DBG("");
+ s->handle = sailfish_manager_slot_add(sm->handle, s, TEST_PATH,
+ OFONO_RADIO_ACCESS_MODE_GSM, NULL, TEST_IMEISV,
+ SAILFISH_SIM_STATE_PRESENT);
+ s2->handle = sailfish_manager_slot_add(sm->handle, s2, TEST_PATH_1,
+ OFONO_RADIO_ACCESS_MODE_GSM, NULL, TEST_IMEISV,
+ SAILFISH_SIM_STATE_PRESENT);
+ sm->slot = s;
+ sm->slot2 = s2;
+ sailfish_slot_manager_started(sm->handle);
+
+ g_assert(!m->ready);
+ sailfish_manager_imei_obtained(s->handle, TEST_IMEI);
+ g_assert(!m->ready);
+ sailfish_manager_imei_obtained(s2->handle, TEST_IMEI_1);
+ g_assert(m->ready);
+
+ g_idle_add(test_multisim_done, sm);
+ return G_SOURCE_REMOVE;
+}
+
+static guint test_multisim_start(test_slot_manager *sm)
+{
+ return g_idle_add(test_multisim_add_slots, sm);
+}
+
+static void test_multisim(void)
+{
+ static const struct sailfish_slot_driver test_multisim_driver = {
+ .name = "multisim",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_multisim_start,
+ .manager_free = test_slot_manager_free,
+ .slot_enabled_changed = test_slot_enabled_changed,
+ .slot_set_data_role = test_slot_set_data_role,
+ .slot_free = test_slot_free
+ };
+ struct sailfish_slot_driver_reg *reg;
+
+ test_common_init();
+ reg = sailfish_slot_driver_register(&test_multisim_driver);
+ g_assert(reg);
+
+ g_main_loop_run(test_loop);
+
+ sailfish_slot_driver_unregister(reg);
+ test_common_deinit();
+}
+
+/* ==== storage ==== */
+
+static void test_storage_init(test_slot_manager *sm)
+{
+ struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
+ struct sailfish_watch *w2 = sailfish_watch_new(TEST_PATH_1);
+ struct ofono_sim sim;
+ struct ofono_sim sim2;
+
+ memset(&sim, 0, sizeof(sim));
+ sim.mcc = TEST_MCC;
+ sim.mnc = TEST_MNC;
+ sim.state = OFONO_SIM_STATE_READY;
+ sim2 = sim;
+
+ /* Assign IMSI to the SIMs */
+ fake_sailfish_watch_set_ofono_sim(w, &sim);
+ fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
+ fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
+ fake_sailfish_watch_emit_queued_signals(w);
+
+ fake_sailfish_watch_set_ofono_sim(w2, &sim2);
+ fake_sailfish_watch_set_ofono_iccid(w2, TEST_ICCID_1);
+ fake_sailfish_watch_set_ofono_imsi(w2, TEST_IMSI_1);
+ fake_sailfish_watch_emit_queued_signals(w2);
+
+ sailfish_watch_unref(w);
+ sailfish_watch_unref(w2);
+}
+
+static void test_storage_add_slots(test_slot_manager *sm)
+{
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+ test_slot *s = g_new0(test_slot, 1);
+ test_slot *s2 = g_new0(test_slot, 1);
+
+ /* Create the slots */
+ DBG("");
+ s->handle = sailfish_manager_slot_add(sm->handle, s, TEST_PATH,
+ OFONO_RADIO_ACCESS_MODE_GSM, NULL, TEST_IMEISV,
+ SAILFISH_SIM_STATE_PRESENT);
+ s2->handle = sailfish_manager_slot_add(sm->handle, s2, TEST_PATH_1,
+ OFONO_RADIO_ACCESS_MODE_GSM, NULL, TEST_IMEISV,
+ SAILFISH_SIM_STATE_PRESENT);
+ sm->slot = s;
+ sm->slot2 = s2;
+ sailfish_slot_manager_started(sm->handle);
+
+ g_assert(!m->ready);
+ sailfish_manager_imei_obtained(s->handle, TEST_IMEI);
+ g_assert(!m->ready);
+ sailfish_manager_imei_obtained(s2->handle, TEST_IMEI_1);
+ g_assert(m->ready);
+}
+
+static gboolean test_storage_save_add_slots(gpointer user_data)
+{
+ test_slot_manager *sm = user_data;
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+ char **slots = gutil_strv_add(NULL, TEST_PATH);
+
+ test_storage_add_slots(sm);
+
+ fake_sailfish_manager_dbus.cb.set_enabled_slots(m, slots);
+ g_assert(m->slots[0]->enabled);
+ g_assert(!m->slots[1]->enabled);
+ g_strfreev(slots);
+
+ test_storage_init(sm);
+
+ /* Wait for D-Bus interface to get unblocked and exit the loop */
+ fake_sailfish_manager_dbus.fn_block_changed =
+ test_quit_loop_when_unblocked;
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean test_storage_restore_add_slots(gpointer user_data)
+{
+ test_slot_manager *sm = user_data;
+ struct sailfish_manager *m = fake_sailfish_manager_dbus.m;
+
+ test_storage_add_slots(sm);
+
+ /* These should get restored from the file */
+ g_assert(m->slots[0]->enabled);
+ g_assert(!m->slots[1]->enabled);
+
+ /* Wait for D-Bus interface to get unblocked and exit the loop */
+ fake_sailfish_manager_dbus.fn_block_changed =
+ test_quit_loop_when_unblocked;
+ return G_SOURCE_REMOVE;
+}
+
+static guint test_storage_save_start(test_slot_manager *sm)
+{
+ return g_idle_add(test_storage_save_add_slots, sm);
+}
+
+static guint test_storage_restore_start(test_slot_manager *sm)
+{
+ return g_idle_add(test_storage_restore_add_slots, sm);
+}
+
+static void test_storage(void)
+{
+ static const struct sailfish_slot_driver test_storage_save_driver = {
+ .name = "storage_save",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_storage_save_start,
+ .manager_free = test_slot_manager_free,
+ .slot_enabled_changed = test_slot_enabled_changed,
+ .slot_free = test_slot_free
+ };
+
+ static const struct sailfish_slot_driver test_storage_restore_driver = {
+ .name = "storage_restore",
+ .manager_create = test_slot_manager_create,
+ .manager_start = test_storage_restore_start,
+ .manager_free = test_slot_manager_free,
+ .slot_enabled_changed = test_slot_enabled_changed,
+ .slot_free = test_slot_free
+ };
+
+ test_common_init();
+
+ g_assert(sailfish_slot_driver_register(&test_storage_save_driver));
+ g_main_loop_run(test_loop);
+
+ /* Reinitialize everything */
+ __ofono_builtin_sailfish_manager.exit();
+ __ofono_builtin_sailfish_manager.init();
+
+ /* And restore settings from the file */
+ g_assert(sailfish_slot_driver_register(&test_storage_restore_driver));
+ g_main_loop_run(test_loop);
+
+ test_common_deinit();
+}
+
+#define TEST_(name) "/sailfish_manager/" name
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ gutil_log_timestamp = FALSE;
+ gutil_log_default.level = g_test_verbose() ?
+ GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
+ __ofono_log_init("test-sailfish_manager",
+ g_test_verbose() ? "*" : NULL,
+ FALSE, FALSE);
+
+ g_test_add_func(TEST_("basic"), test_basic);
+ g_test_add_func(TEST_("early_init"), test_early_init);
+ g_test_add_func(TEST_("too_late"), test_too_late);
+ g_test_add_func(TEST_("create_fail"), test_create_fail);
+ g_test_add_func(TEST_("no_slots"), test_no_slots);
+ g_test_add_func(TEST_("sync_start"), test_sync_start);
+ g_test_add_func(TEST_("async_start"), test_async_start);
+ g_test_add_func(TEST_("cancel_start"), test_cancel_start);
+ g_test_add_func(TEST_("voice_sim"), test_voice_sim);
+ g_test_add_func(TEST_("data_sim"), test_data_sim);
+ g_test_add_func(TEST_("mms_sim"), test_mms_sim);
+ g_test_add_func(TEST_("multisim"), test_multisim);
+ g_test_add_func(TEST_("storage"), test_storage);
+
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:ofono-1.19+git25.tar.bz2/ofono/unit/test-sailfish_sim_info.c
^
|
@@ -0,0 +1,442 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2017 Jolla Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sailfish_sim_info.h"
+#include "fake_sailfish_watch.h"
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include "ofono.h"
+#include "common.h"
+
+#include <gutil_log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define TEST_PATH "/test"
+#define TEST_ICCID "1111111111111111111"
+#define TEST_IMSI "244120000000000"
+#define TEST_MCC "244"
+#define TEST_MNC "12"
+#define TEST_DEFAULT_SPN TEST_MCC TEST_MNC
+#define TEST_SPN "Test"
+
+#define ICCID_MAP STORAGEDIR "/iccidmap"
+#define SIM_CACHE STORAGEDIR "/" TEST_IMSI "/cache"
+
+enum sim_info_signals {
+ SIM_INFO_SIGNAL_ICCID_CHANGED,
+ SIM_INFO_SIGNAL_IMSI_CHANGED,
+ SIM_INFO_SIGNAL_SPN_CHANGED,
+ SIM_INFO_SIGNAL_COUNT
+};
+
+/* Fake ofono_sim */
+
+struct ofono_sim {
+ const char *mcc;
+ const char *mnc;
+ const char *spn;
+ enum ofono_sim_state state;
+};
+
+enum ofono_sim_state ofono_sim_get_state(struct ofono_sim *sim)
+{
+ return sim ? sim->state : OFONO_SIM_STATE_NOT_PRESENT;
+}
+
+const char *ofono_sim_get_mcc(struct ofono_sim *sim)
+{
+ return sim ? sim->mcc : NULL;
+}
+
+const char *ofono_sim_get_mnc(struct ofono_sim *sim)
+{
+ return sim ? sim->mnc : NULL;
+}
+
+/* Fake ofono_netreg */
+
+struct ofono_netreg {
+ const char *mcc;
+ const char *mnc;
+ const char *name;
+ int location;
+ int cellid;
+ enum ofono_radio_access_mode technology;
+ enum network_registration_status status;
+ struct ofono_watchlist *status_watches;
+};
+
+int ofono_netreg_get_status(struct ofono_netreg *netreg)
+{
+ return netreg ? netreg->status : -1;
+}
+
+const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg)
+{
+ return netreg ? netreg->mcc : NULL;
+}
+
+const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg)
+{
+ return netreg ? netreg->mnc : NULL;
+}
+
+const char *ofono_netreg_get_name(struct ofono_netreg *netreg)
+{
+ return netreg ? netreg->name : NULL;
+}
+
+unsigned int __ofono_netreg_add_status_watch(struct ofono_netreg *netreg,
+ ofono_netreg_status_notify_cb_t notify,
+ void *data, ofono_destroy_func destroy)
+{
+ struct ofono_watchlist_item *item =
+ g_new0(struct ofono_watchlist_item, 1);
+
+ DBG("%p", netreg);
+ g_assert(netreg);
+ g_assert(notify);
+ item->notify = notify;
+ item->destroy = destroy;
+ item->notify_data = data;
+ return __ofono_watchlist_add_item(netreg->status_watches, item);
+}
+
+gboolean __ofono_netreg_remove_status_watch(struct ofono_netreg *netreg,
+ unsigned int id)
+{
+ return __ofono_watchlist_remove_item(netreg->status_watches, id);
+}
+
+/* Utilities */
+
+static int rmdir_r(const char *path)
+{
+ DIR *d = opendir(path);
+
+ if (d) {
+ const struct dirent *p;
+ int r = 0;
+
+ while (!r && (p = readdir(d))) {
+ char *buf;
+ struct stat st;
+
+ if (!strcmp(p->d_name, ".") ||
+ !strcmp(p->d_name, "..")) {
+ continue;
+ }
+
+ buf = g_strdup_printf("%s/%s", path, p->d_name);
+ if (!stat(buf, &st)) {
+ r = S_ISDIR(st.st_mode) ? rmdir_r(buf) :
+ unlink(buf);
+ }
+ g_free(buf);
+ }
+ closedir(d);
+ return r ? r : rmdir(path);
+ } else {
+ return -1;
+ }
+}
+
+static void netreg_notify_status_watches(struct ofono_netreg *netreg)
+{
+ GSList *l;
+ const char *mcc = netreg->mcc;
+ const char *mnc = netreg->mnc;
+
+ for (l = netreg->status_watches->items; l; l = l->next) {
+ struct ofono_watchlist_item *item = l->data;
+ ofono_netreg_status_notify_cb_t notify = item->notify;
+
+ notify(netreg->status, netreg->location, netreg->cellid,
+ netreg->technology, mcc, mnc, item->notify_data);
+ }
+}
+
+
+/* Test cases */
+
+static void test_basic(void)
+{
+ struct sailfish_sim_info *si;
+
+ /* NULL tolerance */
+ g_assert(!sailfish_sim_info_new(NULL));
+ g_assert(!sailfish_sim_info_ref(NULL));
+ sailfish_sim_info_unref(NULL);
+ sailfish_sim_info_invalidate(NULL);
+ g_assert(!sailfish_sim_info_add_iccid_changed_handler(NULL,NULL,NULL));
+ g_assert(!sailfish_sim_info_add_imsi_changed_handler(NULL,NULL,NULL));
+ g_assert(!sailfish_sim_info_add_spn_changed_handler(NULL,NULL,NULL));
+ sailfish_sim_info_remove_handler(NULL, 0);
+ sailfish_sim_info_remove_handlers(NULL, NULL, 0);
+
+ /* Very basic things (mostly to improve code coverage) */
+ si = sailfish_sim_info_new("/test");
+ g_assert(si);
+ sailfish_sim_info_invalidate(si);
+ g_assert(!sailfish_sim_info_add_iccid_changed_handler(si,NULL,NULL));
+ g_assert(!sailfish_sim_info_add_imsi_changed_handler(si,NULL,NULL));
+ g_assert(!sailfish_sim_info_add_spn_changed_handler(si,NULL,NULL));
+ sailfish_sim_info_remove_handler(si, 0);
+ sailfish_sim_info_remove_handlers(si, NULL, 0);
+ sailfish_sim_info_unref(sailfish_sim_info_ref(si));
+ sailfish_sim_info_unref(si);
+}
+
+static void test_signal_count_cb(struct sailfish_sim_info *si, void *data)
+{
+ (*((int*)data))++;
+}
+
+static void test_cache(void)
+{
+ struct sailfish_sim_info *si;
+ struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
+ struct ofono_sim sim;
+ struct stat st;
+ gulong id[SIM_INFO_SIGNAL_COUNT];
+ int count[SIM_INFO_SIGNAL_COUNT];
+
+ memset(id, 0, sizeof(id));
+ memset(count, 0, sizeof(count));
+ memset(&sim, 0, sizeof(sim));
+ sim.state = OFONO_SIM_STATE_INSERTED;
+
+ rmdir_r(STORAGEDIR);
+ si = sailfish_sim_info_new(TEST_PATH);
+ id[SIM_INFO_SIGNAL_ICCID_CHANGED] =
+ sailfish_sim_info_add_iccid_changed_handler(si,
+ test_signal_count_cb, count +
+ SIM_INFO_SIGNAL_ICCID_CHANGED);
+ id[SIM_INFO_SIGNAL_IMSI_CHANGED] =
+ sailfish_sim_info_add_imsi_changed_handler(si,
+ test_signal_count_cb, count +
+ SIM_INFO_SIGNAL_IMSI_CHANGED);
+ id[SIM_INFO_SIGNAL_SPN_CHANGED] =
+ sailfish_sim_info_add_spn_changed_handler(si,
+ test_signal_count_cb, count +
+ SIM_INFO_SIGNAL_SPN_CHANGED);
+
+ fake_sailfish_watch_set_ofono_sim(w, &sim);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
+ g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
+ g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
+
+ fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(!g_strcmp0(si->iccid, TEST_ICCID));
+ g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
+ g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
+ g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
+ g_assert(stat(ICCID_MAP, &st) < 0);
+ count[SIM_INFO_SIGNAL_ICCID_CHANGED] = 0;
+
+ fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(!g_strcmp0(si->imsi, TEST_IMSI));
+ g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
+ g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
+ g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
+ count[SIM_INFO_SIGNAL_IMSI_CHANGED] = 0;
+ /* ICCID mape appears */
+ g_assert(stat(ICCID_MAP, &st) == 0);
+ g_assert(S_ISREG(st.st_mode));
+ /* But no cache yet */
+ g_assert(stat(SIM_CACHE, &st) < 0);
+
+ /* This will generate default SPN out of MCC and MNC */
+ sim.mcc = TEST_MCC;
+ sim.mnc = TEST_MNC;
+ sim.state = OFONO_SIM_STATE_READY;
+ fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(!g_strcmp0(si->spn, TEST_DEFAULT_SPN));
+ g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
+ count[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
+
+ /* Replace default SPN with the real one */
+ fake_sailfish_watch_set_ofono_spn(w, TEST_SPN);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(!g_strcmp0(si->spn, TEST_SPN));
+ g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
+ g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
+ g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
+ count[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
+ /* Cache file appears */
+ g_assert(stat(SIM_CACHE, &st) == 0);
+ g_assert(S_ISREG(st.st_mode));
+
+ /* Reset the information */
+ sim.mcc = NULL;
+ sim.mnc = NULL;
+ sim.state = OFONO_SIM_STATE_NOT_PRESENT;
+ fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
+ fake_sailfish_watch_set_ofono_iccid(w, NULL);
+ fake_sailfish_watch_set_ofono_imsi(w, NULL);
+ fake_sailfish_watch_set_ofono_spn(w, NULL);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
+ g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
+ g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
+ memset(count, 0, sizeof(count));
+
+ /* Set ICCID again, that will load the cached information */
+ sim.mcc = NULL;
+ sim.mnc = NULL;
+ sim.state = OFONO_SIM_STATE_INSERTED;
+ fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
+ fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(!g_strcmp0(si->iccid, TEST_ICCID));
+ g_assert(!g_strcmp0(si->imsi, TEST_IMSI));
+ g_assert(!g_strcmp0(si->spn, TEST_SPN));
+ g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
+ g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
+ g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
+ memset(count, 0, sizeof(count));
+
+ sailfish_sim_info_remove_handler(si, id[SIM_INFO_SIGNAL_SPN_CHANGED]);
+ id[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
+ sailfish_sim_info_invalidate(si);
+ g_assert(!si->iccid);
+ g_assert(!si->imsi);
+ g_assert(!si->iccid);
+ g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
+ g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
+ g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]); /* removed ^ */
+ memset(count, 0, sizeof(count));
+
+ sailfish_sim_info_remove_handlers(si, id, G_N_ELEMENTS(id));
+ sailfish_sim_info_unref(si);
+ sailfish_watch_unref(w);
+}
+
+static void test_netreg(void)
+{
+ struct sailfish_sim_info *si;
+ struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
+ struct ofono_sim sim;
+ struct ofono_netreg netreg;
+ struct stat st;
+ gulong id[SIM_INFO_SIGNAL_COUNT];
+ int count[SIM_INFO_SIGNAL_COUNT];
+
+ memset(id, 0, sizeof(id));
+ memset(count, 0, sizeof(count));
+
+ memset(&netreg, 0, sizeof(netreg));
+ netreg.technology = OFONO_RADIO_ACCESS_MODE_GSM;
+ netreg.status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
+ netreg.status_watches = __ofono_watchlist_new(g_free);
+
+ memset(&sim, 0, sizeof(sim));
+ sim.mcc = TEST_MCC;
+ sim.mnc = TEST_MNC;
+ sim.state = OFONO_SIM_STATE_READY;
+
+ rmdir_r(STORAGEDIR);
+ si = sailfish_sim_info_new(TEST_PATH);
+ id[SIM_INFO_SIGNAL_ICCID_CHANGED] =
+ sailfish_sim_info_add_iccid_changed_handler(si,
+ test_signal_count_cb, count +
+ SIM_INFO_SIGNAL_ICCID_CHANGED);
+ id[SIM_INFO_SIGNAL_IMSI_CHANGED] =
+ sailfish_sim_info_add_imsi_changed_handler(si,
+ test_signal_count_cb, count +
+ SIM_INFO_SIGNAL_IMSI_CHANGED);
+ id[SIM_INFO_SIGNAL_SPN_CHANGED] =
+ sailfish_sim_info_add_spn_changed_handler(si,
+ test_signal_count_cb, count +
+ SIM_INFO_SIGNAL_SPN_CHANGED);
+
+ fake_sailfish_watch_set_ofono_sim(w, &sim);
+ fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
+ fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(!g_strcmp0(si->iccid, TEST_ICCID));
+ g_assert(!g_strcmp0(si->imsi, TEST_IMSI));
+ g_assert(!g_strcmp0(si->spn, TEST_DEFAULT_SPN));
+ g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
+ g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
+ g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
+ memset(count, 0, sizeof(count));
+
+ g_assert(stat(ICCID_MAP, &st) == 0);
+ g_assert(S_ISREG(st.st_mode));
+ /* Default SPN doesn't get cached */
+ g_assert(stat(SIM_CACHE, &st) < 0);
+
+ fake_sailfish_watch_set_ofono_netreg(w, &netreg);
+ fake_sailfish_watch_emit_queued_signals(w);
+ g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
+ g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
+ g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
+
+ /* Simulate home registation */
+ netreg.mcc = TEST_MCC;
+ netreg.mnc = TEST_MNC;
+ netreg.name = TEST_SPN;
+ netreg.status = NETWORK_REGISTRATION_STATUS_REGISTERED;
+ netreg_notify_status_watches(&netreg);
+ g_assert(!g_strcmp0(si->spn, TEST_SPN));
+ g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
+ /* This one does get cached */
+ g_assert(stat(SIM_CACHE, &st) == 0);
+ g_assert(S_ISREG(st.st_mode));
+
+ fake_sailfish_watch_set_ofono_netreg(w, NULL);
+ fake_sailfish_watch_emit_queued_signals(w);
+
+ __ofono_watchlist_free(netreg.status_watches);
+ sailfish_sim_info_remove_handlers(si, id, G_N_ELEMENTS(id));
+ sailfish_sim_info_unref(si);
+ sailfish_watch_unref(w);
+}
+
+#define TEST_(name) "/sailfish_sim_info/" name
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ gutil_log_timestamp = FALSE;
+ gutil_log_default.level = g_test_verbose() ?
+ GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
+ __ofono_log_init("test-sailfish_sim_info",
+ g_test_verbose() ? "*" : NULL,
+ FALSE, FALSE);
+
+ g_test_add_func(TEST_("basic"), test_basic);
+ g_test_add_func(TEST_("cache"), test_cache);
+ g_test_add_func(TEST_("netreg"), test_netreg);
+
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
|