diff --git a/AUTHORS b/AUTHORS index 5769bf9c..a8292db0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -123,3 +123,5 @@ Piotr Haber André Draszik Lukasz Nowak Jonas Bonn +Matthijs Kooijman +Clayton Craft diff --git a/Makefile.am b/Makefile.am index fec2d7bd..0ea9a721 100644 --- a/Makefile.am +++ b/Makefile.am @@ -236,7 +236,8 @@ builtin_sources += $(qmi_sources) \ drivers/qmimodem/gprs.c \ drivers/qmimodem/gprs-context.c \ drivers/qmimodem/radio-settings.c \ - drivers/qmimodem/location-reporting.c + drivers/qmimodem/location-reporting.c \ + drivers/qmimodem/qmibridge.c builtin_modules += gobi builtin_sources += plugins/gobi.c @@ -267,7 +268,8 @@ builtin_sources += drivers/atmodem/atmodem.h \ drivers/atmodem/gprs.c \ drivers/atmodem/gprs-context.c \ drivers/atmodem/sim-auth.c \ - drivers/atmodem/gnss.c + drivers/atmodem/gnss.c \ + drivers/atmodem/lte.c builtin_modules += nwmodem builtin_sources += drivers/atmodem/atutil.h \ @@ -398,6 +400,11 @@ builtin_sources += drivers/atmodem/atutil.h \ drivers/gemaltomodem/gemaltomodem.c \ drivers/gemaltomodem/location-reporting.c +builtin_modules += xmm7modem +builtin_sources += drivers/atmodem/atutil.h \ + drivers/xmm7modem/xmm7modem.h \ + drivers/xmm7modem/xmm7modem.c \ + drivers/xmm7modem/radio-settings.c if PHONESIM builtin_modules += phonesim @@ -623,10 +630,11 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \ src/cdma-provision.c src/handsfree.c \ src/handsfree-audio.c src/bluetooth.h \ src/hfp.h src/siri.c \ - src/netmon.c src/lte.c src/call-list.c + src/netmon.c src/lte.c src/call-list.c \ + src/netmonagent.c src/netmonagent.h src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \ - @GLIB_LIBS@ @DBUS_LIBS@ -ldl + @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lqmi-glib src_ofonod_LDFLAGS = -Wl,--export-dynamic \ -Wl,--version-script=$(srcdir)/src/ofono.ver @@ -649,7 +657,7 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ $(builtin_cflags) \ AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/src \ -I$(srcdir)/gdbus -I$(srcdir)/gisi -I$(srcdir)/gatchat \ - -I$(srcdir)/btio -I$(srcdir)/gril + -I$(srcdir)/btio -I$(srcdir)/gril -I/usr/include/libqmi-glib doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \ doc/manager-api.txt doc/modem-api.txt doc/network-api.txt \ @@ -776,7 +784,9 @@ test_scripts = test/backtrace \ test/list-allowed-access-points \ test/enable-throttling \ test/disable-throttling \ - test/set-lte-property + test/set-lte-property \ + test/test-serving-cell-info + if TEST testdir = $(pkglibdir)/test diff --git a/doc/networkmonitor-api.txt b/doc/networkmonitor-api.txt index ddace7e4..f8cc1c2e 100644 --- a/doc/networkmonitor-api.txt +++ b/doc/networkmonitor-api.txt @@ -22,6 +22,34 @@ Methods a{sv} GetServingCellInformation() are available, their valid value ranges and applicability to different cell types. + void RegisterAgent(object path) + + Registers an agent which will be called whenever the + modem registers to or moves to a new cell. + + void UnregisterAgent(object path) + + Unregisters an agent. + +NetworkMonitorAgent Hierarchy [experimental] +============================= + +Service unique name +Interface org.ofono.NetworkMonitorAgent +Object path freely definable + +Methods void ServingCellInformationChanged(a{sv}) [noreply] + + This method is called whenever the serving cell + information has been updated. + + Possible Errors: None + + void Release() [noreply] + + Agent is being released, possibly because of oFono + terminating, NetworkMonitor interface is being torn + down or modem off. No UnregisterAgent call is needed. Network Monitor Property Types ============================== @@ -77,7 +105,7 @@ byte TimingAdvance [optional, gsm] Contains the Timing Advance. Valid range of values is 0-219. -byte Strength [optional, gsm, umts] +byte Strength [optional, gsm, umts, lte] Contains the signal strength. Valid values are 0-31. Refer to in 27.007, Section 8.5. diff --git a/drivers/atmodem/atmodem.c b/drivers/atmodem/atmodem.c index 3a55ac2e..684b2282 100644 --- a/drivers/atmodem/atmodem.c +++ b/drivers/atmodem/atmodem.c @@ -52,6 +52,7 @@ static int atmodem_init(void) at_gprs_context_init(); at_sim_auth_init(); at_gnss_init(); + at_lte_init(); return 0; } @@ -76,6 +77,7 @@ static void atmodem_exit(void) at_gprs_exit(); at_gprs_context_exit(); at_gnss_exit(); + at_lte_exit(); } OFONO_PLUGIN_DEFINE(atmodem, "AT modem driver", VERSION, diff --git a/drivers/atmodem/atmodem.h b/drivers/atmodem/atmodem.h index 6be1fe5d..b7370668 100644 --- a/drivers/atmodem/atmodem.h +++ b/drivers/atmodem/atmodem.h @@ -74,3 +74,6 @@ extern void at_sim_auth_exit(void); extern void at_gnss_init(void); extern void at_gnss_exit(void); + +extern void at_lte_init(void); +extern void at_lte_exit(void); diff --git a/drivers/atmodem/atutil.h b/drivers/atmodem/atutil.h index 862a0a14..90c82549 100644 --- a/drivers/atmodem/atutil.h +++ b/drivers/atmodem/atutil.h @@ -51,9 +51,7 @@ enum at_util_charset { typedef void (*at_util_sim_inserted_cb_t)(gboolean present, void *userdata); void decode_at_error(struct ofono_error *error, const char *final); -gint ofono_call_compare_by_status(gconstpointer a, gconstpointer b); gint at_util_call_compare_by_phone_number(gconstpointer a, gconstpointer b); -gint ofono_call_compare_by_id(gconstpointer a, gconstpointer b); GSList *at_util_parse_clcc(GAtResult *result, unsigned int *mpty_ids); gboolean at_util_parse_reg(GAtResult *result, const char *prefix, int *mode, int *status, diff --git a/drivers/atmodem/gprs-context.c b/drivers/atmodem/gprs-context.c index 9b9679e8..42ec556d 100644 --- a/drivers/atmodem/gprs-context.c +++ b/drivers/atmodem/gprs-context.c @@ -43,7 +43,7 @@ #include "atmodem.h" #include "vendor.h" -#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun" +#define TUN_DEV "/dev/net/tun" #define STATIC_IP_NETMASK "255.255.255.255" @@ -426,7 +426,7 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc, DBG(""); - if (stat(TUN_SYSFS_DIR, &st) < 0) { + if (stat(TUN_DEV, &st) < 0) { ofono_error("Missing support for TUN/TAP devices"); return -ENODEV; } diff --git a/drivers/atmodem/gprs.c b/drivers/atmodem/gprs.c index 94c7d058..df37d05f 100644 --- a/drivers/atmodem/gprs.c +++ b/drivers/atmodem/gprs.c @@ -327,6 +327,26 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data) ofono_gprs_bearer_notify(gprs, bearer); } +static void huawei_hcsq_notify(GAtResult *result, gpointer user_data) +{ + struct ofono_gprs *gprs = user_data; + GAtResultIter iter; + const char *mode; + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "^HCSQ:")) + return; + + if (!g_at_result_iter_next_string(&iter, &mode)) + return; + + if (!strcmp("LTE", mode)) + ofono_gprs_bearer_notify(gprs, 7); /* LTE */ + + /* in other modes, notification ^MODE is used */ +} + static void telit_mode_notify(GAtResult *result, gpointer user_data) { struct ofono_gprs *gprs = user_data; @@ -432,6 +452,8 @@ static void gprs_initialized(gboolean ok, GAtResult *result, gpointer user_data) case OFONO_VENDOR_HUAWEI: g_at_chat_register(gd->chat, "^MODE:", huawei_mode_notify, FALSE, gprs, NULL); + g_at_chat_register(gd->chat, "^HCSQ:", huawei_hcsq_notify, + FALSE, gprs, NULL); break; case OFONO_VENDOR_UBLOX: case OFONO_VENDOR_UBLOX_TOBY_L2: diff --git a/drivers/atmodem/lte.c b/drivers/atmodem/lte.c new file mode 100644 index 00000000..61a4cd2b --- /dev/null +++ b/drivers/atmodem/lte.c @@ -0,0 +1,142 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "gatchat.h" +#include "gatresult.h" + +#include "atmodem.h" + +struct lte_driver_data { + GAtChat *chat; +}; + +static void at_lte_set_default_attach_info_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_lte_cb_t cb = cbd->cb; + struct ofono_error error; + + DBG("ok %d", ok); + + decode_at_error(&error, g_at_result_final_response(result)); + cb(&error, cbd->data); +} + +static void at_lte_set_default_attach_info(const struct ofono_lte *lte, + const struct ofono_lte_default_attach_info *info, + ofono_lte_cb_t cb, void *data) +{ + struct lte_driver_data *ldd = ofono_lte_get_data(lte); + char buf[32 + OFONO_GPRS_MAX_APN_LENGTH + 1]; + struct cb_data *cbd = cb_data_new(cb, data); + + DBG("LTE config with APN: %s", info->apn); + + if (strlen(info->apn) > 0) + snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\",\"%s\"", + info->apn); + else + snprintf(buf, sizeof(buf), "AT+CGDCONT=0,\"IP\""); + + /* We can't do much in case of failure so don't check response. */ + if (g_at_chat_send(ldd->chat, buf, NULL, + at_lte_set_default_attach_info_cb, cbd, g_free) > 0) + return; + + CALLBACK_WITH_FAILURE(cb, data); +} + +static gboolean lte_delayed_register(gpointer user_data) +{ + struct ofono_lte *lte = user_data; + + ofono_lte_register(lte); + + return FALSE; +} + +static int at_lte_probe(struct ofono_lte *lte, void *data) +{ + GAtChat *chat = data; + struct lte_driver_data *ldd; + + DBG("at lte probe"); + + ldd = g_try_new0(struct lte_driver_data, 1); + if (!ldd) + return -ENOMEM; + + ldd->chat = g_at_chat_clone(chat); + + ofono_lte_set_data(lte, ldd); + + g_idle_add(lte_delayed_register, lte); + + return 0; +} + +static void at_lte_remove(struct ofono_lte *lte) +{ + struct lte_driver_data *ldd = ofono_lte_get_data(lte); + + DBG("at lte remove"); + + g_at_chat_unref(ldd->chat); + + ofono_lte_set_data(lte, NULL); + + g_free(ldd); +} + +static struct ofono_lte_driver driver = { + .name = "atmodem", + .probe = at_lte_probe, + .remove = at_lte_remove, + .set_default_attach_info = at_lte_set_default_attach_info, +}; + +void at_lte_init(void) +{ + ofono_lte_driver_register(&driver); +} + +void at_lte_exit(void) +{ + ofono_lte_driver_unregister(&driver); +} diff --git a/drivers/atmodem/network-registration.c b/drivers/atmodem/network-registration.c index c2df0ce1..a5e2af3d 100644 --- a/drivers/atmodem/network-registration.c +++ b/drivers/atmodem/network-registration.c @@ -1088,6 +1088,27 @@ static void huawei_mode_notify(GAtResult *result, gpointer user_data) } } +static void huawei_hcsq_notify(GAtResult *result, gpointer user_data) +{ + struct ofono_netreg *netreg = user_data; + struct netreg_data *nd = ofono_netreg_get_data(netreg); + GAtResultIter iter; + const char *mode; + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "^HCSQ:")) + return; + + if (!g_at_result_iter_next_string(&iter, &mode)) + return; + + if (!strcmp("LTE", mode)) + nd->tech = ACCESS_TECHNOLOGY_EUTRAN; + + /* for other technologies, notification ^MODE is used */ +} + static void huawei_nwtime_notify(GAtResult *result, gpointer user_data) { struct ofono_netreg *netreg = user_data; @@ -1896,6 +1917,10 @@ static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data) g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify, FALSE, netreg, NULL); + /* Register for 4G system mode reports */ + g_at_chat_register(nd->chat, "^HCSQ:", huawei_hcsq_notify, + FALSE, netreg, NULL); + /* Register for network time reports */ g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify, FALSE, netreg, NULL); diff --git a/drivers/cdmamodem/connman.c b/drivers/cdmamodem/connman.c index 8c3265a1..7f0f54b6 100644 --- a/drivers/cdmamodem/connman.c +++ b/drivers/cdmamodem/connman.c @@ -43,7 +43,7 @@ #include "cdmamodem.h" #include "drivers/atmodem/vendor.h" -#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun" +#define TUN_DEV "/dev/net/tun" #define STATIC_IP_NETMASK "255.255.255.255" @@ -285,7 +285,7 @@ static int cdma_connman_probe(struct ofono_cdma_connman *cm, DBG(""); - if (stat(TUN_SYSFS_DIR, &st) < 0) { + if (stat(TUN_DEV, &st) < 0) { ofono_error("Missing support for TUN/TAP devices"); return -ENODEV; } diff --git a/drivers/ifxmodem/gprs-context.c b/drivers/ifxmodem/gprs-context.c index b7b102b9..52a3672c 100644 --- a/drivers/ifxmodem/gprs-context.c +++ b/drivers/ifxmodem/gprs-context.c @@ -42,7 +42,7 @@ #include "ifxmodem.h" -#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun" +#define TUN_DEV "/dev/net/tun" #define STATIC_IP_NETMASK "255.255.255.255" @@ -470,7 +470,7 @@ static int ifx_gprs_context_probe(struct ofono_gprs_context *gc, DBG(""); - if (stat(TUN_SYSFS_DIR, &st) < 0) { + if (stat(TUN_DEV, &st) < 0) { ofono_error("Missing support for TUN/TAP devices"); return -ENODEV; } diff --git a/drivers/isimodem/sim.c b/drivers/isimodem/sim.c index 4379a159..9e86d870 100644 --- a/drivers/isimodem/sim.c +++ b/drivers/isimodem/sim.c @@ -646,8 +646,31 @@ error: /* ISI callback: PIN state (enabled/disabled) query */ static void sec_code_state_resp_cb(const GIsiMessage *msg, void *opaque) { - check_sec_response(msg, opaque, SEC_CODE_STATE_OK_RESP, - SEC_CODE_STATE_FAIL_RESP); + struct isi_cb_data *cbd = opaque; + ofono_query_facility_lock_cb_t cb = cbd->cb; + int locked; + uint8_t state; + uint8_t status; + + if (!g_isi_msg_data_get_byte(msg, 0, &state) || + !g_isi_msg_data_get_byte(msg, 1, &status)) + goto error; + + if (state != SEC_CODE_STATE_OK_RESP) + goto error; + + if (status == SEC_CODE_ENABLE) + locked = 1; + else if (status == SEC_CODE_DISABLE) + locked = 0; + else + goto error; + + CALLBACK_WITH_SUCCESS(cb, locked, cbd->data); + return; + +error: + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); } static void isi_query_locked(struct ofono_sim *sim, diff --git a/drivers/qmimodem/nas.h b/drivers/qmimodem/nas.h index 6608ae5e..9f67707e 100644 --- a/drivers/qmimodem/nas.h +++ b/drivers/qmimodem/nas.h @@ -35,6 +35,8 @@ #define QMI_NAS_SS_INFO_IND 36 /* Current serving system info indication */ #define QMI_NAS_GET_HOME_INFO 37 /* Get info about home network */ +#define QMI_NAS_SET_SYSTEM_SELECTION_PREF 51 +#define QMI_NAS_GET_SYSTEM_SELECTION_PREF 52 /* Set NAS state report conditions */ #define QMI_NAS_PARAM_REPORT_SIGNAL_STRENGTH 0x10 @@ -176,4 +178,13 @@ struct qmi_nas_home_network { char desc[0]; } __attribute__((__packed__)); +#define QMI_NAS_RAT_MODE_PREF_ANY (-1) +#define QMI_NAS_RAT_MODE_PREF_GSM (1 << 2) +#define QMI_NAS_RAT_MODE_PREF_UMTS (1 << 3) +#define QMI_NAS_RAT_MODE_PREF_LTE (1 << 4) + +#define QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE 0x11 + +#define QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE 0x11 + int qmi_nas_rat_to_tech(uint8_t rat); diff --git a/drivers/qmimodem/network-registration.c b/drivers/qmimodem/network-registration.c index d7f96503..c1760b83 100644 --- a/drivers/qmimodem/network-registration.c +++ b/drivers/qmimodem/network-registration.c @@ -48,14 +48,14 @@ static bool extract_ss_info_time( struct qmi_result *result, struct ofono_network_time *time) { - const struct qmi_nas_3gpp_time *time_3gpp= NULL; + const struct qmi_nas_3gpp_time *time_3gpp = NULL; uint8_t dst_3gpp; bool dst_3gpp_valid; uint16_t len; /* parse 3gpp time & dst */ dst_3gpp_valid = qmi_result_get_uint8(result, QMI_NAS_RESULT_3GGP_DST, - &dst_3gpp); + &dst_3gpp); time_3gpp = qmi_result_get(result, QMI_NAS_RESULT_3GPP_TIME, &len); if (time_3gpp && len == sizeof(struct qmi_nas_3gpp_time) && @@ -65,7 +65,7 @@ static bool extract_ss_info_time( time->mday = time_3gpp->day; time->hour = time_3gpp->hour; time->min = time_3gpp->minute; - time->sec= time_3gpp->second; + time->sec = time_3gpp->second; time->utcoff = time_3gpp->timezone * 15 * 60; time->dst = dst_3gpp; return true; @@ -487,10 +487,11 @@ static void event_notify(struct qmi_result *result, void *user_data) if (ss) { int strength; - DBG("signal with %d dBm on %d", ss->dbm, ss->rat); - strength = dbm_to_strength(ss->dbm); + DBG("signal with %d%%(%d dBm) on %d", + strength, ss->dbm, ss->rat); + ofono_netreg_strength_notify(netreg, strength); } @@ -510,10 +511,17 @@ static void event_notify(struct qmi_result *result, void *user_data) static void set_event_cb(struct qmi_result *result, void *user_data) { struct ofono_netreg *netreg = user_data; + struct netreg_data *data = ofono_netreg_get_data(netreg); DBG(""); ofono_netreg_register(netreg); + + qmi_service_register(data->nas, QMI_NAS_EVENT, + event_notify, netreg, NULL); + + qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND, + ss_info_notify, netreg, NULL); } static void create_nas_cb(struct qmi_service *service, void *user_data) @@ -535,12 +543,6 @@ static void create_nas_cb(struct qmi_service *service, void *user_data) data->nas = qmi_service_ref(service); - qmi_service_register(data->nas, QMI_NAS_EVENT, - event_notify, netreg, NULL); - - qmi_service_register(data->nas, QMI_NAS_SS_INFO_IND, - ss_info_notify, netreg, NULL); - param = qmi_param_new(); if (!param) goto done; diff --git a/drivers/qmimodem/qmi.c b/drivers/qmimodem/qmi.c index 9530f0cb..736a3217 100644 --- a/drivers/qmimodem/qmi.c +++ b/drivers/qmimodem/qmi.c @@ -37,6 +37,7 @@ #include +#include "qmibridge.h" #include "qmi.h" #include "ctl.h" @@ -651,6 +652,8 @@ static gboolean can_write_data(GIOChannel *channel, GIOCondition cond, __debug_msg(' ', req->buf, bytes_written, device->debug_func, device->debug_data); + qmibridge_decode_req(req->buf, req->len); + hdr = req->buf; if (hdr->service == QMI_SERVICE_CONTROL) @@ -838,6 +841,7 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond, __hexdump('<', buf, bytes_read, device->debug_func, device->debug_data); + qmibridge_decode_read(buf, bytes_read); offset = 0; while (offset < bytes_read) { @@ -1136,15 +1140,12 @@ static void discover_callback(uint16_t message, uint16_t length, if (type == QMI_SERVICE_CONTROL) { device->control_major = major; device->control_minor = minor; - continue; } - list[count].type = type; - list[count].major = major; - list[count].minor = minor; - list[count].name = name; - - count++; + list[i].type = type; + list[i].major = major; + list[i].minor = minor; + list[i].name = name; if (name) __debug_device(device, "found service [%s %d.%d]", @@ -1153,6 +1154,7 @@ static void discover_callback(uint16_t message, uint16_t length, __debug_device(device, "found service [%d %d.%d]", type, major, minor); } + count = service_list->count; ptr = tlv_get(buffer, length, 0x10, &len); if (!ptr) @@ -1162,11 +1164,6 @@ static void discover_callback(uint16_t message, uint16_t length, service_list = ptr + *((uint8_t *) ptr) + 1; - for (i = 0; i < service_list->count; i++) { - if (service_list->services[i].type == QMI_SERVICE_CONTROL) - continue; - } - done: device->version_list = list; device->version_count = count; @@ -1767,6 +1764,27 @@ bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type, return true; } +bool qmi_result_get_int16(struct qmi_result *result, uint8_t type, + int16_t *value) +{ + const unsigned char *ptr; + uint16_t len, tmp; + + if (!result || !type) + return false; + + ptr = tlv_get(result->data, result->length, type, &len); + if (!ptr) + return false; + + memcpy(&tmp, ptr, 2); + + if (value) + *value = GINT16_FROM_LE(tmp); + + return true; +} + bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type, uint16_t *value) { diff --git a/drivers/qmimodem/qmi.h b/drivers/qmimodem/qmi.h index f0453cc6..1229ab13 100644 --- a/drivers/qmimodem/qmi.h +++ b/drivers/qmimodem/qmi.h @@ -136,6 +136,8 @@ const void *qmi_result_get(struct qmi_result *result, uint8_t type, char *qmi_result_get_string(struct qmi_result *result, uint8_t type); bool qmi_result_get_uint8(struct qmi_result *result, uint8_t type, uint8_t *value); +bool qmi_result_get_int16(struct qmi_result *result, uint8_t type, + int16_t *value); bool qmi_result_get_uint16(struct qmi_result *result, uint8_t type, uint16_t *value); bool qmi_result_get_uint32(struct qmi_result *result, uint8_t type, diff --git a/drivers/qmimodem/qmibridge.c b/drivers/qmimodem/qmibridge.c new file mode 100644 index 00000000..914a1b9a --- /dev/null +++ b/drivers/qmimodem/qmibridge.c @@ -0,0 +1,40 @@ + +#include + +#include +#include + +#include + +#include + +static void ask_qmi(const char *prefix, void *data, size_t len) +{ + /* from osmo-qcdiag */ + GByteArray *buffer; + GError *error = NULL; + QmiMessage *message; + gchar *printable; + + buffer = g_byte_array_sized_new(len); + g_byte_array_append(buffer, data, len); + + message = qmi_message_new_from_raw(buffer, &error); + if (!message) { + fprintf(stderr, "qmi_message_new_from_raw() returned NULL\n"); + return; + } + + printable = qmi_message_get_printable(message, "QMI "); + DBG("%s: %s", prefix, printable); + g_free(printable); +} +void qmibridge_decode_read(void *data, size_t len) +{ + ask_qmi("READ", data, len); +} + +void qmibridge_decode_req(void *data, size_t len) +{ + ask_qmi("_REQ", data, len); +} diff --git a/drivers/qmimodem/qmibridge.h b/drivers/qmimodem/qmibridge.h new file mode 100644 index 00000000..96f8adc5 --- /dev/null +++ b/drivers/qmimodem/qmibridge.h @@ -0,0 +1,3 @@ + +void qmibridge_decode_read(void *data, size_t len); +void qmibridge_decode_req(void *data, size_t len); diff --git a/drivers/qmimodem/radio-settings.c b/drivers/qmimodem/radio-settings.c index 04106ea3..aa8e0d5c 100644 --- a/drivers/qmimodem/radio-settings.c +++ b/drivers/qmimodem/radio-settings.c @@ -29,15 +29,202 @@ #include "qmi.h" #include "nas.h" +#include "dms.h" #include "qmimodem.h" struct settings_data { struct qmi_service *nas; + struct qmi_service *dms; uint16_t major; uint16_t minor; }; +static void get_system_selection_pref_cb(struct qmi_result *result, + void* user_data) +{ + struct cb_data *cbd = user_data; + ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb; + enum ofono_radio_access_mode mode = OFONO_RADIO_ACCESS_MODE_ANY; + uint16_t pref; + + DBG(""); + + if (qmi_result_set_error(result, NULL)) { + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); + return; + } + + qmi_result_get_uint16(result, + QMI_NAS_RESULT_SYSTEM_SELECTION_PREF_MODE, &pref); + + switch (pref) { + case QMI_NAS_RAT_MODE_PREF_GSM: + mode = OFONO_RADIO_ACCESS_MODE_GSM; + break; + case QMI_NAS_RAT_MODE_PREF_UMTS: + mode = OFONO_RADIO_ACCESS_MODE_UMTS; + break; + case QMI_NAS_RAT_MODE_PREF_LTE: + mode = OFONO_RADIO_ACCESS_MODE_LTE; + break; + } + + CALLBACK_WITH_SUCCESS(cb, mode, cbd->data); +} + +static void qmi_query_rat_mode(struct ofono_radio_settings *rs, + ofono_radio_settings_rat_mode_query_cb_t cb, + void *user_data) +{ + struct settings_data *data = ofono_radio_settings_get_data(rs); + struct cb_data *cbd = cb_data_new(cb, user_data); + + DBG(""); + + if (qmi_service_send(data->nas, + QMI_NAS_GET_SYSTEM_SELECTION_PREF, NULL, + get_system_selection_pref_cb, cbd, g_free) > 0) + return; + + CALLBACK_WITH_FAILURE(cb, -1, data); +} + +static void set_system_selection_pref_cb(struct qmi_result *result, + void* user_data) +{ + struct cb_data *cbd = user_data; + ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb; + + DBG(""); + + if (qmi_result_set_error(result, NULL)) { + CALLBACK_WITH_FAILURE(cb, cbd->data); + return; + } + + CALLBACK_WITH_SUCCESS(cb, cbd->data); +} + +static void qmi_set_rat_mode(struct ofono_radio_settings *rs, + enum ofono_radio_access_mode mode, + ofono_radio_settings_rat_mode_set_cb_t cb, + void *user_data) +{ + struct settings_data *data = ofono_radio_settings_get_data(rs); + struct cb_data *cbd = cb_data_new(cb, user_data); + uint16_t pref = QMI_NAS_RAT_MODE_PREF_ANY; + struct qmi_param *param; + + DBG(""); + + switch (mode) { + case OFONO_RADIO_ACCESS_MODE_ANY: + pref = QMI_NAS_RAT_MODE_PREF_ANY; + break; + case OFONO_RADIO_ACCESS_MODE_GSM: + pref = QMI_NAS_RAT_MODE_PREF_GSM; + break; + case OFONO_RADIO_ACCESS_MODE_UMTS: + pref = QMI_NAS_RAT_MODE_PREF_UMTS; + break; + case OFONO_RADIO_ACCESS_MODE_LTE: + pref = QMI_NAS_RAT_MODE_PREF_LTE; + break; + } + + param = qmi_param_new(); + if (!param) { + CALLBACK_WITH_FAILURE(cb, user_data); + return; + } + + qmi_param_append_uint16(param, QMI_NAS_PARAM_SYSTEM_SELECTION_PREF_MODE, + pref); + + if (qmi_service_send(data->nas, + QMI_NAS_SET_SYSTEM_SELECTION_PREF, param, + set_system_selection_pref_cb, cbd, g_free) > 0) + return; + + qmi_param_free(param); + CALLBACK_WITH_FAILURE(cb, user_data); + g_free(cbd); +} + +static void get_caps_cb(struct qmi_result *result, void *user_data) +{ + struct cb_data *cbd = user_data; + ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb; + const struct qmi_dms_device_caps *caps; + unsigned int available_rats; + uint16_t len; + uint8_t i; + + DBG(""); + + if (qmi_result_set_error(result, NULL)) + goto error; + + caps = qmi_result_get(result, QMI_DMS_RESULT_DEVICE_CAPS, &len); + if (!caps) + goto error; + + available_rats = 0; + for (i = 0; i < caps->radio_if_count; i++) { + switch (caps->radio_if[i]) { + case QMI_DMS_RADIO_IF_GSM: + available_rats |= OFONO_RADIO_ACCESS_MODE_GSM; + break; + case QMI_DMS_RADIO_IF_UMTS: + available_rats |= OFONO_RADIO_ACCESS_MODE_UMTS; + break; + case QMI_DMS_RADIO_IF_LTE: + available_rats |= OFONO_RADIO_ACCESS_MODE_LTE; + break; + } + } + + CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data); + + return; + +error: + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); +} + +static void qmi_query_available_rats(struct ofono_radio_settings *rs, + ofono_radio_settings_available_rats_query_cb_t cb, + void *data) +{ + struct settings_data *rsd = ofono_radio_settings_get_data(rs); + struct cb_data *cbd = cb_data_new(cb, data); + + if (!rsd->dms) + goto error; + + if (qmi_service_send(rsd->dms, QMI_DMS_GET_CAPS, NULL, + get_caps_cb, cbd, g_free) > 0) + return; + +error: + g_free(cbd); + CALLBACK_WITH_FAILURE(cb, -1, data); +} + +static void create_dms_cb(struct qmi_service *service, void *user_data) +{ + struct ofono_radio_settings *rs = user_data; + struct settings_data *data = ofono_radio_settings_get_data(rs); + + DBG(""); + + if (!service) + return; + + data->dms = qmi_service_ref(service); +} + static void create_nas_cb(struct qmi_service *service, void *user_data) { struct ofono_radio_settings *rs = user_data; @@ -74,11 +261,12 @@ static int qmi_radio_settings_probe(struct ofono_radio_settings *rs, ofono_radio_settings_set_data(rs, data); + qmi_service_create_shared(device, QMI_SERVICE_DMS, + create_dms_cb, rs, NULL); qmi_service_create_shared(device, QMI_SERVICE_NAS, create_nas_cb, rs, NULL); return 0; - } static void qmi_radio_settings_remove(struct ofono_radio_settings *rs) @@ -100,6 +288,9 @@ static struct ofono_radio_settings_driver driver = { .name = "qmimodem", .probe = qmi_radio_settings_probe, .remove = qmi_radio_settings_remove, + .set_rat_mode = qmi_set_rat_mode, + .query_rat_mode = qmi_query_rat_mode, + .query_available_rats = qmi_query_available_rats, }; void qmi_radio_settings_init(void) diff --git a/drivers/qmimodem/sms.c b/drivers/qmimodem/sms.c index 91501b75..3f4bdeb2 100644 --- a/drivers/qmimodem/sms.c +++ b/drivers/qmimodem/sms.c @@ -277,7 +277,7 @@ static void qmi_bearer_query(struct ofono_sms *sms, DBG(""); - if (data->major < 1 && data->minor < 2) + if (data->major < 1 || (data->major == 1 && data->minor < 2)) goto error; if (qmi_service_send(data->wms, QMI_WMS_GET_DOMAIN_PREF, NULL, @@ -315,7 +315,7 @@ static void qmi_bearer_set(struct ofono_sms *sms, int bearer, DBG("bearer %d", bearer); - if (data->major < 1 && data->minor < 2) + if (data->major < 1 || (data->major == 1 && data->minor < 2)) goto error; domain = bearer_to_domain(bearer); diff --git a/drivers/qmimodem/voicecall.c b/drivers/qmimodem/voicecall.c index c7c54d8a..ff54a469 100644 --- a/drivers/qmimodem/voicecall.c +++ b/drivers/qmimodem/voicecall.c @@ -65,6 +65,9 @@ static void all_call_status_ind(struct qmi_result *result, void *user_data) int i; int size = 0; struct qmi_voice_all_call_status_ind status_ind; + GSList *n, *o; + struct ofono_call *nc, *oc; + if (qmi_voice_ind_call_status(result, &status_ind) != NONE) { DBG("Parsing of all call status indication failed"); @@ -112,7 +115,7 @@ static void all_call_status_ind(struct qmi_result *result, void *user_data) call->type = 0; /* always voice */ number_size = remote_party->number_size; if (number_size > OFONO_MAX_PHONE_NUMBER_LENGTH) - number_size = OFONO_MAX_PHONE_NUMBER_LENGTH; + OFONO_MAX_PHONE_NUMBER_LENGTH; strncpy(call->phone_number.number, remote_party->number, number_size); /* FIXME: set phone_number_type */ @@ -201,6 +204,7 @@ static void dial_cb(struct qmi_result *result, void *user_data) ofono_voicecall_cb_t cb = cbd->cb; uint16_t error; struct qmi_voice_dial_call_result dial_result; + struct ofono_call *call; if (qmi_result_set_error(result, &error)) { DBG("QMI Error %d", error); @@ -262,9 +266,11 @@ static void dial(struct ofono_voicecall *vc, const struct ofono_phone_number *ph static void answer_cb(struct qmi_result *result, void *user_data) { struct cb_data *cbd = user_data; + struct ofono_voicecall *vc = cbd->user; ofono_voicecall_cb_t cb = cbd->cb; uint16_t error; struct qmi_voice_answer_call_result answer_result; + struct ofono_call *call; if (qmi_result_set_error(result, &error)) { DBG("QMI Error %d", error); @@ -322,9 +328,11 @@ err: static void end_cb(struct qmi_result *result, void *user_data) { struct cb_data *cbd = user_data; + struct ofono_voicecall *vc = cbd->user; ofono_voicecall_cb_t cb = cbd->cb; uint16_t error; struct qmi_voice_end_call_result end_result; + struct ofono_call *call; if (qmi_result_set_error(result, &error)) { DBG("QMI Error %d", error); @@ -347,6 +355,7 @@ static void release_specific(struct ofono_voicecall *vc, int id, struct voicecall_data *vd = ofono_voicecall_get_data(vc); struct cb_data *cbd = cb_data_new(cb, data); struct qmi_voice_end_call_arg arg; + int i; DBG(""); cbd->user = vc; @@ -369,19 +378,21 @@ static void hangup_active(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data) { struct voicecall_data *vd = ofono_voicecall_get_data(vc); + struct qmi_voice_end_call_arg arg; struct ofono_call *call; GSList *list = NULL; enum call_status active[] = { CALL_STATUS_ACTIVE, CALL_STATUS_DIALING, - CALL_STATUS_ALERTING + CALL_STATUS_ALERTING, + CALL_STATUS_INCOMING, }; int i; DBG(""); for (i = 0; i < ARRAY_SIZE(active); i++) { list = g_slist_find_custom(vd->call_list, - GINT_TO_POINTER(CALL_STATUS_ACTIVE), + GINT_TO_POINTER(active[i]), ofono_call_compare_by_status); if (list) diff --git a/drivers/rilmodem/netmon.c b/drivers/rilmodem/netmon.c index f7f7c28c..709997c5 100644 --- a/drivers/rilmodem/netmon.c +++ b/drivers/rilmodem/netmon.c @@ -61,6 +61,9 @@ /* size of RIL_CellInfoTdscdma */ #define NETMON_RIL_CELLINFO_SIZE_TDSCDMA 24 +#define MSECS_RATE_INVALID (0x7fffffff) +#define SECS_TO_MSECS(x) ((x) * 1000) + struct netmon_data { GRil *ril; }; @@ -96,11 +99,9 @@ static int ril_cell_type_to_size(int cell_type) return 0; } -static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data) +static int process_cellinfo_list(struct ril_msg *message, + struct ofono_netmon *netmon) { - struct cb_data *cbd = user_data; - ofono_netmon_cb_t cb = cbd->cb; - struct ofono_netmon *netmon = cbd->data; struct parcel rilp; int skip_len; int cell_info_cnt; @@ -114,7 +115,7 @@ static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data) int i, j; if (message->error != RIL_E_SUCCESS) - goto error; + return OFONO_ERROR_TYPE_FAILURE; g_ril_init_parcel(message, &rilp); @@ -146,7 +147,7 @@ static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data) } if (!registered) - goto error; + return OFONO_ERROR_TYPE_FAILURE; if (cell_type == NETMON_RIL_CELLINFO_TYPE_GSM) { mcc = parcel_r_int32(&rilp); @@ -216,17 +217,53 @@ static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data) OFONO_NETMON_INFO_BER, ber, OFONO_NETMON_INFO_INVALID); - } else { - goto error; } - CALLBACK_WITH_SUCCESS(cb, cbd->data); - return; + return OFONO_ERROR_TYPE_NO_ERROR; +} + +static void ril_netmon_update_cb(struct ril_msg *message, gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_netmon_cb_t cb = cbd->cb; + struct ofono_netmon *netmon = cbd->data; + + if (process_cellinfo_list(message, netmon) == + OFONO_ERROR_TYPE_NO_ERROR) { + CALLBACK_WITH_SUCCESS(cb, cbd->data); + return; + } -error: CALLBACK_WITH_FAILURE(cb, cbd->data); } +static void ril_cellinfo_notify(struct ril_msg *message, gpointer user_data) +{ + struct ofono_netmon *netmon = user_data; + + process_cellinfo_list(message, netmon); +} + +static void setup_cell_info_notify(struct ofono_netmon *netmon) +{ + struct netmon_data *nmd = ofono_netmon_get_data(netmon); + struct parcel rilp; + + parcel_init(&rilp); + + parcel_w_int32(&rilp, 1); /* Number of elements */ + + parcel_w_int32(&rilp, MSECS_RATE_INVALID); + + if (g_ril_send(nmd->ril, RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, + &rilp, NULL, NULL, NULL) == 0) + ofono_error("%s: setup failed\n", __func__); + + if (g_ril_register(nmd->ril, RIL_UNSOL_CELL_INFO_LIST, + ril_cellinfo_notify, netmon) == 0) + ofono_error("%s: setup failed\n", __func__); +} + static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor, void *user) { @@ -237,6 +274,8 @@ static int ril_netmon_probe(struct ofono_netmon *netmon, ofono_netmon_set_data(netmon, ud); + setup_cell_info_notify(netmon); + g_idle_add(ril_delayed_register, netmon); return 0; @@ -257,18 +296,55 @@ static void ril_netmon_request_update(struct ofono_netmon *netmon, struct cb_data *cbd = cb_data_new(cb, data, nmd); if (g_ril_send(nmd->ril, RIL_REQUEST_GET_CELL_INFO_LIST, NULL, - ril_netmon_update_cb, cbd, NULL) > 0) + ril_netmon_update_cb, cbd, g_free) > 0) return; g_free(cbd); CALLBACK_WITH_FAILURE(cb, data); } +static void periodic_update_cb(struct ril_msg *message, gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_netmon_cb_t cb = cbd->cb; + + if (message->error != RIL_E_SUCCESS) + CALLBACK_WITH_FAILURE(cb, cbd->data); + + CALLBACK_WITH_SUCCESS(cb, cbd->data); +} + +static void ril_netmon_periodic_update(struct ofono_netmon *netmon, + unsigned int enable, unsigned int period, + ofono_netmon_cb_t cb, void *data) +{ + struct netmon_data *nmd = ofono_netmon_get_data(netmon); + struct cb_data *cbd = cb_data_new(cb, data, nmd); + struct parcel rilp; + + parcel_init(&rilp); + + parcel_w_int32(&rilp, 1); /* Number of elements */ + + if (enable) + parcel_w_int32(&rilp, SECS_TO_MSECS(period)); + else + parcel_w_int32(&rilp, MSECS_RATE_INVALID); + + if (g_ril_send(nmd->ril, RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, + &rilp, periodic_update_cb, cbd, g_free) > 0) + return; + + g_free(cbd); + CALLBACK_WITH_FAILURE(cb, cbd->data); +} + static struct ofono_netmon_driver driver = { .name = RILMODEM, .probe = ril_netmon_probe, .remove = ril_netmon_remove, .request_update = ril_netmon_request_update, + .enable_periodic_update = ril_netmon_periodic_update, }; void ril_netmon_init(void) diff --git a/drivers/xmm7modem/radio-settings.c b/drivers/xmm7modem/radio-settings.c new file mode 100644 index 00000000..f22c388a --- /dev/null +++ b/drivers/xmm7modem/radio-settings.c @@ -0,0 +1,233 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "gatchat.h" +#include "gatresult.h" + +#include "xmm7modem.h" + +static const char *none_prefix[] = { NULL }; +static const char *xact_prefix[] = { "+XACT:", NULL }; + +struct radio_settings_data { + GAtChat *chat; +}; + +static void xact_query_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb; + enum ofono_radio_access_mode mode; + struct ofono_error error; + GAtResultIter iter; + int value, preferred; + + decode_at_error(&error, g_at_result_final_response(result)); + + if (!ok) { + cb(&error, -1, cbd->data); + return; + } + + g_at_result_iter_init(&iter, result); + + if (g_at_result_iter_next(&iter, "+XACT:") == FALSE) + goto error; + + if (g_at_result_iter_next_number(&iter, &value) == FALSE) + goto error; + + if (g_at_result_iter_next_number(&iter, &preferred) == FALSE) + goto error; + + switch (value) { + case 0: + mode = OFONO_RADIO_ACCESS_MODE_GSM; + break; + case 1: + mode = OFONO_RADIO_ACCESS_MODE_UMTS; + break; + case 2: + mode = OFONO_RADIO_ACCESS_MODE_LTE; + break; + case 3: + mode = OFONO_RADIO_ACCESS_MODE_UMTS; + break; + case 4: + mode = OFONO_RADIO_ACCESS_MODE_LTE; + break; + case 5: + mode = OFONO_RADIO_ACCESS_MODE_LTE; + break; + case 6: + mode = OFONO_RADIO_ACCESS_MODE_ANY; + break; + default: + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); + return; + } + + cb(&error, mode, cbd->data); + + return; + +error: + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); +} + +static void xmm_query_rat_mode(struct ofono_radio_settings *rs, + ofono_radio_settings_rat_mode_query_cb_t cb, + void *data) +{ + struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs); + struct cb_data *cbd = cb_data_new(cb, data); + + if (g_at_chat_send(rsd->chat, "AT+XACT?", xact_prefix, + xact_query_cb, cbd, g_free) > 0) + return; + + CALLBACK_WITH_FAILURE(cb, -1, data); + g_free(cbd); +} + +static void xact_modify_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb; + struct ofono_error error; + + decode_at_error(&error, g_at_result_final_response(result)); + cb(&error, cbd->data); +} + +static void xmm_set_rat_mode(struct ofono_radio_settings *rs, + enum ofono_radio_access_mode mode, + ofono_radio_settings_rat_mode_set_cb_t cb, + void *data) +{ + struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs); + struct cb_data *cbd = cb_data_new(cb, data); + char buf[20]; + int value = 6, preferred = 2; + + switch (mode) { + case OFONO_RADIO_ACCESS_MODE_ANY: + value = 6; + break; + case OFONO_RADIO_ACCESS_MODE_GSM: + value = 0; + break; + case OFONO_RADIO_ACCESS_MODE_UMTS: + value = 1; + break; + case OFONO_RADIO_ACCESS_MODE_LTE: + value = 2; + break; + } + + if (value == 6) + snprintf(buf, sizeof(buf), "AT+XACT=%u,%u", value, preferred); + else + snprintf(buf, sizeof(buf), "AT+XACT=%u", value); + + if (g_at_chat_send(rsd->chat, buf, none_prefix, + xact_modify_cb, cbd, g_free) > 0) + return; + + CALLBACK_WITH_FAILURE(cb, data); + g_free(cbd); +} + +static void xact_support_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct ofono_radio_settings *rs = user_data; + + if (!ok) { + ofono_radio_settings_remove(rs); + return; + } + + ofono_radio_settings_register(rs); +} + +static int xmm_radio_settings_probe(struct ofono_radio_settings *rs, + unsigned int vendor, void *user) +{ + GAtChat *chat = user; + struct radio_settings_data *rsd; + + rsd = g_try_new0(struct radio_settings_data, 1); + if (rsd == NULL) + return -ENOMEM; + + rsd->chat = g_at_chat_clone(chat); + + ofono_radio_settings_set_data(rs, rsd); + + g_at_chat_send(rsd->chat, "AT+XACT=?", xact_prefix, + xact_support_cb, rs, NULL); + + return 0; +} + +static void xmm_radio_settings_remove(struct ofono_radio_settings *rs) +{ + struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs); + + ofono_radio_settings_set_data(rs, NULL); + + g_at_chat_unref(rsd->chat); + g_free(rsd); +} + +static struct ofono_radio_settings_driver driver = { + .name = "xmm7modem", + .probe = xmm_radio_settings_probe, + .remove = xmm_radio_settings_remove, + .query_rat_mode = xmm_query_rat_mode, + .set_rat_mode = xmm_set_rat_mode +}; + +void xmm_radio_settings_init(void) +{ + ofono_radio_settings_driver_register(&driver); +} + +void xmm_radio_settings_exit(void) +{ + ofono_radio_settings_driver_unregister(&driver); +} diff --git a/drivers/xmm7modem/xmm7modem.c b/drivers/xmm7modem/xmm7modem.c new file mode 100644 index 00000000..db1864e0 --- /dev/null +++ b/drivers/xmm7modem/xmm7modem.c @@ -0,0 +1,50 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#define OFONO_API_SUBJECT_TO_CHANGE +#include +#include +#include + +#include "xmm7modem.h" + +static int xmm7modem_init(void) +{ + xmm_radio_settings_init(); + + return 0; +} + +static void xmm7modem_exit(void) +{ + xmm_radio_settings_exit(); +} + +OFONO_PLUGIN_DEFINE(xmm7modem, "Intel xmm7xxx series modem driver", + VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT, + xmm7modem_init, xmm7modem_exit) diff --git a/drivers/xmm7modem/xmm7modem.h b/drivers/xmm7modem/xmm7modem.h new file mode 100644 index 00000000..44fa3d62 --- /dev/null +++ b/drivers/xmm7modem/xmm7modem.h @@ -0,0 +1,27 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#define XMM7MODEM "xmm7modem" + +extern void xmm_radio_settings_init(void); +extern void xmm_radio_settings_exit(void); diff --git a/gril/grilutil.c b/gril/grilutil.c index 9e7cd315..89a6d6f7 100644 --- a/gril/grilutil.c +++ b/gril/grilutil.c @@ -338,6 +338,8 @@ const char *ril_request_id_to_string(int req) return "RIL_REQUEST_GET_CELL_INFO_LIST"; case RIL_REQUEST_SET_INITIAL_ATTACH_APN: return "RIL_REQUEST_SET_INITIAL_ATTACH_APN"; + case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE: + return "RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE"; default: return ""; } @@ -416,6 +418,8 @@ const char *ril_unsol_request_to_string(int request) return "UNSOL_EXIT_EMERGENCY_CALLBACK_MODE"; case RIL_UNSOL_RIL_CONNECTED: return "UNSOL_RIL_CONNECTED"; + case RIL_UNSOL_CELL_INFO_LIST: + return "RIL_UNSOL_CELL_INFO_LIST"; default: return ""; } diff --git a/gril/parcel.h b/gril/parcel.h index e5592ae1..46887890 100644 --- a/gril/parcel.h +++ b/gril/parcel.h @@ -23,6 +23,7 @@ #define __PARCEL_H #include +#include struct parcel { char *data; diff --git a/gril/ril_constants.h b/gril/ril_constants.h index cbc596e0..b707136f 100644 --- a/gril/ril_constants.h +++ b/gril/ril_constants.h @@ -348,6 +348,7 @@ #define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107 #define RIL_REQUEST_VOICE_RADIO_TECH 108 #define RIL_REQUEST_GET_CELL_INFO_LIST 109 +#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110 #define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111 /* RIL Unsolicited Messages */ @@ -388,6 +389,7 @@ #define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033 #define RIL_UNSOL_RIL_CONNECTED 1034 #define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035 +#define RIL_UNSOL_CELL_INFO_LIST 1036 /* Suplementary services Service class*/ #define SERVICE_CLASS_NONE 0 diff --git a/include/dbus.h b/include/dbus.h index cf68ae5f..a6519c7c 100644 --- a/include/dbus.h +++ b/include/dbus.h @@ -61,6 +61,7 @@ extern "C" { #define OFONO_HANDSFREE_INTERFACE OFONO_SERVICE ".Handsfree" #define OFONO_SIRI_INTERFACE OFONO_SERVICE ".Siri" #define OFONO_NETMON_INTERFACE OFONO_SERVICE ".NetworkMonitor" +#define OFONO_NETMON_AGENT_INTERFACE OFONO_SERVICE ".NetworkMonitorAgent" #define OFONO_LTE_INTERFACE OFONO_SERVICE ".LongTermEvolution" /* CDMA Interfaces */ diff --git a/include/gprs-context.h b/include/gprs-context.h index 7e163cc9..38e5c09d 100644 --- a/include/gprs-context.h +++ b/include/gprs-context.h @@ -29,7 +29,13 @@ extern "C" { #include struct ofono_gprs_context; +struct ofono_modem; +/* + * ETSI 123.003, Section 9.1: + * the APN has, after encoding as defined in the paragraph below, a maximum + * length of 100 octets + */ #define OFONO_GPRS_MAX_APN_LENGTH 100 #define OFONO_GPRS_MAX_USERNAME_LENGTH 63 #define OFONO_GPRS_MAX_PASSWORD_LENGTH 255 diff --git a/include/netmon.h b/include/netmon.h index 72090c32..c8fcafa6 100644 --- a/include/netmon.h +++ b/include/netmon.h @@ -39,6 +39,10 @@ struct ofono_netmon_driver { void (*remove)(struct ofono_netmon *netmon); void (*request_update)(struct ofono_netmon *netmon, ofono_netmon_cb_t cb, void *data); + void (*enable_periodic_update)(struct ofono_netmon *netmon, + unsigned int enable, + unsigned int period, + ofono_netmon_cb_t cb, void *data); }; enum ofono_netmon_cell_type { diff --git a/plugins/gemalto.c b/plugins/gemalto.c index 011713e6..45ec0cf9 100644 --- a/plugins/gemalto.c +++ b/plugins/gemalto.c @@ -25,6 +25,7 @@ #include #include +#include #include #include diff --git a/plugins/gobi.c b/plugins/gobi.c index 1acd8709..abd53450 100644 --- a/plugins/gobi.c +++ b/plugins/gobi.c @@ -252,6 +252,15 @@ error: shutdown_device(modem); } +static void create_shared_dms(void *user_data) +{ + struct ofono_modem *modem = user_data; + struct gobi_data *data = ofono_modem_get_data(modem); + + qmi_service_create_shared(data->device, QMI_SERVICE_DMS, + create_dms_cb, modem, NULL); +} + static void discover_cb(uint8_t count, const struct qmi_version *list, void *user_data) { @@ -266,6 +275,13 @@ static void discover_cb(uint8_t count, const struct qmi_version *list, list[i].type); switch (list[i].type) { + case QMI_SERVICE_CONTROL: + /* sync command resets the QMI state */ + if (list[i].major > 1 || list[i].minor >= 5) + ofono_modem_set_boolean(modem, + "SupportQMISync", + TRUE); + break; case QMI_SERVICE_DMS: data->features |= GOBI_DMS; break; @@ -314,18 +330,10 @@ static void discover_cb(uint8_t count, const struct qmi_version *list, return; } - qmi_service_create_shared(data->device, QMI_SERVICE_DMS, - create_dms_cb, modem, NULL); -} - -static void sync_cb(void *user_data) -{ - struct ofono_modem *modem = user_data; - struct gobi_data *data = ofono_modem_get_data(modem); - - DBG("modem in sync"); - - qmi_device_discover(data->device, discover_cb, modem, NULL); + if (ofono_modem_get_boolean(modem, "SupportQMISync") == TRUE) + qmi_device_sync(data->device, create_shared_dms, modem); + else + create_shared_dms(modem); } static int gobi_enable(struct ofono_modem *modem) @@ -355,7 +363,7 @@ static int gobi_enable(struct ofono_modem *modem) qmi_device_set_close_on_unref(data->device, true); - qmi_device_sync(data->device, sync_cb, modem); + qmi_device_discover(data->device, discover_cb, modem, NULL); return -EINPROGRESS; } diff --git a/plugins/udevng.c b/plugins/udevng.c index aa28bcb8..518eda8e 100644 --- a/plugins/udevng.c +++ b/plugins/udevng.c @@ -261,18 +261,34 @@ static gboolean setup_sierra(struct modem_info *modem) if (g_strcmp0(info->interface, "255/255/255") == 0) { if (g_strcmp0(info->number, "01") == 0) diag = info->devnode; - if (g_strcmp0(info->number, "03") == 0) + else if (g_strcmp0(info->number, "03") == 0) mdm = info->devnode; else if (g_strcmp0(info->number, "04") == 0) app = info->devnode; else if (g_strcmp0(info->number, "07") == 0) net = info->devnode; - else if (g_strcmp0(info->number, "0a") == 0) { - if (g_strcmp0(info->subsystem, "net") == 0) + else if (g_strcmp0(info->subsystem, "net") == 0) { + /* + * When using the voice firmware on a mc7304 + * the second cdc-wdm interface doesn't handle + * qmi messages properly. + * Some modems still have a working second + * cdc-wdm interface, some are not. But always + * the first interface works. + */ + if (g_strcmp0(info->number, "08") == 0) { net = info->devnode; - else if (g_strcmp0(info->subsystem, - "usbmisc") == 0) + } else if (g_strcmp0(info->number, "0a") == 0) { + if (net == NULL) + net = info->devnode; + } + } else if (g_strcmp0(info->subsystem, "usbmisc") == 0) { + if (g_strcmp0(info->number, "08") == 0) { qmi = info->devnode; + } else if (g_strcmp0(info->number, "0a") == 0) { + if (qmi == NULL) + qmi = info->devnode; + } } } } @@ -860,7 +876,7 @@ static gboolean setup_quectel(struct modem_info *modem) static gboolean setup_quectelqmi(struct modem_info *modem) { - const char *qmi = NULL, *net = NULL, *gps = NULL; + const char *qmi = NULL, *net = NULL, *gps = NULL, *aux = NULL; GSList *list; DBG("%s", modem->syspath); @@ -878,8 +894,11 @@ static gboolean setup_quectelqmi(struct modem_info *modem) else if (g_strcmp0(info->subsystem, "usbmisc") == 0) qmi = info->devnode; } else if (g_strcmp0(info->interface, "255/0/0") == 0 && - g_strcmp0(info->number, "02") == 0) { + g_strcmp0(info->number, "01") == 0) { gps = info->devnode; + } else if (g_strcmp0(info->interface, "255/0/0") == 0 && + g_strcmp0(info->number, "02") == 0) { + aux = info->devnode; } } @@ -893,8 +912,12 @@ static gboolean setup_quectelqmi(struct modem_info *modem) ofono_modem_set_string(modem->modem, "Device", qmi); ofono_modem_set_string(modem->modem, "NetworkInterface", net); + DBG("gps=%s aux=%s", gps, aux); + if (gps) ofono_modem_set_string(modem->modem, "GPS", gps); + if (aux) + ofono_modem_set_string(modem->modem, "Aux", aux); ofono_modem_set_driver(modem->modem, "gobi"); diff --git a/src/common.c b/src/common.c index 1185d1ce..5d127ca9 100644 --- a/src/common.c +++ b/src/common.c @@ -704,6 +704,9 @@ gboolean is_valid_apn(const char *apn) int i; int last_period = 0; + if (apn == NULL) + return FALSE; + if (apn[0] == '.' || apn[0] == '\0') return FALSE; @@ -742,6 +745,28 @@ void ofono_call_init(struct ofono_call *call) call->clip_validity = CLIP_VALIDITY_NOT_AVAILABLE; } +const char *call_status_to_string(enum call_status status) +{ + switch (status) { + case CALL_STATUS_ACTIVE: + return "active"; + case CALL_STATUS_HELD: + return "held"; + case CALL_STATUS_DIALING: + return "dialing"; + case CALL_STATUS_ALERTING: + return "alerting"; + case CALL_STATUS_INCOMING: + return "incoming"; + case CALL_STATUS_WAITING: + return "waiting"; + case CALL_STATUS_DISCONNECTED: + return "disconnected"; + } + + return "unknown"; +} + gint ofono_call_compare(gconstpointer a, gconstpointer b) { const struct ofono_call *ca = a; diff --git a/src/common.h b/src/common.h index 9166ea34..7a2e9263 100644 --- a/src/common.h +++ b/src/common.h @@ -184,6 +184,7 @@ const char *registration_tech_to_string(int tech); const char *packet_bearer_to_string(int bearer); gboolean is_valid_apn(const char *apn); +const char *call_status_to_string(enum call_status status); gint ofono_call_compare(gconstpointer a, gconstpointer b); gint ofono_call_compare_by_status(gconstpointer a, gconstpointer b); diff --git a/src/gprs.c b/src/gprs.c index e0276024..b5634472 100644 --- a/src/gprs.c +++ b/src/gprs.c @@ -2596,10 +2596,14 @@ void ofono_gprs_detached_notify(struct ofono_gprs *gprs) void ofono_gprs_status_notify(struct ofono_gprs *gprs, int status) { - DBG("%s status %d", __ofono_atom_get_path(gprs->atom), status); + DBG("%s status %s (%d)", __ofono_atom_get_path(gprs->atom), + registration_status_to_string(status), status); gprs->status = status; + if (status == 0) + ofono_gprs_detached_notify(gprs); + if (status != NETWORK_REGISTRATION_STATUS_REGISTERED && status != NETWORK_REGISTRATION_STATUS_ROAMING) { gprs_attached_update(gprs); diff --git a/src/netmon.c b/src/netmon.c index 64767830..3a495873 100644 --- a/src/netmon.c +++ b/src/netmon.c @@ -34,6 +34,7 @@ #include #include "ofono.h" +#include "netmonagent.h" #define CELL_INFO_DICT_APPEND(p_dict, key, info, type, dbus_type) do { \ type value; \ @@ -51,6 +52,7 @@ struct ofono_netmon { DBusMessage *reply; void *driver_data; struct ofono_atom *atom; + struct netmon_agent *agent; }; static const char *cell_type_to_tech_name(enum ofono_netmon_cell_type type) @@ -72,6 +74,7 @@ void ofono_netmon_serving_cell_notify(struct ofono_netmon *netmon, int info_type, ...) { va_list arglist; + DBusMessage *agent_notify = NULL; DBusMessageIter iter; DBusMessageIter dict; enum ofono_netmon_info next_info_type = info_type; @@ -79,13 +82,18 @@ void ofono_netmon_serving_cell_notify(struct ofono_netmon *netmon, char *mcc; char *mnc; int intval; - netmon->reply = dbus_message_new_method_return(netmon->pending); - if (netmon->reply == NULL) + if (netmon->pending != NULL) { + netmon->reply = dbus_message_new_method_return(netmon->pending); + dbus_message_iter_init_append(netmon->reply, &iter); + } else if (netmon->agent != NULL) { + agent_notify = netmon_agent_new_method_call(netmon->agent, + "ServingCellInformationChanged"); + + dbus_message_iter_init_append(agent_notify, &iter); + } else return; - dbus_message_iter_init_append(netmon->reply, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, OFONO_PROPERTIES_ARRAY_SIGNATURE, &dict); @@ -243,6 +251,9 @@ done: va_end(arglist); dbus_message_iter_close_container(&iter, &dict); + + if (agent_notify) + netmon_agent_send_no_reply(netmon->agent, agent_notify); } static void serving_cell_info_callback(const struct ofono_error *error, @@ -291,10 +302,117 @@ static DBusMessage *netmon_get_serving_cell_info(DBusConnection *conn, return NULL; } +static void periodic_updates_enabled_cb(const struct ofono_error *error, + void *data) +{ + struct ofono_netmon *netmon = data; + + if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { + ofono_error("Error enabling periodic updates"); + + netmon_agent_free(netmon->agent); + return; + } +} + +static void periodic_updates_disabled_cb(const struct ofono_error *error, + void *data) +{ + if (error->type != OFONO_ERROR_TYPE_NO_ERROR) + ofono_error("Error disabling periodic updates"); +} + +static void agent_removed_cb(gpointer user_data) +{ + struct ofono_netmon *netmon = user_data; + + netmon->agent = NULL; + + netmon->driver->enable_periodic_update(netmon, 0, 0, + periodic_updates_disabled_cb, + NULL); +} + +static DBusMessage *netmon_register_agent(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct ofono_netmon *netmon = data; + const char *agent_path; + const unsigned int enable = 1; + unsigned int period; + + if (netmon->agent) + return __ofono_error_busy(msg); + + if (!netmon->driver->enable_periodic_update) + return __ofono_error_not_implemented(msg); + + if (dbus_message_get_args(msg, NULL, + DBUS_TYPE_OBJECT_PATH, &agent_path, + DBUS_TYPE_UINT32, &period, + DBUS_TYPE_INVALID) == FALSE) + return __ofono_error_invalid_args(msg); + + if (!__ofono_dbus_valid_object_path(agent_path)) + return __ofono_error_invalid_format(msg); + + if (!period) + return __ofono_error_invalid_args(msg); + + /* minimum period is 5 seconds, to avoid frequent updates*/ + if (period < 5) + period = 5; + + netmon->agent = netmon_agent_new(agent_path, + dbus_message_get_sender(msg)); + + if (netmon->agent == NULL) + return __ofono_error_failed(msg); + + netmon_agent_set_removed_notify(netmon->agent, agent_removed_cb, netmon); + + netmon->driver->enable_periodic_update(netmon, enable, period, + periodic_updates_enabled_cb, netmon); + + return dbus_message_new_method_return(msg); +} + +static DBusMessage *netmon_unregister_agent(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct ofono_netmon *netmon = data; + const char *agent_path; + const char *agent_bus = dbus_message_get_sender(msg); + + if (!netmon->driver->enable_periodic_update) + return __ofono_error_not_implemented(msg); + + if (dbus_message_get_args(msg, NULL, + DBUS_TYPE_OBJECT_PATH, &agent_path, + DBUS_TYPE_INVALID) == FALSE) + return __ofono_error_invalid_args(msg); + + if (netmon->agent == NULL) + return __ofono_error_failed(msg); + + if (!netmon_agent_matches(netmon->agent, agent_path, agent_bus)) + return __ofono_error_access_denied(msg); + + netmon_agent_free(netmon->agent); + + return dbus_message_new_method_return(msg); +} + static const GDBusMethodTable netmon_methods[] = { { GDBUS_ASYNC_METHOD("GetServingCellInformation", NULL, GDBUS_ARGS({ "cellinfo", "a{sv}" }), netmon_get_serving_cell_info) }, + { GDBUS_METHOD("RegisterAgent", + GDBUS_ARGS({ "path", "o"}, { "period", "u"}), NULL, + netmon_register_agent) }, + { GDBUS_METHOD("UnregisterAgent", + GDBUS_ARGS({ "agent", "o" }), NULL, + netmon_unregister_agent) }, { } }; diff --git a/src/netmonagent.c b/src/netmonagent.c new file mode 100644 index 00000000..dfe1d464 --- /dev/null +++ b/src/netmonagent.c @@ -0,0 +1,122 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE +#include +#include +#include + +#include +#include + +#include "ofono.h" +#include "netmonagent.h" + +struct netmon_agent { + char *path; + char *bus; + guint disconnect_watch; + ofono_destroy_func removed_cb; + void *removed_data; +}; + +DBusMessage *netmon_agent_new_method_call(struct netmon_agent *agent, + const char *method) +{ + DBusMessage *msg = dbus_message_new_method_call(agent->bus, + agent->path, + OFONO_NETMON_AGENT_INTERFACE, + method); + + return msg; +} + +void netmon_agent_send_no_reply(struct netmon_agent *agent, + DBusMessage *message) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + + dbus_message_set_no_reply(message, TRUE); + + g_dbus_send_message(conn, message); +} + +static inline void netmon_agent_send_release(struct netmon_agent *agent) +{ + DBusMessage *msg = netmon_agent_new_method_call(agent, "Release"); + + netmon_agent_send_no_reply(agent, msg); +} + +ofono_bool_t netmon_agent_matches(struct netmon_agent *agent, + const char *path, const char *sender) +{ + return g_str_equal(agent->path, path) && + g_str_equal(agent->bus, sender); +} + +ofono_bool_t netmon_agent_sender_matches(struct netmon_agent *agent, + const char *sender) +{ + return g_str_equal(agent->bus, sender); +} + +void netmon_agent_set_removed_notify(struct netmon_agent *agent, + ofono_destroy_func destroy, + void *user_data) +{ + agent->removed_cb = destroy; + agent->removed_data = user_data; +} + +void netmon_agent_free(struct netmon_agent *agent) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + + if (agent == NULL) + return; + + if (agent->disconnect_watch) { + netmon_agent_send_release(agent); + g_dbus_remove_watch(conn, agent->disconnect_watch); + agent->disconnect_watch = 0; + } + + if (agent->removed_cb) + agent->removed_cb(agent->removed_data); + + g_free(agent->path); + g_free(agent->bus); + g_free(agent); +} + +static void netmon_agent_disconnect_cb(DBusConnection *conn, void *user_data) +{ + struct netmon_agent *agent = user_data; + + ofono_debug("Agent exited without calling UnregisterAgent"); + + agent->disconnect_watch = 0; + + netmon_agent_free(agent); +} + +struct netmon_agent *netmon_agent_new(const char *path, + const char *sender) +{ + struct netmon_agent *agent = g_try_new0(struct netmon_agent, 1); + DBusConnection *conn = ofono_dbus_get_connection(); + + if (agent == NULL) + return NULL; + + agent->bus = g_strdup(sender); + agent->path = g_strdup(path); + + agent->disconnect_watch = g_dbus_add_disconnect_watch(conn, sender, + netmon_agent_disconnect_cb, + agent, NULL); + + return agent; +} diff --git a/src/netmonagent.h b/src/netmonagent.h new file mode 100644 index 00000000..f64a503a --- /dev/null +++ b/src/netmonagent.h @@ -0,0 +1,23 @@ +struct netmon_agent; + +struct netmon_agent *netmon_agent_new(const char *path, const char *sender); + +void netmon_agent_free(struct netmon_agent *agent); + +void netmon_agent_set_removed_notify(struct netmon_agent *agent, + ofono_destroy_func removed_cb, + void *user_data); + +ofono_bool_t netmon_agent_matches(struct netmon_agent *agent, + const char *path, const char *sender); + +ofono_bool_t netmon_agent_sender_matches(struct netmon_agent *agent, + const char *sender); + +DBusMessage *netmon_agent_new_method_call(struct netmon_agent *netmon, + const char *method); + +void netmon_agent_send_no_reply(struct netmon_agent *agent, + DBusMessage *message); + +void netmon_agent_test(struct netmon_agent *agent); diff --git a/src/network.c b/src/network.c index 3b10fdd1..9b5b3645 100644 --- a/src/network.c +++ b/src/network.c @@ -1186,6 +1186,9 @@ static void notify_status_watches(struct ofono_netreg *netreg) const char *mcc = NULL; const char *mnc = NULL; + if (netreg->status_watches == NULL) + return; + if (netreg->current_operator) { mcc = netreg->current_operator->mcc; mnc = netreg->current_operator->mnc; diff --git a/src/ofono.conf b/src/ofono.conf index ed56d3bd..61e0bdec 100644 --- a/src/ofono.conf +++ b/src/ofono.conf @@ -15,6 +15,7 @@ + diff --git a/src/radio-settings.c b/src/radio-settings.c index 4f81a841..7fd92df9 100644 --- a/src/radio-settings.c +++ b/src/radio-settings.c @@ -167,7 +167,7 @@ static gboolean radio_band_umts_from_string(const char *str, enum ofono_radio_band_umts *band) { if (g_str_equal(str, "any")) { - *band = OFONO_RADIO_BAND_GSM_ANY; + *band = OFONO_RADIO_BAND_UMTS_ANY; return TRUE; } else if (g_str_equal(str, "850")) { *band = OFONO_RADIO_BAND_UMTS_850; diff --git a/src/sms.c b/src/sms.c index 17c5a9c9..b86158e6 100644 --- a/src/sms.c +++ b/src/sms.c @@ -1171,7 +1171,8 @@ static gboolean compute_incoming_msgid(GSList *sms_list, static void dispatch_app_datagram(struct ofono_sms *sms, const struct ofono_uuid *uuid, int dst, int src, - unsigned char *buf, unsigned len, + const unsigned char *buf, + unsigned int len, const struct sms_address *addr, const struct sms_scts *scts) { diff --git a/src/ussd.c b/src/ussd.c index 99fa753f..84f64c67 100644 --- a/src/ussd.c +++ b/src/ussd.c @@ -511,6 +511,20 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID); ussd_change_state(ussd, new_state); + goto free; + } else if (ussd->state == USSD_STATE_USER_ACTION && + status != OFONO_USSD_STATUS_ACTION_REQUIRED) { + ussd_change_state(ussd, USSD_STATE_IDLE); + + if (status == OFONO_USSD_STATUS_NOTIFY && str && str[0]) { + const char *path = __ofono_atom_get_path(ussd->atom); + + g_dbus_emit_signal(conn, path, + OFONO_SUPPLEMENTARY_SERVICES_INTERFACE, + "NotificationReceived", DBUS_TYPE_STRING, + &str, DBUS_TYPE_INVALID); + } + goto free; } else { ofono_error("Received an unsolicited USSD but can't handle."); diff --git a/src/voicecall.c b/src/voicecall.c index e3ae80cf..d06c2dc2 100644 --- a/src/voicecall.c +++ b/src/voicecall.c @@ -2252,7 +2252,7 @@ void ofono_voicecall_notify(struct ofono_voicecall *vc, DBG("Got a voicecall event, status: %s (%d), id: %u, number: %s" " called_number: %s, called_name %s", - ofono_call_status_to_string(call->status), + call_status_to_string(call->status), call->status, call->id, call->phone_number.number, call->called_number.number, call->name); diff --git a/test/test-serving-cell-info b/test/test-serving-cell-info new file mode 100644 index 00000000..498ce88b --- /dev/null +++ b/test/test-serving-cell-info @@ -0,0 +1,97 @@ +#!/usr/bin/python3 + +from gi.repository import GLib + +import sys +import dbus +import dbus.service +import dbus.mainloop.glib + +NETMON_INTERFACE = "org.ofono.NetworkMonitor" +AGENT_INTERFACE = "org.ofono.NetworkMonitorAgent" + +class NetworkMonitorAgent(dbus.service.Object): + @dbus.service.method(AGENT_INTERFACE, + in_signature="", out_signature="") + def Release(self): + print("Agent Released") + mainloop.quit() + + @dbus.service.method(AGENT_INTERFACE, + in_signature="a{sv}", out_signature="") + def ServingCellInformationChanged(self, servingcell): + print("ServingCellInformationChanged notification recieved") + + tech = 'Technology' + mcc = 'MobileCountryCode' + mnc = 'MobileNetworkCode' + lac = 'LocationAreaCode' + cid = 'CellId' + psc = 'PrimaryScramblingCode' + rssi = 'Strength' + ber = 'BitErrorRate' + + if tech in servingcell: + print(" [ Radio Access Technology = %s]" \ + % (servingcell[tech])) + + if mcc in servingcell: + print(" [ Mobile Country Code = %s]" \ + % (servingcell[mcc])) + + if mnc in servingcell: + print(" [ Mobile Network Code = %s]" \ + % (servingcell[mnc])) + + if lac in servingcell: + print(" [ Location Area Code = %d]" \ + % (servingcell[lac])) + + if cid in servingcell: + print(" [ Cell Identity = %d]" \ + % (servingcell[cid])) + + if psc in servingcell: + print(" [ Primary Scrambling Code = %d]" \ + % (servingcell[psc])) + + if rssi in servingcell: + print(" [ Signal Strength = %d]" \ + % (servingcell[rssi])) + + if ber in servingcell: + print(" [ Bit Error Rate = %d]" \ + % (servingcell[ber])) + + print('') + +if __name__ == '__main__': + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + if len(sys.argv) < 2: + print("Usage: %s " %\ + (sys.argv[0])) + sys.exit(1) + + bus = dbus.SystemBus() + manager = dbus.Interface(bus.get_object("org.ofono", "/"), + "org.ofono.Manager") + + modems = manager.GetModems() + path = modems[0][0] + nm = dbus.Interface(bus.get_object('org.ofono', path), + NETMON_INTERFACE) + + path = "/test/netmonagent" + agent = NetworkMonitorAgent(bus, path) + + try: + period = int(sys.argv[1]) + except: + print("Error: Invalid argument %s" % (sys.argv[1])) + sys.exit(1) + + nm.RegisterAgent(path, period) + print("Agent registered") + mainloop = GLib.MainLoop() + mainloop.run() diff --git a/unit/test-simutil.c b/unit/test-simutil.c index 69dd81ef..490e288f 100644 --- a/unit/test-simutil.c +++ b/unit/test-simutil.c @@ -178,12 +178,12 @@ static void test_ber_tlv_builder_efpnn(void) ber_tlv_builder_optimize(&builder, NULL, NULL); eons_info = sim_eons_new(1); - sim_eons_add_pnn_record(eons_info, 1, efpnn0, sizeof(efpnn0)); + sim_eons_add_pnn_record(eons_info, 1, efpnn0, 8 + 10); g_assert(!sim_eons_pnn_is_empty(eons_info)); sim_eons_free(eons_info); eons_info = sim_eons_new(1); - sim_eons_add_pnn_record(eons_info, 1, efpnn1, sizeof(efpnn1)); + sim_eons_add_pnn_record(eons_info, 1, efpnn1, 8 + 6); g_assert(!sim_eons_pnn_is_empty(eons_info)); sim_eons_free(eons_info); }