Files
ofono-binder-plugin/src/binder_util.c
Eugenio Paolantonio (g7) 4e9dc9670c [ofono-binder] util: drop RAF_EHRPD from UMTS and LTE families
EHRPD is only used in CDMA networks. The modem might not expect
it and raise an INVALID_ARGUMENT when using setPreferredNetworkTypeBitmap.

Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2025-02-01 18:07:31 +02:00

982 lines
25 KiB
C

/*
* oFono - Open Source Telephony - binder based adaptation
*
* Copyright (C) 2021-2022 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 "binder_util.h"
#include <ofono/misc.h>
#include <ofono/netreg.h>
#include <ofono/log.h>
#include <radio_request.h>
#include <gbinder_reader.h>
#include <gbinder_writer.h>
#include <gutil_idlepool.h>
#include <gutil_misc.h>
static GUtilIdlePool* binder_util_pool = NULL;
static const char binder_empty_str[] = "";
static const char PROTO_IP_STR[] = "IP";
static const char PROTO_IPV6_STR[] = "IPV6";
static const char PROTO_IPV4V6_STR[] = "IPV4V6";
#define RADIO_ACCESS_FAMILY_GSM \
(RAF_GSM|RAF_GPRS|RAF_EDGE)
#define RADIO_ACCESS_FAMILY_UMTS \
(RAF_UMTS|RAF_HSDPA|RAF_HSUPA|RAF_HSPA|RAF_HSPAP|RAF_TD_SCDMA)
#define RADIO_ACCESS_FAMILY_LTE \
(RAF_LTE|RAF_LTE_CA)
#define RADIO_ACCESS_FAMILY_NR \
(RAF_NR)
static
const char*
binder_pool_string(
char* str)
{
GUtilIdlePool* pool = gutil_idle_pool_get(&binder_util_pool);
gutil_idle_pool_add(pool, str, g_free);
return str;
}
RADIO_ACCESS_NETWORK
binder_radio_access_network_for_tech(
RADIO_TECH tech)
{
switch (tech) {
case RADIO_TECH_GPRS:
case RADIO_TECH_EDGE:
case RADIO_TECH_GSM:
return RADIO_ACCESS_NETWORK_GERAN;
case RADIO_TECH_UMTS:
case RADIO_TECH_HSDPA:
case RADIO_TECH_HSPAP:
case RADIO_TECH_HSUPA:
case RADIO_TECH_HSPA:
case RADIO_TECH_TD_SCDMA:
return RADIO_ACCESS_NETWORK_UTRAN;
case RADIO_TECH_IS95A:
case RADIO_TECH_IS95B:
case RADIO_TECH_ONE_X_RTT:
case RADIO_TECH_EVDO_0:
case RADIO_TECH_EVDO_A:
case RADIO_TECH_EVDO_B:
case RADIO_TECH_EHRPD:
return RADIO_ACCESS_NETWORK_CDMA2000;
case RADIO_TECH_LTE:
case RADIO_TECH_LTE_CA:
return RADIO_ACCESS_NETWORK_EUTRAN;
case RADIO_TECH_IWLAN:
return RADIO_ACCESS_NETWORK_IWLAN;
case RADIO_TECH_NR:
return RADIO_ACCESS_NETWORK_NGRAN;
case RADIO_TECH_UNKNOWN:
break;
}
return RADIO_ACCESS_NETWORK_UNKNOWN;
}
RADIO_APN_TYPES
binder_radio_apn_types_for_profile(
guint profile_id,
const BinderDataProfileConfig* config)
{
RADIO_APN_TYPES apn_types = RADIO_APN_TYPE_NONE;
if (profile_id == config->mms_profile_id) {
apn_types |= RADIO_APN_TYPE_MMS;
}
if (profile_id == config->default_profile_id) {
apn_types |= (RADIO_APN_TYPE_DEFAULT |
RADIO_APN_TYPE_SUPL |
RADIO_APN_TYPE_IA);
}
switch (profile_id) {
case RADIO_DATA_PROFILE_IMS:
apn_types |= RADIO_APN_TYPE_IMS;
break;
case RADIO_DATA_PROFILE_CBS:
apn_types |= RADIO_APN_TYPE_CBS;
break;
case RADIO_DATA_PROFILE_FOTA:
apn_types |= RADIO_APN_TYPE_FOTA;
break;
default:
if (profile_id == config->mms_profile_id ||
profile_id == config->default_profile_id) {
break;
}
/* fallthrough */
case RADIO_DATA_PROFILE_INVALID:
case RADIO_DATA_PROFILE_DEFAULT:
apn_types |= (RADIO_APN_TYPE_DEFAULT |
RADIO_APN_TYPE_SUPL |
RADIO_APN_TYPE_IA);
break;
}
return apn_types;
}
RADIO_PDP_PROTOCOL_TYPE
binder_proto_from_ofono_proto(
enum ofono_gprs_proto proto)
{
switch (proto) {
case OFONO_GPRS_PROTO_IP:
return RADIO_PDP_PROTOCOL_IP;
case OFONO_GPRS_PROTO_IPV6:
return RADIO_PDP_PROTOCOL_IPV6;
case OFONO_GPRS_PROTO_IPV4V6:
return RADIO_PDP_PROTOCOL_IPV4V6;
}
return RADIO_PDP_PROTOCOL_UNKNOWN;
}
const char*
binder_proto_str_from_ofono_proto(
enum ofono_gprs_proto proto)
{
switch (proto) {
case OFONO_GPRS_PROTO_IP:
return PROTO_IP_STR;
case OFONO_GPRS_PROTO_IPV6:
return PROTO_IPV6_STR;
case OFONO_GPRS_PROTO_IPV4V6:
return PROTO_IPV4V6_STR;
}
return NULL;
}
enum ofono_gprs_proto
binder_ofono_proto_from_proto_type(
RADIO_PDP_PROTOCOL_TYPE type)
{
switch (type) {
case RADIO_PDP_PROTOCOL_IP:
return OFONO_GPRS_PROTO_IP;
case RADIO_PDP_PROTOCOL_IPV6:
return OFONO_GPRS_PROTO_IPV6;
case RADIO_PDP_PROTOCOL_IPV4V6:
return OFONO_GPRS_PROTO_IPV4V6;
case RADIO_PDP_PROTOCOL_PPP:
case RADIO_PDP_PROTOCOL_NON_IP:
case RADIO_PDP_PROTOCOL_UNSTRUCTURED:
case RADIO_PDP_PROTOCOL_UNKNOWN:
break;
}
/* Need OFONO_GPRS_PROTO_UNKNOWN? */
return OFONO_GPRS_PROTO_IP;
}
enum ofono_gprs_proto
binder_ofono_proto_from_proto_str(
const char* type)
{
if (type) {
if (!g_ascii_strcasecmp(type, PROTO_IP_STR)) {
return OFONO_GPRS_PROTO_IP;
} else if (!g_ascii_strcasecmp(type, PROTO_IPV6_STR)) {
return OFONO_GPRS_PROTO_IPV6;
} else if (!g_ascii_strcasecmp(type, PROTO_IPV4V6_STR)) {
return OFONO_GPRS_PROTO_IPV4V6;
}
}
/* Need OFONO_GPRS_PROTO_UNKNOWN? */
return OFONO_GPRS_PROTO_IP;
}
RADIO_APN_AUTH_TYPE
binder_radio_auth_from_ofono_method(
enum ofono_gprs_auth_method auth)
{
switch (auth) {
case OFONO_GPRS_AUTH_METHOD_NONE:
return RADIO_APN_AUTH_NONE;
case OFONO_GPRS_AUTH_METHOD_CHAP:
return RADIO_APN_AUTH_CHAP;
case OFONO_GPRS_AUTH_METHOD_PAP:
return RADIO_APN_AUTH_PAP;
case OFONO_GPRS_AUTH_METHOD_ANY:
/* Use default */
break;
}
/* Default */
return RADIO_APN_AUTH_PAP_CHAP;
}
RADIO_PREF_NET_TYPE
binder_pref_from_raf(
RADIO_ACCESS_FAMILY raf)
{
if (raf & RADIO_ACCESS_FAMILY_GSM) {
if (raf & RADIO_ACCESS_FAMILY_UMTS) {
if (raf & RADIO_ACCESS_FAMILY_LTE) {
if (raf & RADIO_ACCESS_FAMILY_NR) {
return RADIO_PREF_NET_NR_LTE_GSM_WCDMA;
}
return RADIO_PREF_NET_LTE_GSM_WCDMA;
}
return RADIO_PREF_NET_GSM_WCDMA;
}
return RADIO_PREF_NET_GSM_ONLY;
} else if (raf & RADIO_ACCESS_FAMILY_UMTS) {
if (raf & RADIO_ACCESS_FAMILY_LTE) {
if (raf & RADIO_ACCESS_FAMILY_NR) {
return RADIO_PREF_NET_NR_LTE_WCDMA;
}
return RADIO_PREF_NET_LTE_WCDMA;
}
return RADIO_PREF_NET_WCDMA;
} else if (raf & RADIO_ACCESS_FAMILY_LTE) {
if (raf & RADIO_ACCESS_FAMILY_NR) {
return RADIO_PREF_NET_NR_LTE;
}
return RADIO_PREF_NET_LTE_ONLY;
} else if (raf & RADIO_ACCESS_FAMILY_NR) {
return RADIO_PREF_NET_NR_ONLY;
} else {
return RADIO_PREF_NET_INVALID;
}
}
static
int
binder_pref_mask(
RADIO_PREF_NET_TYPE pref,
int none,
int gsm_mask,
int umts_mask,
int lte_mask,
int nr_mask)
{
switch (pref) {
case RADIO_PREF_NET_GSM_ONLY:
return gsm_mask;
case RADIO_PREF_NET_WCDMA:
case RADIO_PREF_NET_TD_SCDMA_ONLY:
case RADIO_PREF_NET_TD_SCDMA_WCDMA:
return umts_mask;
case RADIO_PREF_NET_LTE_ONLY:
case RADIO_PREF_NET_LTE_CDMA_EVDO:
return lte_mask;
case RADIO_PREF_NET_NR_ONLY:
return nr_mask;
case RADIO_PREF_NET_NR_LTE:
return lte_mask | nr_mask;
case RADIO_PREF_NET_TD_SCDMA_GSM:
case RADIO_PREF_NET_GSM_WCDMA:
case RADIO_PREF_NET_GSM_WCDMA_AUTO:
case RADIO_PREF_NET_GSM_WCDMA_CDMA_EVDO_AUTO:
case RADIO_PREF_NET_TD_SCDMA_GSM_WCDMA:
case RADIO_PREF_NET_TD_SCDMA_GSM_WCDMA_CDMA_EVDO_AUTO:
return gsm_mask | umts_mask;
case RADIO_PREF_NET_LTE_WCDMA:
case RADIO_PREF_NET_TD_SCDMA_LTE:
case RADIO_PREF_NET_TD_SCDMA_WCDMA_LTE:
return umts_mask | lte_mask;
case RADIO_PREF_NET_LTE_GSM_WCDMA:
case RADIO_PREF_NET_TD_SCDMA_GSM_LTE:
case RADIO_PREF_NET_LTE_CMDA_EVDO_GSM_WCDMA:
case RADIO_PREF_NET_TD_SCDMA_GSM_WCDMA_LTE:
case RADIO_PREF_NET_TD_SCDMA_LTE_CDMA_EVDO_GSM_WCDMA:
return gsm_mask | umts_mask | lte_mask;
case RADIO_PREF_NET_NR_LTE_CDMA_EVDO:
case RADIO_PREF_NET_NR_LTE_WCDMA:
case RADIO_PREF_NET_NR_LTE_TD_SCDMA:
case RADIO_PREF_NET_NR_LTE_TD_SCDMA_WCDMA:
return umts_mask | lte_mask | nr_mask;
case RADIO_PREF_NET_NR_LTE_GSM_WCDMA:
case RADIO_PREF_NET_NR_LTE_TD_SCDMA_GSM:
case RADIO_PREF_NET_NR_LTE_CDMA_EVDO_GSM_WCDMA:
case RADIO_PREF_NET_NR_LTE_TD_SCDMA_GSM_WCDMA:
case RADIO_PREF_NET_NR_LTE_TD_SCDMA_CDMA_EVDO_GSM_WCDMA:
return gsm_mask | umts_mask | lte_mask | nr_mask;
case RADIO_PREF_NET_CDMA_ONLY:
case RADIO_PREF_NET_EVDO_ONLY:
case RADIO_PREF_NET_CDMA_EVDO_AUTO:
case RADIO_PREF_NET_INVALID:
return none;
}
DBG("unexpected pref mode %d", pref);
return none;
}
RADIO_ACCESS_FAMILY
binder_raf_from_pref(
RADIO_PREF_NET_TYPE pref)
{
return binder_pref_mask(pref, RAF_NONE,
RADIO_ACCESS_FAMILY_GSM, RADIO_ACCESS_FAMILY_UMTS,
RADIO_ACCESS_FAMILY_LTE, RADIO_ACCESS_FAMILY_NR);
}
enum ofono_radio_access_mode
binder_access_modes_from_pref(
RADIO_PREF_NET_TYPE pref)
{
return binder_pref_mask(pref, OFONO_RADIO_ACCESS_MODE_NONE,
OFONO_RADIO_ACCESS_MODE_GSM, OFONO_RADIO_ACCESS_MODE_UMTS,
OFONO_RADIO_ACCESS_MODE_LTE, OFONO_RADIO_ACCESS_MODE_NR);
}
enum ofono_radio_access_mode
binder_access_modes_from_raf(
RADIO_ACCESS_FAMILY raf)
{
if (raf == RAF_UNKNOWN) {
return OFONO_RADIO_ACCESS_MODE_ALL;
} else {
enum ofono_radio_access_mode modes = OFONO_RADIO_ACCESS_MODE_NONE;
if (raf & RADIO_ACCESS_FAMILY_GSM) {
modes |= OFONO_RADIO_ACCESS_MODE_GSM;
}
if (raf & RADIO_ACCESS_FAMILY_UMTS) {
modes |= OFONO_RADIO_ACCESS_MODE_UMTS;
}
if (raf & RADIO_ACCESS_FAMILY_LTE) {
modes |= OFONO_RADIO_ACCESS_MODE_LTE;
}
if (raf & RADIO_ACCESS_FAMILY_NR) {
modes |= OFONO_RADIO_ACCESS_MODE_NR;
}
return modes;
}
}
enum ofono_radio_access_mode
binder_access_modes_up_to(
enum ofono_radio_access_mode mode)
{
/* Make sure only one bit is set in max_mode */
enum ofono_radio_access_mode max_mode = ofono_radio_access_max_mode(mode);
/* Treat ANY (zero) as ALL, otherwise set all lower bits */
return (max_mode == OFONO_RADIO_ACCESS_MODE_ANY) ?
OFONO_RADIO_ACCESS_MODE_ALL : (max_mode | (max_mode - 1));
}
enum ofono_access_technology
binder_access_tech_from_radio_tech(
RADIO_TECH radio_tech)
{
switch (radio_tech) {
case RADIO_TECH_UNKNOWN:
return OFONO_ACCESS_TECHNOLOGY_NONE;
case RADIO_TECH_GPRS:
case RADIO_TECH_GSM:
return OFONO_ACCESS_TECHNOLOGY_GSM;
case RADIO_TECH_EDGE:
return OFONO_ACCESS_TECHNOLOGY_GSM_EGPRS;
case RADIO_TECH_UMTS:
return OFONO_ACCESS_TECHNOLOGY_UTRAN;
case RADIO_TECH_HSDPA:
return OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA;
case RADIO_TECH_HSUPA:
return OFONO_ACCESS_TECHNOLOGY_UTRAN_HSUPA;
case RADIO_TECH_HSPA:
case RADIO_TECH_HSPAP:
return OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
case RADIO_TECH_LTE:
case RADIO_TECH_LTE_CA:
return OFONO_ACCESS_TECHNOLOGY_EUTRAN;
case RADIO_TECH_NR:
return OFONO_ACCESS_TECHNOLOGY_NR_5GCN;
case RADIO_TECH_IWLAN:
case RADIO_TECH_IS95B:
case RADIO_TECH_ONE_X_RTT:
case RADIO_TECH_EVDO_0:
case RADIO_TECH_EVDO_A:
case RADIO_TECH_EVDO_B:
case RADIO_TECH_EHRPD:
case RADIO_TECH_TD_SCDMA:
case RADIO_TECH_IS95A:
break;
}
DBG("Unknown radio tech %d", radio_tech);
return OFONO_ACCESS_TECHNOLOGY_NONE;
}
const char*
binder_ofono_access_technology_string(
enum ofono_access_technology act)
{
switch (act) {
case OFONO_ACCESS_TECHNOLOGY_NONE:
return "none";
case OFONO_ACCESS_TECHNOLOGY_GSM:
return "gsm";
case OFONO_ACCESS_TECHNOLOGY_GSM_COMPACT:
return "gsmc";
case OFONO_ACCESS_TECHNOLOGY_UTRAN:
return "utran";
case OFONO_ACCESS_TECHNOLOGY_GSM_EGPRS:
return "egprs";
case OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA:
return "hsdpa";
case OFONO_ACCESS_TECHNOLOGY_UTRAN_HSUPA:
return "hsupa";
case OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA:
return "utran";
case OFONO_ACCESS_TECHNOLOGY_EUTRAN:
return "eutran";
case OFONO_ACCESS_TECHNOLOGY_EUTRA_5GCN:
return "eutran";
case OFONO_ACCESS_TECHNOLOGY_NR_5GCN:
case OFONO_ACCESS_TECHNOLOGY_NG_RAN:
case OFONO_ACCESS_TECHNOLOGY_EUTRA_NR:
return "nr";
}
return binder_pool_string(g_strdup_printf("%d (?)", act));
}
const char*
binder_radio_op_status_string(
RADIO_OP_STATUS status)
{
switch (status) {
case RADIO_OP_AVAILABLE:
return "available";
case RADIO_OP_CURRENT:
return "current";
case RADIO_OP_FORBIDDEN:
return "forbidden";
case RADIO_OP_STATUS_UNKNOWN:
break;
}
return "unknown";
}
const char*
binder_radio_state_string(
RADIO_STATE state)
{
#define RADIO_STATE_(name) case RADIO_STATE_##name: return #name
switch (state) {
RADIO_STATE_(OFF);
RADIO_STATE_(UNAVAILABLE);
RADIO_STATE_(ON);
}
return binder_pool_string(g_strdup_printf("%d (?)", state));
}
const char*
binder_radio_error_string(
RADIO_ERROR error)
{
switch (error) {
#define RADIO_ERROR_STR_(name) case RADIO_ERROR_##name: return #name
RADIO_ERROR_STR_(NONE);
RADIO_ERROR_STR_(RADIO_NOT_AVAILABLE);
RADIO_ERROR_STR_(GENERIC_FAILURE);
RADIO_ERROR_STR_(PASSWORD_INCORRECT);
RADIO_ERROR_STR_(SIM_PIN2);
RADIO_ERROR_STR_(SIM_PUK2);
RADIO_ERROR_STR_(REQUEST_NOT_SUPPORTED);
RADIO_ERROR_STR_(CANCELLED);
RADIO_ERROR_STR_(OP_NOT_ALLOWED_DURING_VOICE_CALL);
RADIO_ERROR_STR_(OP_NOT_ALLOWED_BEFORE_REG_TO_NW);
RADIO_ERROR_STR_(SMS_SEND_FAIL_RETRY);
RADIO_ERROR_STR_(SIM_ABSENT);
RADIO_ERROR_STR_(SUBSCRIPTION_NOT_AVAILABLE);
RADIO_ERROR_STR_(MODE_NOT_SUPPORTED);
RADIO_ERROR_STR_(FDN_CHECK_FAILURE);
RADIO_ERROR_STR_(ILLEGAL_SIM_OR_ME);
RADIO_ERROR_STR_(MISSING_RESOURCE);
RADIO_ERROR_STR_(NO_SUCH_ELEMENT);
RADIO_ERROR_STR_(DIAL_MODIFIED_TO_USSD);
RADIO_ERROR_STR_(DIAL_MODIFIED_TO_SS);
RADIO_ERROR_STR_(DIAL_MODIFIED_TO_DIAL);
RADIO_ERROR_STR_(USSD_MODIFIED_TO_DIAL);
RADIO_ERROR_STR_(USSD_MODIFIED_TO_SS);
RADIO_ERROR_STR_(USSD_MODIFIED_TO_USSD);
RADIO_ERROR_STR_(SS_MODIFIED_TO_DIAL);
RADIO_ERROR_STR_(SS_MODIFIED_TO_USSD);
RADIO_ERROR_STR_(SUBSCRIPTION_NOT_SUPPORTED);
RADIO_ERROR_STR_(SS_MODIFIED_TO_SS);
RADIO_ERROR_STR_(LCE_NOT_SUPPORTED);
RADIO_ERROR_STR_(NO_MEMORY);
RADIO_ERROR_STR_(INTERNAL_ERR);
RADIO_ERROR_STR_(SYSTEM_ERR);
RADIO_ERROR_STR_(MODEM_ERR);
RADIO_ERROR_STR_(INVALID_STATE);
RADIO_ERROR_STR_(NO_RESOURCES);
RADIO_ERROR_STR_(SIM_ERR);
RADIO_ERROR_STR_(INVALID_ARGUMENTS);
RADIO_ERROR_STR_(INVALID_SIM_STATE);
RADIO_ERROR_STR_(INVALID_MODEM_STATE);
RADIO_ERROR_STR_(INVALID_CALL_ID);
RADIO_ERROR_STR_(NO_SMS_TO_ACK);
RADIO_ERROR_STR_(NETWORK_ERR);
RADIO_ERROR_STR_(REQUEST_RATE_LIMITED);
RADIO_ERROR_STR_(SIM_BUSY);
RADIO_ERROR_STR_(SIM_FULL);
RADIO_ERROR_STR_(NETWORK_REJECT);
RADIO_ERROR_STR_(OPERATION_NOT_ALLOWED);
RADIO_ERROR_STR_(EMPTY_RECORD);
RADIO_ERROR_STR_(INVALID_SMS_FORMAT);
RADIO_ERROR_STR_(ENCODING_ERR);
RADIO_ERROR_STR_(INVALID_SMSC_ADDRESS);
RADIO_ERROR_STR_(NO_SUCH_ENTRY);
RADIO_ERROR_STR_(NETWORK_NOT_READY);
RADIO_ERROR_STR_(NOT_PROVISIONED);
RADIO_ERROR_STR_(NO_SUBSCRIPTION);
RADIO_ERROR_STR_(NO_NETWORK_FOUND);
RADIO_ERROR_STR_(DEVICE_IN_USE);
RADIO_ERROR_STR_(ABORTED);
RADIO_ERROR_STR_(INVALID_RESPONSE);
RADIO_ERROR_STR_(OEM_ERROR_1);
RADIO_ERROR_STR_(OEM_ERROR_2);
RADIO_ERROR_STR_(OEM_ERROR_3);
RADIO_ERROR_STR_(OEM_ERROR_4);
RADIO_ERROR_STR_(OEM_ERROR_5);
RADIO_ERROR_STR_(OEM_ERROR_6);
RADIO_ERROR_STR_(OEM_ERROR_7);
RADIO_ERROR_STR_(OEM_ERROR_8);
RADIO_ERROR_STR_(OEM_ERROR_9);
RADIO_ERROR_STR_(OEM_ERROR_10);
RADIO_ERROR_STR_(OEM_ERROR_11);
RADIO_ERROR_STR_(OEM_ERROR_12);
RADIO_ERROR_STR_(OEM_ERROR_13);
RADIO_ERROR_STR_(OEM_ERROR_14);
RADIO_ERROR_STR_(OEM_ERROR_15);
RADIO_ERROR_STR_(OEM_ERROR_16);
RADIO_ERROR_STR_(OEM_ERROR_17);
RADIO_ERROR_STR_(OEM_ERROR_18);
RADIO_ERROR_STR_(OEM_ERROR_19);
RADIO_ERROR_STR_(OEM_ERROR_20);
RADIO_ERROR_STR_(OEM_ERROR_21);
RADIO_ERROR_STR_(OEM_ERROR_22);
RADIO_ERROR_STR_(OEM_ERROR_23);
RADIO_ERROR_STR_(OEM_ERROR_24);
RADIO_ERROR_STR_(OEM_ERROR_25);
}
return binder_pool_string(g_strdup_printf("%d", error));
}
enum ofono_access_technology
binder_parse_tech(
const char* stech,
RADIO_TECH* radio_tech)
{
int rt = RADIO_TECH_UNKNOWN;
const enum ofono_access_technology at = gutil_parse_int(stech, 0, &rt) ?
binder_access_tech_from_radio_tech(rt) : OFONO_ACCESS_TECHNOLOGY_NONE;
if (radio_tech) {
*radio_tech = rt;
}
return at;
}
gboolean
binder_parse_mcc_mnc(
const char* str,
struct ofono_network_operator* op)
{
if (str) {
int i;
const char* ptr = str;
/* Three digit country code */
for (i = 0;
i < OFONO_MAX_MCC_LENGTH && *ptr && g_ascii_isdigit(*ptr);
i++) {
op->mcc[i] = *ptr++;
}
op->mcc[i] = 0;
if (i == OFONO_MAX_MCC_LENGTH) {
/* Usually 2 but sometimes 3 digit network code */
for (i = 0;
i < OFONO_MAX_MNC_LENGTH && *ptr && g_ascii_isdigit(*ptr);
i++) {
op->mnc[i] = *ptr++;
}
op->mnc[i] = 0;
if (i > 0) {
/*
* Sometimes MCC/MNC are followed by + and what looks
* like the technology code. This seems to be modem
* specific.
*/
if (*ptr == '+') {
const enum ofono_access_technology at =
binder_parse_tech(ptr + 1, NULL);
if (at != OFONO_ACCESS_TECHNOLOGY_NONE) {
op->tech = at;
}
}
return TRUE;
}
}
}
return FALSE;
}
char*
binder_encode_hex(
const void* in,
guint size)
{
char *out = g_new(char, size * 2 + 1);
ofono_encode_hex(in, size, out);
return out;
}
void*
binder_decode_hex(
const char* hex,
int len,
guint* out_size)
{
void* out = NULL;
guint size = 0;
if (hex) {
if (len < 0) {
len = (int) strlen(hex);
}
if (len > 0 && !(len & 1)) {
size = len/2;
out = g_malloc(size);
if (!gutil_hex2bin(hex, len, out)) {
g_free(out);
out = NULL;
size = 0;
}
}
}
if (out_size) {
*out_size = size;
}
return out;
}
const char*
binder_print_strv(
char** strv,
const char* sep)
{
if (!strv) {
return NULL;
} else if (!strv[0]) {
return binder_empty_str;
} else {
GUtilIdlePool* pool = gutil_idle_pool_get(&binder_util_pool);
char* str = g_strjoinv(sep, strv);
gutil_idle_pool_add(pool, str, g_free);
return str;
}
}
const char*
binder_print_hex(
const void* data,
gsize size)
{
if (data && size) {
const guint8* bytes = data;
GUtilIdlePool* pool = gutil_idle_pool_get(&binder_util_pool);
char* str = g_new(char, size * 2 + 1);
char* ptr = str;
gsize i;
for (i = 0; i < size; i++) {
static const char hex[] = "0123456789abcdef";
const guint8 b = bytes[i];
*ptr++ = hex[(b >> 4) & 0xf];
*ptr++ = hex[b & 0xf];
}
*ptr++ = 0;
gutil_idle_pool_add(pool, str, g_free);
return str;
}
return binder_empty_str;
}
gboolean
binder_submit_request(
RadioRequestGroup* g,
RADIO_REQ code)
{
RadioRequest* req = radio_request_new2(g, code, NULL, NULL, NULL, NULL);
gboolean ok = radio_request_submit(req);
radio_request_unref(req);
return ok;
}
gboolean
binder_submit_request2(
RadioRequestGroup* g,
RADIO_REQ code,
RadioRequestCompleteFunc complete,
GDestroyNotify destroy,
void* user_data)
{
RadioRequest* req = radio_request_new2(g, code, NULL, complete, destroy,
user_data);
gboolean ok = radio_request_submit(req);
radio_request_unref(req);
return ok;
}
const char*
binder_read_hidl_string(
const GBinderReader* args)
{
GBinderReader reader;
/* Read a single string arg */
gbinder_reader_copy(&reader, args);
return gbinder_reader_read_hidl_string_c(&reader);
}
char*
binder_read_string16(
const GBinderReader* args)
{
GBinderReader reader;
/* Read a single string arg */
gbinder_reader_copy(&reader, args);
return gbinder_reader_read_string16(&reader);
}
gboolean
binder_read_int32(
const GBinderReader* args,
gint32* value)
{
GBinderReader reader;
/* Read a single int32 arg */
gbinder_reader_copy(&reader, args);
return gbinder_reader_read_int32(&reader, value);
}
const void*
binder_read_hidl_struct1(
const GBinderReader* args,
gsize size)
{
GBinderReader reader;
/* Read a single struct */
gbinder_reader_copy(&reader, args);
return gbinder_reader_read_hidl_struct1(&reader, size);
}
const void*
binder_read_parcelable(
const GBinderReader* args,
gsize* out_size)
{
GBinderReader reader;
/* Read a single AIDL parcelable */
gbinder_reader_copy(&reader, args);
return gbinder_reader_read_parcelable(&reader, out_size);
}
gsize
binder_read_parcelable_size(
GBinderReader* reader)
{
/* Read a single AIDL parcelable header and return inner data size */
guint32 non_null = 0, payload_size = 0;
if (gbinder_reader_read_uint32(reader, &non_null) && non_null &&
gbinder_reader_read_uint32(reader, &payload_size) &&
payload_size >= sizeof(payload_size)) {
return payload_size - sizeof(payload_size);
}
return 0;
}
char**
binder_strv_from_hidl_string_vec(
const GBinderHidlVec* vec)
{
if (vec) {
const GBinderHidlString* strings = vec->data.ptr;
char** out = g_new(char*, vec->count + 1);
char** ptr = out;
guint i;
for (i = 0; i < vec->count; i++, ptr++) {
const char* str = strings[i].data.str;
*ptr = str ? gutil_memdup(str, strings[i].len + 1) : g_strdup("");
}
*ptr = NULL;
return out;
}
return NULL;
}
gboolean
binder_read_string16_parse_int(
GBinderReader* reader,
gint32* value)
{
/* Read a string and parse integer value from it */
gboolean ret = FALSE;
char* str = gbinder_reader_read_string16(reader);
ret = gutil_parse_int(str, 10, value);
g_free(str);
return ret;
}
char**
binder_strv_from_string16_array(
GBinderReader* reader)
{
if (reader) {
gint32 count;
gbinder_reader_read_int32(reader, &count);
if (count < 0) {
count = 0;
}
char** out = g_new(char*, count + 1);
char** ptr = out;
guint i;
for (i = 0; i < count; i++, ptr++) {
char* str = gbinder_reader_read_string16(reader);
*ptr = str ? str : g_strdup("");
}
*ptr = NULL;
return out;
}
return NULL;
}
guint
binder_append_vec_with_data(
GBinderWriter* writer,
const void* data,
guint elemsize,
guint count,
const GBinderParent* parent)
{
GBinderHidlVec* vec = gbinder_writer_new0(writer, GBinderHidlVec);
GBinderParent p;
vec->data.ptr = data;
vec->count = count;
p.index = gbinder_writer_append_buffer_object(writer, vec, sizeof(*vec));
p.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
/* Return the index of the data buffer */
return gbinder_writer_append_buffer_object_with_parent(writer,
data, count * elemsize, &p);
}
static
void
binder_copy_hidl_string_impl(
GBinderWriter* writer,
GBinderHidlString* dest,
const char* src,
gssize len)
{
dest->owns_buffer = TRUE;
if (len > 0) {
/* GBinderWriter takes ownership of the string contents */
dest->len = (guint32) len;
dest->data.str = gbinder_writer_memdup(writer, src, len + 1);
} else {
/* Replace NULL strings with empty strings */
dest->data.str = binder_empty_str;
dest->len = 0;
}
}
void
binder_copy_hidl_string(
GBinderWriter* writer,
GBinderHidlString* dest,
const char* src)
{
binder_copy_hidl_string_impl(writer, dest, src, src ? strlen(src) : 0);
}
void
binder_copy_hidl_string_len(
GBinderWriter* writer,
GBinderHidlString* dest,
const char* src,
gssize len)
{
binder_copy_hidl_string_impl(writer, dest, src, (src && len < 0) ?
strlen(src) : 0);
}
void
binder_append_hidl_string_with_parent(
GBinderWriter* writer,
const GBinderHidlString* str,
guint32 index,
guint32 offset)
{
GBinderParent parent;
parent.index = index;
parent.offset = offset;
/* Strings are NULL-terminated, hence len + 1 */
gbinder_writer_append_buffer_object_with_parent(writer, str->data.str,
str->len + 1, &parent);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/