2009-05-22 11:58:49 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* oFono - Open Source Telephony
|
|
|
|
*
|
2011-10-10 20:39:48 +00:00
|
|
|
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
2009-05-22 11:58:49 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
2011-08-04 15:00:05 +00:00
|
|
|
#include <errno.h>
|
2009-05-22 11:58:49 +00:00
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
#include <ofono/log.h>
|
2009-07-29 19:33:58 +00:00
|
|
|
#include <ofono/modem.h>
|
2009-08-18 22:05:50 +00:00
|
|
|
#include <ofono/sim.h>
|
2009-05-22 11:58:49 +00:00
|
|
|
|
|
|
|
#include "gatchat.h"
|
|
|
|
#include "gatresult.h"
|
2009-10-03 00:25:58 +00:00
|
|
|
#include "simutil.h"
|
2009-11-10 06:30:10 +00:00
|
|
|
#include "vendor.h"
|
2017-11-03 23:30:49 +00:00
|
|
|
#include "util.h"
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2009-09-04 19:05:15 +00:00
|
|
|
#include "atmodem.h"
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2010-10-15 12:25:50 +00:00
|
|
|
#define EF_STATUS_INVALIDATED 0
|
|
|
|
#define EF_STATUS_VALID 1
|
|
|
|
|
2011-01-10 21:59:53 +00:00
|
|
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
|
|
|
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data {
|
|
|
|
GAtChat *chat;
|
|
|
|
unsigned int vendor;
|
2017-10-23 20:52:36 +00:00
|
|
|
guint passwd_type_mask;
|
2012-04-18 12:39:48 +00:00
|
|
|
struct at_util_sim_state_query *sim_state_query;
|
2009-11-10 06:30:10 +00:00
|
|
|
};
|
|
|
|
|
2009-05-22 11:58:49 +00:00
|
|
|
static const char *crsm_prefix[] = { "+CRSM:", NULL };
|
2010-05-12 01:20:53 +00:00
|
|
|
static const char *cpin_prefix[] = { "+CPIN:", NULL };
|
|
|
|
static const char *clck_prefix[] = { "+CLCK:", NULL };
|
2011-01-10 21:59:53 +00:00
|
|
|
static const char *huawei_cpin_prefix[] = { "^CPIN:", NULL };
|
2011-01-19 18:34:53 +00:00
|
|
|
static const char *xpincnt_prefix[] = { "+XPINCNT:", NULL };
|
2011-08-03 21:54:39 +00:00
|
|
|
static const char *zpinpuk_prefix[] = { "+ZPINPUK:", NULL };
|
2012-05-25 12:32:28 +00:00
|
|
|
static const char *pinnum_prefix[] = { "%PINNUM:", NULL };
|
2011-12-29 20:08:38 +00:00
|
|
|
static const char *oercn_prefix[] = { "_OERCN:", NULL };
|
2011-01-31 12:48:20 +00:00
|
|
|
static const char *cpinr_prefixes[] = { "+CPINR:", "+CPINRE:", NULL };
|
2011-02-01 13:45:47 +00:00
|
|
|
static const char *epin_prefix[] = { "*EPIN:", NULL };
|
2017-11-07 16:01:57 +00:00
|
|
|
static const char *simcom_spic_prefix[] = { "+SPIC:", NULL };
|
2018-09-25 07:12:32 +00:00
|
|
|
static const char *gemalto_spic_prefix[] = { "^SPIC:", NULL };
|
2012-08-16 07:37:20 +00:00
|
|
|
static const char *pct_prefix[] = { "#PCT:", NULL };
|
2012-11-15 08:35:51 +00:00
|
|
|
static const char *pnnm_prefix[] = { "+PNNM:", NULL };
|
2014-06-26 17:08:14 +00:00
|
|
|
static const char *qpinc_prefix[] = { "+QPINC:", NULL };
|
2018-08-28 07:45:39 +00:00
|
|
|
static const char *qtrpin_prefix[] = { "+QTRPIN:", NULL };
|
2014-07-03 10:32:05 +00:00
|
|
|
static const char *upincnt_prefix[] = { "+UPINCNT:", NULL };
|
2017-11-03 23:30:49 +00:00
|
|
|
static const char *cuad_prefix[] = { "+CUAD:", NULL };
|
|
|
|
static const char *ccho_prefix[] = { "+CCHO:", NULL };
|
|
|
|
static const char *crla_prefix[] = { "+CRLA:", NULL };
|
2017-11-07 16:42:50 +00:00
|
|
|
static const char *cgla_prefix[] = { "+CGLA:", NULL };
|
2019-04-02 06:24:02 +00:00
|
|
|
static const char *xcmscsc_prefix[] = { "+XCMSCSC:", NULL};
|
2010-05-12 01:20:53 +00:00
|
|
|
static const char *none_prefix[] = { NULL };
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2017-11-03 22:34:43 +00:00
|
|
|
static void append_file_path(char *buf, const unsigned char *path,
|
|
|
|
unsigned int path_len)
|
|
|
|
{
|
|
|
|
if (path_len > 0) {
|
|
|
|
*buf++ = ',';
|
|
|
|
*buf++ = ',';
|
|
|
|
*buf++ = '\"';
|
|
|
|
|
|
|
|
for (; path_len; path_len--)
|
|
|
|
buf += sprintf(buf, "%02hhX", *path++);
|
|
|
|
|
|
|
|
*buf++ = '\"';
|
|
|
|
*buf = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-03 23:30:49 +00:00
|
|
|
static void get_response_common_cb(gboolean ok, GAtResult *result,
|
|
|
|
gpointer user_data, const char *prefix)
|
2009-05-22 11:58:49 +00:00
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
GAtResultIter iter;
|
2009-06-18 03:44:44 +00:00
|
|
|
ofono_sim_file_info_cb_t cb = cbd->cb;
|
2009-05-22 11:58:49 +00:00
|
|
|
struct ofono_error error;
|
2009-06-18 03:44:28 +00:00
|
|
|
const guint8 *response;
|
|
|
|
gint sw1, sw2, len;
|
2009-06-18 03:44:44 +00:00
|
|
|
int flen, rlen;
|
2009-10-02 19:52:52 +00:00
|
|
|
int str;
|
2009-07-27 21:53:03 +00:00
|
|
|
unsigned char access[3];
|
2010-10-14 21:02:51 +00:00
|
|
|
unsigned char file_status;
|
2009-05-22 11:58:49 +00:00
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
2010-10-15 12:25:50 +00:00
|
|
|
cb(&error, -1, -1, -1, NULL, EF_STATUS_INVALIDATED, cbd->data);
|
2009-05-22 11:58:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
2017-11-03 23:30:49 +00:00
|
|
|
if (!g_at_result_iter_next(&iter, prefix))
|
2009-10-02 22:59:08 +00:00
|
|
|
goto error;
|
2009-05-22 11:58:49 +00:00
|
|
|
|
|
|
|
g_at_result_iter_next_number(&iter, &sw1);
|
2009-06-18 03:44:44 +00:00
|
|
|
g_at_result_iter_next_number(&iter, &sw2);
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2009-06-18 03:44:28 +00:00
|
|
|
if (!g_at_result_iter_next_hexstring(&iter, &response, &len) ||
|
2009-09-11 17:36:35 +00:00
|
|
|
(sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92) ||
|
2010-07-06 22:39:00 +00:00
|
|
|
(sw1 == 0x90 && sw2 != 0x00)) {
|
|
|
|
memset(&error, 0, sizeof(error));
|
|
|
|
|
|
|
|
error.type = OFONO_ERROR_TYPE_SIM;
|
|
|
|
error.error = (sw1 << 8) | sw2;
|
|
|
|
|
2010-10-15 12:25:50 +00:00
|
|
|
cb(&error, -1, -1, -1, NULL, EF_STATUS_INVALIDATED, cbd->data);
|
2010-07-06 22:39:00 +00:00
|
|
|
return;
|
|
|
|
}
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("crsm_info_cb: %02x, %02x, %i", sw1, sw2, len);
|
2009-06-18 03:44:44 +00:00
|
|
|
|
2010-10-14 21:02:51 +00:00
|
|
|
if (response[0] == 0x62) {
|
2009-10-02 22:59:08 +00:00
|
|
|
ok = sim_parse_3g_get_response(response, len, &flen, &rlen,
|
|
|
|
&str, access, NULL);
|
2010-10-14 21:02:51 +00:00
|
|
|
|
2010-10-15 12:25:50 +00:00
|
|
|
file_status = EF_STATUS_VALID;
|
2012-03-23 13:12:03 +00:00
|
|
|
} else
|
2009-10-02 22:59:08 +00:00
|
|
|
ok = sim_parse_2g_get_response(response, len, &flen, &rlen,
|
2010-10-14 21:02:51 +00:00
|
|
|
&str, access, &file_status);
|
2009-10-02 22:59:08 +00:00
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
goto error;
|
2009-06-18 03:44:28 +00:00
|
|
|
|
2010-10-14 21:02:51 +00:00
|
|
|
cb(&error, flen, str, rlen, access, file_status, cbd->data);
|
|
|
|
|
2009-10-02 22:59:08 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-10-15 12:25:50 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
|
|
|
|
EF_STATUS_INVALIDATED, cbd->data);
|
2009-05-22 11:58:49 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 23:30:49 +00:00
|
|
|
static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
get_response_common_cb(ok, result, user_data, "+CRSM:");
|
|
|
|
}
|
|
|
|
|
2009-08-18 22:05:50 +00:00
|
|
|
static void at_sim_read_info(struct ofono_sim *sim, int fileid,
|
2012-11-22 15:40:18 +00:00
|
|
|
const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
|
|
|
ofono_sim_file_info_cb_t cb, void *data)
|
2009-05-22 11:58:49 +00:00
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2010-06-13 09:46:29 +00:00
|
|
|
struct cb_data *cbd;
|
2012-11-23 13:09:29 +00:00
|
|
|
char buf[128];
|
|
|
|
unsigned int len;
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2010-06-13 06:10:13 +00:00
|
|
|
if (sd->vendor == OFONO_VENDOR_OPTION_HSO) {
|
|
|
|
unsigned char access[3] = { 0x00, 0x00, 0x00 };
|
|
|
|
|
|
|
|
if (fileid == SIM_EFAD_FILEID) {
|
2010-10-15 12:25:50 +00:00
|
|
|
CALLBACK_WITH_SUCCESS(cb, 4, 0, 0, access,
|
|
|
|
EF_STATUS_VALID, data);
|
2010-06-13 06:10:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-13 09:46:29 +00:00
|
|
|
cbd = cb_data_new(cb, data);
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2012-11-23 13:09:29 +00:00
|
|
|
len = snprintf(buf, sizeof(buf), "AT+CRSM=192,%i", fileid);
|
2009-07-10 18:10:14 +00:00
|
|
|
|
2011-01-10 23:35:39 +00:00
|
|
|
switch (sd->vendor) {
|
2012-11-23 13:09:29 +00:00
|
|
|
default:
|
|
|
|
if (path_len == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Fall through */
|
2011-08-03 21:54:39 +00:00
|
|
|
case OFONO_VENDOR_ZTE:
|
2011-01-10 23:35:39 +00:00
|
|
|
case OFONO_VENDOR_HUAWEI:
|
2011-01-27 14:49:32 +00:00
|
|
|
case OFONO_VENDOR_SIERRA:
|
2011-08-04 13:54:26 +00:00
|
|
|
case OFONO_VENDOR_SPEEDUP:
|
2011-01-10 23:35:39 +00:00
|
|
|
case OFONO_VENDOR_QUALCOMM_MSM:
|
2013-07-19 13:35:38 +00:00
|
|
|
case OFONO_VENDOR_SIMCOM:
|
2020-09-15 13:23:01 +00:00
|
|
|
case OFONO_VENDOR_DROID:
|
2012-11-23 13:09:29 +00:00
|
|
|
/* Maximum possible length */
|
|
|
|
len += sprintf(buf + len, ",0,0,255");
|
2011-01-10 23:35:39 +00:00
|
|
|
break;
|
2011-01-10 21:02:26 +00:00
|
|
|
}
|
2009-11-10 06:30:10 +00:00
|
|
|
|
2017-11-03 22:34:43 +00:00
|
|
|
append_file_path(buf + len, path, path_len);
|
2012-11-23 13:09:29 +00:00
|
|
|
|
2009-11-10 06:30:10 +00:00
|
|
|
if (g_at_chat_send(sd->chat, buf, crsm_prefix,
|
2009-06-18 03:44:44 +00:00
|
|
|
at_crsm_info_cb, cbd, g_free) > 0)
|
2009-05-22 11:58:49 +00:00
|
|
|
return;
|
|
|
|
|
2011-01-29 18:21:21 +00:00
|
|
|
g_free(cbd);
|
|
|
|
|
2010-10-15 12:25:50 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
|
|
|
|
EF_STATUS_INVALIDATED, data);
|
2009-05-22 11:58:49 +00:00
|
|
|
}
|
|
|
|
|
2009-06-18 03:44:44 +00:00
|
|
|
static void at_crsm_read_cb(gboolean ok, GAtResult *result,
|
2012-03-23 13:12:03 +00:00
|
|
|
gpointer user_data)
|
2009-05-22 11:58:49 +00:00
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
GAtResultIter iter;
|
|
|
|
ofono_sim_read_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
const guint8 *response;
|
|
|
|
gint sw1, sw2, len;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, 0, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CRSM:")) {
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
2009-05-22 11:58:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_next_number(&iter, &sw1);
|
|
|
|
g_at_result_iter_next_number(&iter, &sw2);
|
2009-07-10 18:10:14 +00:00
|
|
|
|
2010-07-06 22:39:00 +00:00
|
|
|
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
|
|
|
(sw1 == 0x90 && sw2 != 0x00)) {
|
|
|
|
memset(&error, 0, sizeof(error));
|
|
|
|
|
|
|
|
error.type = OFONO_ERROR_TYPE_SIM;
|
|
|
|
error.error = (sw1 << 8) | sw2;
|
|
|
|
|
|
|
|
cb(&error, NULL, 0, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_hexstring(&iter, &response, &len)) {
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
2009-05-22 11:58:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("crsm_read_cb: %02x, %02x, %d", sw1, sw2, len);
|
2009-05-22 11:58:49 +00:00
|
|
|
|
|
|
|
cb(&error, response, len, cbd->data);
|
|
|
|
}
|
|
|
|
|
2009-08-18 22:05:50 +00:00
|
|
|
static void at_sim_read_binary(struct ofono_sim *sim, int fileid,
|
2012-11-22 15:40:18 +00:00
|
|
|
int start, int length,
|
|
|
|
const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
|
|
|
ofono_sim_read_cb_t cb, void *data)
|
2009-05-22 11:58:49 +00:00
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2009-05-22 11:58:49 +00:00
|
|
|
char buf[64];
|
2012-11-23 13:09:29 +00:00
|
|
|
unsigned int len;
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2012-11-23 13:09:29 +00:00
|
|
|
len = snprintf(buf, sizeof(buf), "AT+CRSM=176,%i,%i,%i,%i", fileid,
|
2009-05-22 11:58:49 +00:00
|
|
|
start >> 8, start & 0xff, length);
|
2009-07-10 18:10:14 +00:00
|
|
|
|
2017-11-03 22:34:43 +00:00
|
|
|
append_file_path(buf + len, path, path_len);
|
2012-11-23 13:09:29 +00:00
|
|
|
|
2009-11-10 06:30:10 +00:00
|
|
|
if (g_at_chat_send(sd->chat, buf, crsm_prefix,
|
2009-06-18 03:44:44 +00:00
|
|
|
at_crsm_read_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-06-18 03:44:44 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
2009-06-18 03:44:44 +00:00
|
|
|
}
|
|
|
|
|
2009-08-18 22:05:50 +00:00
|
|
|
static void at_sim_read_record(struct ofono_sim *sim, int fileid,
|
2012-11-22 15:40:18 +00:00
|
|
|
int record, int length,
|
|
|
|
const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
|
|
|
ofono_sim_read_cb_t cb, void *data)
|
2009-06-18 03:44:44 +00:00
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2012-11-23 13:09:29 +00:00
|
|
|
char buf[128];
|
2017-11-03 22:34:43 +00:00
|
|
|
unsigned int len;
|
2009-06-18 03:44:44 +00:00
|
|
|
|
2017-11-03 22:34:43 +00:00
|
|
|
len = snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid,
|
2009-07-10 18:08:24 +00:00
|
|
|
record, length);
|
2009-07-10 18:10:14 +00:00
|
|
|
|
2017-11-03 22:34:43 +00:00
|
|
|
append_file_path(buf + len, path, path_len);
|
|
|
|
|
2009-11-10 06:30:10 +00:00
|
|
|
if (g_at_chat_send(sd->chat, buf, crsm_prefix,
|
2009-06-18 03:44:44 +00:00
|
|
|
at_crsm_read_cb, cbd, g_free) > 0)
|
2009-05-22 11:58:49 +00:00
|
|
|
return;
|
|
|
|
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
2009-05-22 11:58:49 +00:00
|
|
|
}
|
|
|
|
|
2009-06-18 03:44:44 +00:00
|
|
|
static void at_crsm_update_cb(gboolean ok, GAtResult *result,
|
2012-03-23 13:12:03 +00:00
|
|
|
gpointer user_data)
|
2009-06-18 03:44:44 +00:00
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
GAtResultIter iter;
|
2009-08-18 22:05:50 +00:00
|
|
|
ofono_sim_write_cb_t cb = cbd->cb;
|
2009-06-18 03:44:44 +00:00
|
|
|
struct ofono_error error;
|
|
|
|
gint sw1, sw2;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CRSM:")) {
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
2009-06-18 03:44:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_next_number(&iter, &sw1);
|
|
|
|
g_at_result_iter_next_number(&iter, &sw2);
|
2009-07-10 18:10:14 +00:00
|
|
|
|
2009-06-18 03:44:44 +00:00
|
|
|
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
2009-09-11 17:36:35 +00:00
|
|
|
(sw1 == 0x90 && sw2 != 0x00)) {
|
2010-07-06 22:39:00 +00:00
|
|
|
memset(&error, 0, sizeof(error));
|
|
|
|
|
|
|
|
error.type = OFONO_ERROR_TYPE_SIM;
|
|
|
|
error.error = (sw1 << 8) | sw2;
|
2009-06-18 03:44:44 +00:00
|
|
|
}
|
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("crsm_update_cb: %02x, %02x", sw1, sw2);
|
2009-06-18 03:44:44 +00:00
|
|
|
|
|
|
|
cb(&error, cbd->data);
|
|
|
|
}
|
|
|
|
|
2012-03-22 17:28:10 +00:00
|
|
|
static void at_sim_update_file(struct ofono_sim *sim, int cmd, int fileid,
|
2012-03-23 13:12:03 +00:00
|
|
|
int p1, int p2, int p3,
|
|
|
|
const unsigned char *value,
|
2012-11-22 15:40:18 +00:00
|
|
|
const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
2012-03-23 13:12:03 +00:00
|
|
|
ofono_sim_write_cb_t cb, void *data)
|
2009-06-18 03:44:44 +00:00
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2011-03-02 12:56:52 +00:00
|
|
|
char *buf;
|
2009-06-18 03:44:44 +00:00
|
|
|
int len, ret;
|
2012-11-23 13:21:46 +00:00
|
|
|
int size = 38 + p3 * 2;
|
2011-03-02 12:56:52 +00:00
|
|
|
|
2012-03-22 17:28:10 +00:00
|
|
|
DBG("");
|
|
|
|
|
2011-03-02 12:56:52 +00:00
|
|
|
buf = g_try_new(char, size);
|
2011-01-29 13:34:35 +00:00
|
|
|
if (buf == NULL)
|
2009-06-18 03:44:44 +00:00
|
|
|
goto error;
|
|
|
|
|
2012-11-23 13:21:46 +00:00
|
|
|
len = sprintf(buf, "AT+CRSM=%i,%i,%i,%i,%i,\"", cmd, fileid,p1, p2, p3);
|
2011-03-02 12:56:52 +00:00
|
|
|
|
2012-03-22 17:28:10 +00:00
|
|
|
for (; p3; p3--)
|
2009-12-18 00:58:22 +00:00
|
|
|
len += sprintf(buf + len, "%02hhX", *value++);
|
2009-07-10 18:10:14 +00:00
|
|
|
|
2012-11-23 13:21:46 +00:00
|
|
|
buf[len++] = '\"';
|
|
|
|
buf[len] = '\0';
|
2011-03-02 12:56:52 +00:00
|
|
|
|
2009-11-10 06:30:10 +00:00
|
|
|
ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
|
2012-03-23 13:12:03 +00:00
|
|
|
at_crsm_update_cb, cbd, g_free);
|
2009-06-18 03:44:44 +00:00
|
|
|
|
|
|
|
g_free(buf);
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-06-18 03:44:44 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, data);
|
2009-06-18 03:44:44 +00:00
|
|
|
}
|
|
|
|
|
2012-03-22 17:28:10 +00:00
|
|
|
static void at_sim_update_binary(struct ofono_sim *sim, int fileid,
|
2012-03-23 13:12:03 +00:00
|
|
|
int start, int length,
|
|
|
|
const unsigned char *value,
|
2012-11-22 15:40:18 +00:00
|
|
|
const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
2012-03-23 13:12:03 +00:00
|
|
|
ofono_sim_write_cb_t cb, void *data)
|
2009-06-21 01:30:14 +00:00
|
|
|
{
|
2012-03-22 17:28:10 +00:00
|
|
|
at_sim_update_file(sim, 214, fileid, start >> 8, start & 0xff,
|
2012-11-22 15:40:18 +00:00
|
|
|
length, value, path, path_len, cb, data);
|
2012-03-22 17:28:10 +00:00
|
|
|
}
|
2009-06-21 01:30:14 +00:00
|
|
|
|
2012-03-22 17:28:10 +00:00
|
|
|
static void at_sim_update_record(struct ofono_sim *sim, int fileid,
|
2012-03-23 13:12:03 +00:00
|
|
|
int record, int length,
|
|
|
|
const unsigned char *value,
|
2012-11-22 15:40:18 +00:00
|
|
|
const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
2012-03-23 13:12:03 +00:00
|
|
|
ofono_sim_write_cb_t cb, void *data)
|
2012-03-22 17:28:10 +00:00
|
|
|
{
|
2012-03-23 13:12:03 +00:00
|
|
|
at_sim_update_file(sim, 220, fileid, record, 4, length,
|
2012-11-22 15:40:18 +00:00
|
|
|
value, path, path_len, cb, data);
|
2012-03-22 17:28:10 +00:00
|
|
|
}
|
2009-06-21 01:30:14 +00:00
|
|
|
|
2012-03-22 17:28:10 +00:00
|
|
|
static void at_sim_update_cyclic(struct ofono_sim *sim, int fileid,
|
2012-03-23 13:12:03 +00:00
|
|
|
int length, const unsigned char *value,
|
2012-11-22 15:40:18 +00:00
|
|
|
const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
2012-03-23 13:12:03 +00:00
|
|
|
ofono_sim_write_cb_t cb, void *data)
|
2012-03-22 17:28:10 +00:00
|
|
|
{
|
2012-11-22 15:40:18 +00:00
|
|
|
at_sim_update_file(sim, 220, fileid, 0, 3, length, value,
|
|
|
|
path, path_len, cb, data);
|
2009-06-21 01:30:14 +00:00
|
|
|
}
|
|
|
|
|
2009-05-22 11:58:49 +00:00
|
|
|
static void at_cimi_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
GAtResultIter iter;
|
2009-08-18 22:05:50 +00:00
|
|
|
ofono_sim_imsi_cb_t cb = cbd->cb;
|
2009-05-22 11:58:49 +00:00
|
|
|
struct ofono_error error;
|
|
|
|
const char *imsi;
|
2009-05-29 23:14:40 +00:00
|
|
|
int i;
|
2009-05-22 11:58:49 +00:00
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
2009-07-10 18:10:14 +00:00
|
|
|
|
2009-05-22 11:58:49 +00:00
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
2009-05-29 23:14:40 +00:00
|
|
|
|
|
|
|
for (i = 0; i < g_at_result_num_response_lines(result); i++)
|
|
|
|
g_at_result_iter_next(&iter, NULL);
|
2009-05-22 11:58:49 +00:00
|
|
|
|
|
|
|
imsi = g_at_result_iter_raw_line(&iter);
|
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("cimi_cb: %s", imsi);
|
2009-05-22 11:58:49 +00:00
|
|
|
|
|
|
|
cb(&error, imsi, cbd->data);
|
|
|
|
}
|
|
|
|
|
2009-08-18 22:05:50 +00:00
|
|
|
static void at_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
|
2012-03-23 13:12:03 +00:00
|
|
|
void *data)
|
2009-05-22 11:58:49 +00:00
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-08-19 23:15:46 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2009-11-10 06:30:10 +00:00
|
|
|
if (g_at_chat_send(sd->chat, "AT+CIMI", NULL,
|
2009-05-22 11:58:49 +00:00
|
|
|
at_cimi_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-05-22 11:58:49 +00:00
|
|
|
|
2009-09-11 17:36:35 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
2009-05-22 11:58:49 +00:00
|
|
|
}
|
|
|
|
|
2009-09-17 20:43:22 +00:00
|
|
|
static struct {
|
2009-09-21 13:03:56 +00:00
|
|
|
enum ofono_sim_password_type type;
|
2009-09-17 20:43:22 +00:00
|
|
|
const char *name;
|
|
|
|
} const at_sim_name[] = {
|
2010-06-10 01:23:05 +00:00
|
|
|
{ OFONO_SIM_PASSWORD_NONE, "READY" },
|
|
|
|
{ OFONO_SIM_PASSWORD_SIM_PIN, "SIM PIN" },
|
|
|
|
{ OFONO_SIM_PASSWORD_SIM_PUK, "SIM PUK" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHSIM_PIN, "PH-SIM PIN" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHFSIM_PIN, "PH-FSIM PIN" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHFSIM_PUK, "PH-FSIM PUK" },
|
|
|
|
{ OFONO_SIM_PASSWORD_SIM_PIN2, "SIM PIN2" },
|
|
|
|
{ OFONO_SIM_PASSWORD_SIM_PUK2, "SIM PUK2" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHNET_PIN, "PH-NET PIN" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHNET_PUK, "PH-NET PUK" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHNETSUB_PIN, "PH-NETSUB PIN" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHNETSUB_PUK, "PH-NETSUB PUK" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHSP_PIN, "PH-SP PIN" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHSP_PUK, "PH-SP PUK" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHCORP_PIN, "PH-CORP PIN" },
|
|
|
|
{ OFONO_SIM_PASSWORD_PHCORP_PUK, "PH-CORP PUK" },
|
2009-09-17 20:43:22 +00:00
|
|
|
};
|
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
#define BUILD_PIN_RETRIES_ARRAY(passwd_types, passwd_types_cnt, retry) \
|
|
|
|
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++) \
|
|
|
|
retry[i] = -1; \
|
|
|
|
\
|
|
|
|
for (i = 0; i < passwd_types_cnt; i++) { \
|
|
|
|
int val; \
|
|
|
|
\
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &val)) \
|
|
|
|
goto error; \
|
|
|
|
\
|
|
|
|
retry[passwd_types[i]] = val; \
|
|
|
|
\
|
|
|
|
DBG("retry counter id=%d, val=%d", passwd_types[i], \
|
|
|
|
retry[passwd_types[i]]); \
|
|
|
|
} \
|
|
|
|
|
2011-01-10 21:59:53 +00:00
|
|
|
static void huawei_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
2011-01-10 22:14:50 +00:00
|
|
|
static enum ofono_sim_password_type password_types[] = {
|
2011-01-10 21:59:53 +00:00
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK2,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN2,
|
|
|
|
};
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "^CPIN:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* Skip status since we are not interested in this */
|
|
|
|
if (!g_at_result_iter_skip_next(&iter))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* Skip "overall counter" since we'll grab each one individually */
|
|
|
|
if (!g_at_result_iter_skip_next(&iter))
|
|
|
|
goto error;
|
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
|
|
|
retries);
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
2011-01-10 21:59:53 +00:00
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
return;
|
2011-01-10 21:59:53 +00:00
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2012-05-25 12:32:28 +00:00
|
|
|
static void pinnum_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
static enum ofono_sim_password_type password_types[] = {
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN2,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK2,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "%PINNUM:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
|
|
|
retries);
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2011-08-03 21:54:39 +00:00
|
|
|
static void zpinpuk_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
static enum ofono_sim_password_type password_types[] = {
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+ZPINPUK:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
|
|
|
retries);
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
static void xpincnt_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
static enum ofono_sim_password_type password_types[] = {
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN2,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK2,
|
|
|
|
};
|
2011-01-10 21:59:53 +00:00
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
decode_at_error(&error, final);
|
2011-01-10 21:59:53 +00:00
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
2011-01-10 21:59:53 +00:00
|
|
|
}
|
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+XPINCNT:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
|
|
|
retries);
|
|
|
|
|
2011-01-10 21:59:53 +00:00
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2011-12-29 20:08:38 +00:00
|
|
|
static void oercn_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
static enum ofono_sim_password_type password_types[] = {
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
|
|
|
};
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "_OERCN:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
|
|
|
retries);
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2011-08-04 15:00:05 +00:00
|
|
|
static void cpnnum_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
const char *line;
|
|
|
|
int num;
|
|
|
|
char **entries;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
for (num = 0; num < g_at_result_num_response_lines(result); num++)
|
|
|
|
g_at_result_iter_next(&iter, NULL);
|
|
|
|
|
|
|
|
line = g_at_result_iter_raw_line(&iter);
|
|
|
|
|
|
|
|
DBG("%s", line);
|
|
|
|
|
|
|
|
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
|
|
|
retries[i] = -1;
|
|
|
|
|
|
|
|
entries = g_strsplit(line, "; ", -1);
|
|
|
|
|
|
|
|
for (num = 0; entries[num]; num++) {
|
|
|
|
int retry;
|
|
|
|
|
|
|
|
if (strlen(entries[num]) < 5)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
retry = strtol(entries[num] + 5, NULL, 10);
|
|
|
|
if (retry == 0 && errno == EINVAL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (g_str_has_prefix(entries[num], "PIN1=") == TRUE)
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PIN] = retry;
|
|
|
|
else if (g_str_has_prefix(entries[num], "PUK1=") == TRUE)
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PUK] = retry;
|
|
|
|
else if (g_str_has_prefix(entries[num], "PIN2=") == TRUE)
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PIN2] = retry;
|
|
|
|
else if (g_str_has_prefix(entries[num], "PUK2=") == TRUE)
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PUK2] = retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strfreev(entries);
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
}
|
|
|
|
|
2011-02-01 13:45:47 +00:00
|
|
|
static void at_epin_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
static enum ofono_sim_password_type password_types[] = {
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN2,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK2,
|
|
|
|
};
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "*EPIN:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
|
|
|
retries);
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2011-01-31 12:48:20 +00:00
|
|
|
static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t len = sizeof(at_sim_name) / sizeof(*at_sim_name);
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
|
|
|
retries[i] = -1;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
/* Ignore +CPINRE results... */
|
|
|
|
while (g_at_result_iter_next(&iter, "+CPINR:")) {
|
|
|
|
const char *name;
|
|
|
|
int val;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_unquoted_string(&iter, &name))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &val))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (i = 1; i < len; i++) {
|
|
|
|
if (!strcmp(name, at_sim_name[i].name)) {
|
2015-02-02 09:32:45 +00:00
|
|
|
retries[at_sim_name[i].type] = val;
|
2011-01-31 12:48:20 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
}
|
|
|
|
|
2017-11-07 16:01:57 +00:00
|
|
|
static void simcom_spic_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
2012-02-22 12:18:37 +00:00
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
static enum ofono_sim_password_type password_types[] = {
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN2,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK2,
|
|
|
|
};
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+SPIC:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
|
|
|
retries);
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2012-08-16 07:37:20 +00:00
|
|
|
#define AT_PCT_SET_RETRIES(retries, pin_type, value) \
|
|
|
|
retries[pin_type] = value; \
|
|
|
|
DBG("retry counter id=%d, val=%d", pin_type, value);
|
|
|
|
|
|
|
|
static void at_pct_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_sim *sim = cbd->user;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
2012-08-16 06:04:47 +00:00
|
|
|
enum ofono_sim_password_type pin_type;
|
2012-08-16 07:37:20 +00:00
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
|
|
|
retries[i] = -1;
|
|
|
|
|
2012-08-16 06:04:47 +00:00
|
|
|
pin_type = ofono_sim_get_password_type(sim);
|
2012-08-16 07:37:20 +00:00
|
|
|
if (pin_type == OFONO_SIM_PASSWORD_NONE) {
|
|
|
|
DBG("Note: No password required, returning maximum retries:");
|
2012-08-16 06:05:01 +00:00
|
|
|
|
2012-08-16 07:37:20 +00:00
|
|
|
AT_PCT_SET_RETRIES(retries, OFONO_SIM_PASSWORD_SIM_PIN, 3);
|
|
|
|
AT_PCT_SET_RETRIES(retries, OFONO_SIM_PASSWORD_SIM_PIN2, 3);
|
|
|
|
AT_PCT_SET_RETRIES(retries, OFONO_SIM_PASSWORD_SIM_PUK, 10);
|
|
|
|
AT_PCT_SET_RETRIES(retries, OFONO_SIM_PASSWORD_SIM_PUK2, 10);
|
2012-08-16 06:05:01 +00:00
|
|
|
|
2012-08-16 07:37:20 +00:00
|
|
|
goto callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_at_result_iter_next(&iter, "#PCT:") == FALSE)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (g_at_result_iter_next_number(&iter, &retries[pin_type]) == FALSE)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
DBG("retry counter id=%d, val=%d", pin_type, retries[pin_type]);
|
|
|
|
|
|
|
|
callback:
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2012-11-15 08:35:51 +00:00
|
|
|
static void at_pnnm_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
static enum ofono_sim_password_type password_types[] = {
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
|
|
|
};
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+PNNM:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
|
|
|
retries);
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2018-08-28 07:45:39 +00:00
|
|
|
static void at_qtrpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
|
|
|
retries[i] = -1;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
while (g_at_result_iter_next(&iter, "+QTRPIN:")) {
|
|
|
|
int pin, pin2, puk, puk2;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &pin))
|
|
|
|
continue;
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &pin2))
|
|
|
|
continue;
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &puk))
|
|
|
|
continue;
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &puk2))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PIN] = pin;
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PUK] = puk;
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PIN2] = pin2;
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PUK2] = puk2;
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
}
|
|
|
|
|
2014-06-26 17:08:14 +00:00
|
|
|
static void at_qpinc_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
|
|
|
retries[i] = -1;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
2014-06-30 18:44:40 +00:00
|
|
|
|
2014-06-26 17:08:14 +00:00
|
|
|
while (g_at_result_iter_next(&iter, "+QPINC:")) {
|
|
|
|
const char *name;
|
|
|
|
int pin, puk;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_string(&iter, &name))
|
|
|
|
continue;
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &pin))
|
|
|
|
continue;
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &puk))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!strcmp(name, "SC")) {
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PIN] = pin;
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PUK] = puk;
|
|
|
|
} else if (!strcmp(name, "P2")) {
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PIN2] = pin;
|
|
|
|
retries[OFONO_SIM_PASSWORD_SIM_PUK2] = puk;
|
|
|
|
}
|
|
|
|
}
|
2014-06-30 18:44:40 +00:00
|
|
|
|
2014-06-26 17:08:14 +00:00
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
}
|
|
|
|
|
2014-07-03 10:32:05 +00:00
|
|
|
static void upincnt_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
static enum ofono_sim_password_type password_types[] = {
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PIN2,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK,
|
|
|
|
OFONO_SIM_PASSWORD_SIM_PUK2,
|
|
|
|
};
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+UPINCNT:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
|
|
|
|
retries);
|
|
|
|
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2018-09-25 07:12:32 +00:00
|
|
|
static void gemalto_spic_cb(gboolean ok, GAtResult *result,
|
2017-11-07 16:01:57 +00:00
|
|
|
gpointer user_data)
|
2017-11-07 09:53:10 +00:00
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
struct ofono_sim *sim = cbd->user;
|
|
|
|
ofono_sim_pin_retries_cb_t cb = cbd->cb;
|
|
|
|
const char *final = g_at_result_final_response(result);
|
|
|
|
GAtResultIter iter;
|
|
|
|
struct ofono_error error;
|
|
|
|
int retries[OFONO_SIM_PASSWORD_INVALID];
|
|
|
|
size_t i;
|
|
|
|
int pin_type = ofono_sim_get_password_type(sim);
|
|
|
|
|
|
|
|
decode_at_error(&error, final);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
|
|
|
|
retries[i] = -1;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "^SPIC:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &retries[pin_type]))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
DBG("Retry : %d, type : %d", retries[pin_type], pin_type);
|
|
|
|
cb(&error, retries, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
|
|
|
|
}
|
|
|
|
|
2011-01-10 21:59:53 +00:00
|
|
|
static void at_pin_retries_query(struct ofono_sim *sim,
|
2011-01-19 18:34:53 +00:00
|
|
|
ofono_sim_pin_retries_cb_t cb,
|
|
|
|
void *data)
|
2011-01-10 21:59:53 +00:00
|
|
|
{
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2011-01-19 18:34:53 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
2012-08-16 07:37:20 +00:00
|
|
|
cbd->user = sim;
|
2011-01-10 21:59:53 +00:00
|
|
|
|
|
|
|
DBG("");
|
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
switch (sd->vendor) {
|
2019-04-02 06:24:02 +00:00
|
|
|
case OFONO_VENDOR_XMM:
|
2011-01-19 18:34:53 +00:00
|
|
|
case OFONO_VENDOR_IFX:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT+XPINCNT", xpincnt_prefix,
|
|
|
|
xpincnt_cb, cbd, g_free) > 0)
|
2011-01-10 21:59:53 +00:00
|
|
|
return;
|
2011-01-19 18:34:53 +00:00
|
|
|
break;
|
2011-08-04 15:00:05 +00:00
|
|
|
case OFONO_VENDOR_SPEEDUP:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT+CPNNUM", NULL,
|
|
|
|
cpnnum_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
break;
|
2011-12-29 20:08:38 +00:00
|
|
|
case OFONO_VENDOR_OPTION_HSO:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT_OERCN?", oercn_prefix,
|
|
|
|
oercn_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
break;
|
2011-01-19 18:34:53 +00:00
|
|
|
case OFONO_VENDOR_HUAWEI:
|
2011-01-10 21:59:53 +00:00
|
|
|
if (g_at_chat_send(sd->chat, "AT^CPIN?", huawei_cpin_prefix,
|
|
|
|
huawei_cpin_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
2011-08-03 21:54:39 +00:00
|
|
|
break;
|
2012-05-25 12:32:28 +00:00
|
|
|
case OFONO_VENDOR_ICERA:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT%PINNUM?", pinnum_prefix,
|
|
|
|
pinnum_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
break;
|
2011-08-03 21:54:39 +00:00
|
|
|
case OFONO_VENDOR_ZTE:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT+ZPINPUK=?", zpinpuk_prefix,
|
|
|
|
zpinpuk_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
2011-02-01 13:45:47 +00:00
|
|
|
break;
|
|
|
|
case OFONO_VENDOR_MBM:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT*EPIN?", epin_prefix,
|
|
|
|
at_epin_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
2011-01-19 20:56:48 +00:00
|
|
|
break;
|
2012-02-22 12:18:37 +00:00
|
|
|
case OFONO_VENDOR_SIMCOM:
|
2017-11-07 16:01:57 +00:00
|
|
|
if (g_at_chat_send(sd->chat, "AT+SPIC", simcom_spic_prefix,
|
|
|
|
simcom_spic_cb, cbd, g_free) > 0)
|
2012-02-22 12:18:37 +00:00
|
|
|
return;
|
|
|
|
break;
|
2012-08-16 07:37:20 +00:00
|
|
|
case OFONO_VENDOR_TELIT:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT#PCT", pct_prefix,
|
|
|
|
at_pct_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
break;
|
2012-11-15 08:35:51 +00:00
|
|
|
case OFONO_VENDOR_ALCATEL:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT+PNNM?", pnnm_prefix,
|
|
|
|
at_pnnm_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
break;
|
2014-06-26 17:08:14 +00:00
|
|
|
case OFONO_VENDOR_QUECTEL:
|
2020-08-11 11:42:15 +00:00
|
|
|
case OFONO_VENDOR_QUECTEL_EC2X:
|
2014-06-26 17:08:14 +00:00
|
|
|
if (g_at_chat_send(sd->chat, "AT+QPINC?", qpinc_prefix,
|
|
|
|
at_qpinc_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
break;
|
2019-07-16 19:10:48 +00:00
|
|
|
case OFONO_VENDOR_QUECTEL_SERIAL:
|
2018-08-28 07:45:39 +00:00
|
|
|
if (g_at_chat_send(sd->chat, "AT+QTRPIN", qtrpin_prefix,
|
|
|
|
at_qtrpin_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
break;
|
2014-07-03 10:32:05 +00:00
|
|
|
case OFONO_VENDOR_UBLOX:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT+UPINCNT", upincnt_prefix,
|
|
|
|
upincnt_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
break;
|
2018-09-25 07:12:32 +00:00
|
|
|
case OFONO_VENDOR_GEMALTO:
|
|
|
|
if (g_at_chat_send(sd->chat, "AT^SPIC", gemalto_spic_prefix,
|
|
|
|
gemalto_spic_cb, cbd, g_free) > 0)
|
2017-11-07 09:53:10 +00:00
|
|
|
return;
|
|
|
|
break;
|
2011-01-19 18:34:53 +00:00
|
|
|
default:
|
2011-01-31 12:48:20 +00:00
|
|
|
if (g_at_chat_send(sd->chat, "AT+CPINR", cpinr_prefixes,
|
|
|
|
at_cpinr_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
2011-01-10 22:21:16 +00:00
|
|
|
break;
|
2011-01-19 18:34:53 +00:00
|
|
|
}
|
2011-01-10 21:59:53 +00:00
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
g_free(cbd);
|
2011-01-10 21:59:53 +00:00
|
|
|
|
2011-01-19 18:34:53 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, data);
|
2011-01-10 21:59:53 +00:00
|
|
|
}
|
|
|
|
|
2012-11-01 09:05:03 +00:00
|
|
|
static int needs_wavecom_sim_quirk(int vendor)
|
|
|
|
{
|
|
|
|
return vendor == OFONO_VENDOR_WAVECOM ||
|
|
|
|
vendor == OFONO_VENDOR_WAVECOM_Q2XXX;
|
|
|
|
}
|
|
|
|
|
2009-09-17 20:43:22 +00:00
|
|
|
static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
2010-02-08 22:13:43 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(cbd->user);
|
2009-09-17 20:43:22 +00:00
|
|
|
GAtResultIter iter;
|
|
|
|
ofono_sim_passwd_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
const char *pin_required;
|
2009-09-21 13:03:56 +00:00
|
|
|
int pin_type = OFONO_SIM_PASSWORD_INVALID;
|
2009-09-17 20:43:22 +00:00
|
|
|
int i;
|
|
|
|
int len = sizeof(at_sim_name) / sizeof(*at_sim_name);
|
2010-02-08 22:13:43 +00:00
|
|
|
const char *final = g_at_result_final_response(result);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
2012-11-01 09:05:03 +00:00
|
|
|
if (needs_wavecom_sim_quirk(sd->vendor) && ok && strlen(final) > 7)
|
2010-02-08 22:13:43 +00:00
|
|
|
decode_at_error(&error, "OK");
|
|
|
|
else
|
|
|
|
decode_at_error(&error, final);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, -1, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-11-01 09:05:03 +00:00
|
|
|
if (needs_wavecom_sim_quirk(sd->vendor)) {
|
2010-02-08 22:13:43 +00:00
|
|
|
/* +CPIN: <pin> */
|
|
|
|
pin_required = final + 7;
|
|
|
|
} else {
|
|
|
|
g_at_result_iter_init(&iter, result);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
2010-02-08 22:13:43 +00:00
|
|
|
if (!g_at_result_iter_next(&iter, "+CPIN:")) {
|
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-17 20:43:22 +00:00
|
|
|
|
2010-02-08 22:13:43 +00:00
|
|
|
g_at_result_iter_next_unquoted_string(&iter, &pin_required);
|
|
|
|
}
|
2009-09-17 20:43:22 +00:00
|
|
|
|
2009-09-21 15:11:07 +00:00
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
if (strcmp(pin_required, at_sim_name[i].name))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pin_type = at_sim_name[i].type;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-17 20:43:22 +00:00
|
|
|
|
2009-09-21 13:03:56 +00:00
|
|
|
if (pin_type == OFONO_SIM_PASSWORD_INVALID) {
|
2009-09-17 20:43:22 +00:00
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("crsm_pin_cb: %s", pin_required);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
cb(&error, pin_type, cbd->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
|
|
|
|
void *data)
|
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-09-17 20:43:22 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
|
2010-02-08 22:13:43 +00:00
|
|
|
cbd->user = sim;
|
|
|
|
|
2010-05-12 01:20:53 +00:00
|
|
|
if (g_at_chat_send(sd->chat, "AT+CPIN?", cpin_prefix,
|
2009-09-17 20:43:22 +00:00
|
|
|
at_cpin_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
|
|
|
}
|
|
|
|
|
2012-04-18 12:39:48 +00:00
|
|
|
static void sim_state_cb(gboolean present, gpointer user_data)
|
|
|
|
{
|
2017-11-09 03:37:12 +00:00
|
|
|
struct ofono_sim *sim = user_data;
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2012-04-18 12:39:48 +00:00
|
|
|
|
|
|
|
at_util_sim_state_query_free(sd->sim_state_query);
|
|
|
|
sd->sim_state_query = NULL;
|
|
|
|
|
|
|
|
if (present == 1)
|
2017-11-09 03:37:12 +00:00
|
|
|
ofono_sim_initialized_notify(sim);
|
2012-04-18 12:39:48 +00:00
|
|
|
}
|
|
|
|
|
2010-06-17 13:42:13 +00:00
|
|
|
static void at_pin_send_cb(gboolean ok, GAtResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
2017-11-09 03:37:12 +00:00
|
|
|
struct ofono_sim *sim = cbd->user;
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2010-06-17 13:42:13 +00:00
|
|
|
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
2010-09-25 02:32:40 +00:00
|
|
|
if (!ok)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
switch (sd->vendor) {
|
2012-04-18 12:39:48 +00:00
|
|
|
case OFONO_VENDOR_ZTE:
|
2012-11-09 13:16:53 +00:00
|
|
|
case OFONO_VENDOR_ALCATEL:
|
|
|
|
case OFONO_VENDOR_HUAWEI:
|
2013-03-22 10:36:17 +00:00
|
|
|
case OFONO_VENDOR_SIMCOM:
|
2015-02-02 09:32:44 +00:00
|
|
|
case OFONO_VENDOR_SIERRA:
|
2012-04-18 12:39:48 +00:00
|
|
|
/*
|
|
|
|
* On ZTE modems, after pin is entered, SIM state is checked
|
|
|
|
* by polling CPIN as their modem doesn't provide unsolicited
|
|
|
|
* notification of SIM readiness.
|
2013-03-22 10:36:17 +00:00
|
|
|
*
|
|
|
|
* On SIMCOM modems, SIM is busy after pin is entered (we
|
|
|
|
* got a "+CME ERROR: 14" for the "AT+CPIN?" request) and
|
|
|
|
* ofono don't catch the "+CPIN: READY" message sent by the
|
|
|
|
* modem when SIM is ready. So, use extra CPIN to check the
|
|
|
|
* state.
|
2012-04-18 12:39:48 +00:00
|
|
|
*/
|
|
|
|
sd->sim_state_query = at_util_sim_state_query_new(sd->chat,
|
2017-11-09 03:37:12 +00:00
|
|
|
2, 20, sim_state_cb, sim,
|
|
|
|
NULL);
|
2010-06-17 13:42:13 +00:00
|
|
|
}
|
|
|
|
|
2010-09-25 02:32:40 +00:00
|
|
|
done:
|
2010-06-17 13:42:13 +00:00
|
|
|
cb(&error, cbd->data);
|
|
|
|
}
|
|
|
|
|
2009-09-17 20:43:22 +00:00
|
|
|
static void at_pin_send(struct ofono_sim *sim, const char *passwd,
|
|
|
|
ofono_sim_lock_unlock_cb_t cb, void *data)
|
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-09-17 20:43:22 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char buf[64];
|
|
|
|
int ret;
|
|
|
|
|
2017-11-09 03:37:12 +00:00
|
|
|
cbd->user = sim;
|
2010-06-17 13:42:13 +00:00
|
|
|
|
2009-09-17 20:43:22 +00:00
|
|
|
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
|
|
|
|
|
2010-05-12 01:20:53 +00:00
|
|
|
ret = g_at_chat_send(sd->chat, buf, none_prefix,
|
2017-11-09 03:37:12 +00:00
|
|
|
at_pin_send_cb, cbd, g_free);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
return;
|
|
|
|
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
|
|
|
|
const char *passwd,
|
|
|
|
ofono_sim_lock_unlock_cb_t cb, void *data)
|
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-09-17 20:43:22 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char buf[64];
|
|
|
|
int ret;
|
|
|
|
|
2018-05-22 13:08:31 +00:00
|
|
|
cbd->user = sim;
|
2010-10-16 10:26:26 +00:00
|
|
|
|
2009-09-17 20:43:22 +00:00
|
|
|
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd);
|
|
|
|
|
2010-05-12 01:20:53 +00:00
|
|
|
ret = g_at_chat_send(sd->chat, buf, none_prefix,
|
2018-05-22 13:08:31 +00:00
|
|
|
at_pin_send_cb, cbd, g_free);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
return;
|
|
|
|
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, data);
|
|
|
|
}
|
|
|
|
|
2010-10-16 10:26:26 +00:00
|
|
|
static void at_lock_unlock_cb(gboolean ok, GAtResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
cb(&error, cbd->data);
|
|
|
|
}
|
|
|
|
|
2009-09-17 20:43:22 +00:00
|
|
|
static const char *const at_clck_cpwd_fac[] = {
|
2009-09-21 13:03:56 +00:00
|
|
|
[OFONO_SIM_PASSWORD_SIM_PIN] = "SC",
|
|
|
|
[OFONO_SIM_PASSWORD_SIM_PIN2] = "P2",
|
|
|
|
[OFONO_SIM_PASSWORD_PHSIM_PIN] = "PS",
|
|
|
|
[OFONO_SIM_PASSWORD_PHFSIM_PIN] = "PF",
|
|
|
|
[OFONO_SIM_PASSWORD_PHNET_PIN] = "PN",
|
|
|
|
[OFONO_SIM_PASSWORD_PHNETSUB_PIN] = "PU",
|
|
|
|
[OFONO_SIM_PASSWORD_PHSP_PIN] = "PP",
|
|
|
|
[OFONO_SIM_PASSWORD_PHCORP_PIN] = "PC",
|
2009-09-17 20:43:22 +00:00
|
|
|
};
|
|
|
|
|
2009-09-22 04:04:53 +00:00
|
|
|
static void at_pin_enable(struct ofono_sim *sim,
|
|
|
|
enum ofono_sim_password_type passwd_type,
|
|
|
|
int enable, const char *passwd,
|
|
|
|
ofono_sim_lock_unlock_cb_t cb, void *data)
|
2009-09-17 20:43:22 +00:00
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-09-17 20:43:22 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char buf[64];
|
|
|
|
int ret;
|
|
|
|
|
2017-10-23 20:52:36 +00:00
|
|
|
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
2009-09-17 20:43:22 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
|
|
|
|
at_clck_cpwd_fac[passwd_type], enable ? 1 : 0, passwd);
|
|
|
|
|
2010-05-12 01:20:53 +00:00
|
|
|
ret = g_at_chat_send(sd->chat, buf, none_prefix,
|
2009-11-10 06:30:10 +00:00
|
|
|
at_lock_unlock_cb, cbd, g_free);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, data);
|
|
|
|
}
|
|
|
|
|
2009-09-21 13:03:56 +00:00
|
|
|
static void at_change_passwd(struct ofono_sim *sim,
|
2012-03-23 13:12:03 +00:00
|
|
|
enum ofono_sim_password_type passwd_type,
|
|
|
|
const char *old_passwd, const char *new_passwd,
|
|
|
|
ofono_sim_lock_unlock_cb_t cb, void *data)
|
2009-09-17 20:43:22 +00:00
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-09-17 20:43:22 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char buf[64];
|
|
|
|
int ret;
|
|
|
|
|
2017-10-23 20:52:36 +00:00
|
|
|
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
2009-09-17 20:43:22 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
|
2011-01-26 16:17:01 +00:00
|
|
|
at_clck_cpwd_fac[passwd_type], old_passwd, new_passwd);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
2010-05-12 01:20:53 +00:00
|
|
|
ret = g_at_chat_send(sd->chat, buf, none_prefix,
|
2009-11-10 06:30:10 +00:00
|
|
|
at_lock_unlock_cb, cbd, g_free);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-09-17 20:43:22 +00:00
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, data);
|
|
|
|
}
|
|
|
|
|
2009-09-23 22:33:28 +00:00
|
|
|
static void at_lock_status_cb(gboolean ok, GAtResult *result,
|
2012-03-23 13:12:03 +00:00
|
|
|
gpointer user_data)
|
2009-09-23 22:33:28 +00:00
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
GAtResultIter iter;
|
2016-04-27 16:04:43 +00:00
|
|
|
ofono_query_facility_lock_cb_t cb = cbd->cb;
|
2009-09-23 22:33:28 +00:00
|
|
|
struct ofono_error error;
|
|
|
|
int locked;
|
|
|
|
|
|
|
|
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, "+CLCK:")) {
|
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_next_number(&iter, &locked);
|
|
|
|
|
2010-02-08 18:09:01 +00:00
|
|
|
DBG("lock_status_cb: %i", locked);
|
2009-09-23 22:33:28 +00:00
|
|
|
|
|
|
|
cb(&error, locked, cbd->data);
|
|
|
|
}
|
|
|
|
|
2016-04-27 16:04:43 +00:00
|
|
|
static void at_query_clck(struct ofono_sim *sim,
|
2009-09-23 22:33:28 +00:00
|
|
|
enum ofono_sim_password_type passwd_type,
|
2016-04-27 16:04:43 +00:00
|
|
|
ofono_query_facility_lock_cb_t cb, void *data)
|
2009-09-23 22:33:28 +00:00
|
|
|
{
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
2009-09-23 22:33:28 +00:00
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char buf[64];
|
|
|
|
|
2017-10-23 20:52:36 +00:00
|
|
|
if (!(sd->passwd_type_mask & (1 << passwd_type)))
|
2009-09-23 22:33:28 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
|
|
|
|
at_clck_cpwd_fac[passwd_type]);
|
|
|
|
|
2010-05-12 01:20:53 +00:00
|
|
|
if (g_at_chat_send(sd->chat, buf, clck_prefix,
|
2009-09-23 22:33:28 +00:00
|
|
|
at_lock_status_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2010-08-16 20:02:01 +00:00
|
|
|
g_free(cbd);
|
2009-09-23 22:33:28 +00:00
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
|
|
|
}
|
|
|
|
|
2017-10-23 20:52:36 +00:00
|
|
|
static void at_clck_query_cb(gboolean ok, GAtResult *result, gpointer user)
|
2009-08-18 22:05:50 +00:00
|
|
|
{
|
|
|
|
struct ofono_sim *sim = user;
|
2017-10-23 20:52:36 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
GAtResultIter iter;
|
|
|
|
const char *fac;
|
2009-08-18 22:05:50 +00:00
|
|
|
|
2017-10-23 20:52:36 +00:00
|
|
|
if (!ok)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
/* e.g. +CLCK: ("SC","FD","PN","PU","PP","PC","PF") */
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CLCK:") ||
|
|
|
|
!g_at_result_iter_open_list(&iter))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Clear the default mask */
|
|
|
|
sd->passwd_type_mask = 0;
|
2009-08-18 22:05:50 +00:00
|
|
|
|
2017-10-23 20:52:36 +00:00
|
|
|
/* Set the bits for <fac>s that are actually supported */
|
|
|
|
while (g_at_result_iter_next_string(&iter, &fac)) {
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
/* Find it in the list of known <fac>s */
|
|
|
|
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++) {
|
|
|
|
if (!g_strcmp0(at_clck_cpwd_fac[i], fac)) {
|
|
|
|
sd->passwd_type_mask |= (1 << i);
|
|
|
|
DBG("found %s", fac);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
ofono_sim_register(sim);
|
2009-08-18 22:05:50 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 23:30:49 +00:00
|
|
|
static void at_discover_apps_cb(gboolean ok, GAtResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
GAtResultIter iter;
|
|
|
|
ofono_sim_list_apps_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
const unsigned char *buffer;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, 0, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CUAD:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_hexstring(&iter, &buffer, &len))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
cb(&error, buffer, len, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_discover_apps(struct ofono_sim *sim,
|
|
|
|
ofono_sim_list_apps_cb_t cb,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
|
|
|
|
if (g_at_chat_send(sd->chat, "AT+CUAD", cuad_prefix,
|
|
|
|
at_discover_apps_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free(cbd);
|
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_open_channel_cb(gboolean ok, GAtResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
GAtResultIter iter;
|
|
|
|
ofono_sim_open_channel_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
int session_id = -1;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CCHO:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &session_id))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
cb(&error, session_id, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
cb(&error, -1, cbd->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_open_channel(struct ofono_sim *sim, const unsigned char *aid,
|
|
|
|
ofono_sim_open_channel_cb_t cb, void *data)
|
|
|
|
{
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char cmd[43];
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
strcpy(cmd, "AT+CCHO=\"");
|
|
|
|
ret += 9;
|
|
|
|
|
|
|
|
encode_hex_own_buf(aid, 16, 0, cmd + ret);
|
|
|
|
ret += 32;
|
|
|
|
|
|
|
|
strcpy(cmd + ret, "\"");
|
|
|
|
|
|
|
|
if (g_at_chat_send(sd->chat, cmd, ccho_prefix, at_open_channel_cb,
|
|
|
|
cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free(cbd);
|
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_close_channel_cb(gboolean ok, GAtResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_close_channel_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (cb)
|
|
|
|
cb(&error, cbd->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_close_channel(struct ofono_sim *sim, int session_id,
|
|
|
|
ofono_sim_close_channel_cb_t cb, void *data)
|
|
|
|
{
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char cmd[15];
|
|
|
|
|
|
|
|
sprintf(cmd, "AT+CCHC=%d", session_id);
|
|
|
|
|
|
|
|
g_at_chat_send(sd->chat, cmd, NULL, at_close_channel_cb, cbd, g_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_crla_read_cb(gboolean ok, GAtResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
GAtResultIter iter;
|
|
|
|
ofono_sim_read_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
const guint8 *response;
|
|
|
|
gint sw1, sw2, len;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
cb(&error, NULL, 0, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CRLA:")) {
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_at_result_iter_next_number(&iter, &sw1);
|
|
|
|
g_at_result_iter_next_number(&iter, &sw2);
|
|
|
|
|
|
|
|
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
|
|
|
|
(sw1 == 0x90 && sw2 != 0x00)) {
|
|
|
|
memset(&error, 0, sizeof(error));
|
|
|
|
|
|
|
|
error.type = OFONO_ERROR_TYPE_SIM;
|
|
|
|
error.error = (sw1 << 8) | sw2;
|
|
|
|
|
|
|
|
cb(&error, NULL, 0, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_hexstring(&iter, &response, &len)) {
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG("crla_read_cb: %02x, %02x, %d", sw1, sw2, len);
|
|
|
|
|
|
|
|
cb(&error, response, len, cbd->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_session_read_binary(struct ofono_sim *sim, int session,
|
|
|
|
int fileid, int start, int length,
|
|
|
|
const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
|
|
|
ofono_sim_read_cb_t cb, void *data)
|
|
|
|
{
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char buf[64];
|
|
|
|
unsigned int len;
|
|
|
|
|
|
|
|
len = snprintf(buf, sizeof(buf), "AT+CRLA=%i,176,%i,%i,%i,%i,,",
|
|
|
|
session, fileid, start >> 8, start & 0xff, length);
|
|
|
|
|
|
|
|
append_file_path(buf + len, path, path_len);
|
|
|
|
|
|
|
|
if (g_at_chat_send(sd->chat, buf, crla_prefix,
|
|
|
|
at_crla_read_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free(cbd);
|
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_session_read_record(struct ofono_sim *sim, int session_id,
|
|
|
|
int fileid, int record, int length,
|
|
|
|
const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
|
|
|
ofono_sim_read_cb_t cb, void *data)
|
|
|
|
{
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char buf[128];
|
|
|
|
unsigned int len;
|
|
|
|
|
|
|
|
len = snprintf(buf, sizeof(buf), "AT+CRLA=%i,178,%i,%i,4,%i",
|
|
|
|
session_id, fileid, record, length);
|
|
|
|
|
|
|
|
append_file_path(buf + len, path, path_len);
|
|
|
|
|
|
|
|
if (g_at_chat_send(sd->chat, buf, crla_prefix,
|
|
|
|
at_crla_read_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free(cbd);
|
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_crla_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|
|
|
{
|
|
|
|
get_response_common_cb(ok, result, user_data, "+CRLA:");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_session_read_info(struct ofono_sim *sim, int session_id,
|
|
|
|
int fileid, const unsigned char *path,
|
|
|
|
unsigned int path_len,
|
|
|
|
ofono_sim_file_info_cb_t cb, void *data)
|
|
|
|
{
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char buf[128];
|
|
|
|
unsigned int len;
|
|
|
|
|
|
|
|
len = snprintf(buf, sizeof(buf), "AT+CRLA=%i,192,%i", session_id,
|
|
|
|
fileid);
|
|
|
|
|
|
|
|
append_file_path(buf + len, path, path_len);
|
|
|
|
|
|
|
|
if (g_at_chat_send(sd->chat, buf, crla_prefix,
|
|
|
|
at_crla_info_cb, cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free(cbd);
|
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
|
|
|
|
EF_STATUS_INVALIDATED, data);
|
|
|
|
}
|
|
|
|
|
2017-11-07 16:42:50 +00:00
|
|
|
static void logical_access_cb(gboolean ok, GAtResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_logical_access_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
const char *str_data;
|
|
|
|
unsigned char *raw;
|
|
|
|
gint len = 0;
|
|
|
|
GAtResultIter iter;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+CGLA:"))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &len))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_string(&iter, &str_data))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
raw = alloca(len / 2);
|
|
|
|
|
|
|
|
decode_hex_own_buf(str_data, len, NULL, 0, raw);
|
|
|
|
|
|
|
|
cb(&error, raw, len / 2, cbd->data);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
cb(&error, NULL, 0, cbd->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_logical_access(struct ofono_sim *sim, int session_id,
|
|
|
|
const unsigned char *pdu, unsigned int len,
|
|
|
|
ofono_sim_logical_access_cb_t cb, void *data)
|
|
|
|
{
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
int ret = 0;
|
|
|
|
char cmd[(len * 2) + 19];
|
|
|
|
|
|
|
|
ret = sprintf(cmd, "AT+CGLA=%d,%d,\"", session_id, len * 2);
|
|
|
|
|
|
|
|
encode_hex_own_buf(pdu, len, 0, cmd + ret);
|
|
|
|
ret += len * 2;
|
|
|
|
|
|
|
|
strcpy(cmd + ret, "\"");
|
|
|
|
|
|
|
|
if (g_at_chat_send(sd->chat, cmd, cgla_prefix, logical_access_cb,
|
|
|
|
cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free(cbd);
|
|
|
|
|
|
|
|
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
|
|
|
|
}
|
|
|
|
|
2019-04-02 06:24:02 +00:00
|
|
|
static void xcmscsc_query_cb(gboolean ok, GAtResult *result, gpointer user)
|
|
|
|
{
|
|
|
|
struct ofono_sim *sim = user;
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
GAtResultIter iter;
|
|
|
|
int active_slot;
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+XCMSCSC:"))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
g_at_result_iter_skip_next(&iter);
|
|
|
|
g_at_result_iter_skip_next(&iter);
|
|
|
|
|
|
|
|
g_at_result_iter_next_number(&iter, &active_slot);
|
|
|
|
|
|
|
|
/* set active SIM slot */
|
|
|
|
ofono_sim_set_active_card_slot(sim, active_slot + 1);
|
|
|
|
|
|
|
|
done:
|
|
|
|
/* Query supported <fac>s */
|
|
|
|
g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
|
|
|
|
at_clck_query_cb, sim, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_xcmscsc_test_cb(gboolean ok, GAtResult *result, gpointer user)
|
|
|
|
{
|
|
|
|
struct ofono_sim *sim = user;
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
GAtResultIter iter;
|
|
|
|
int card_slot_count;
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
g_at_result_iter_init(&iter, result);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next(&iter, "+XCMSCSC:"))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
g_at_result_iter_skip_next(&iter);
|
|
|
|
g_at_result_iter_skip_next(&iter);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_open_list(&iter))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
g_at_result_iter_skip_next(&iter);
|
|
|
|
|
|
|
|
if (!g_at_result_iter_next_number(&iter, &card_slot_count))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Set num slots */
|
|
|
|
ofono_sim_set_card_slot_count(sim, card_slot_count + 1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* enable reporting of MSIM remap status information
|
|
|
|
* and enable automatic acceptance of MSIM Remap
|
|
|
|
* acknowledgement
|
|
|
|
*/
|
|
|
|
g_at_chat_send(sd->chat, "AT+XCMSRS=2", none_prefix,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
/* Query active card slot */
|
|
|
|
g_at_chat_send(sd->chat, "AT+XCMSCSC?", xcmscsc_prefix,
|
|
|
|
xcmscsc_query_cb, sim, NULL);
|
|
|
|
return;
|
|
|
|
|
|
|
|
done:
|
|
|
|
/* Query supported <fac>s */
|
|
|
|
g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
|
|
|
|
at_clck_query_cb, sim, NULL);
|
|
|
|
}
|
|
|
|
|
2009-09-02 02:39:02 +00:00
|
|
|
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
|
|
|
|
void *data)
|
2009-08-18 22:05:50 +00:00
|
|
|
{
|
2009-09-01 22:36:27 +00:00
|
|
|
GAtChat *chat = data;
|
2009-11-10 06:30:10 +00:00
|
|
|
struct sim_data *sd;
|
2017-10-23 20:52:36 +00:00
|
|
|
unsigned int i;
|
2009-11-10 06:30:10 +00:00
|
|
|
|
|
|
|
sd = g_new0(struct sim_data, 1);
|
2010-08-12 21:40:40 +00:00
|
|
|
sd->chat = g_at_chat_clone(chat);
|
2009-11-10 06:30:10 +00:00
|
|
|
sd->vendor = vendor;
|
2009-09-01 22:36:27 +00:00
|
|
|
|
2009-11-10 06:30:10 +00:00
|
|
|
ofono_sim_set_data(sim, sd);
|
2009-08-18 22:05:50 +00:00
|
|
|
|
2017-10-23 20:52:36 +00:00
|
|
|
/* <fac>s supported by default */
|
|
|
|
for (i = 0; i < ARRAY_SIZE(at_clck_cpwd_fac); i++)
|
|
|
|
if (at_clck_cpwd_fac[i])
|
|
|
|
sd->passwd_type_mask |= (1 << i);
|
|
|
|
|
2019-04-02 06:24:02 +00:00
|
|
|
if (sd->vendor == OFONO_VENDOR_XMM)
|
|
|
|
return g_at_chat_send(sd->chat, "AT+XCMSCSC=?", xcmscsc_prefix,
|
|
|
|
at_xcmscsc_test_cb, sim, NULL) ? 0 : -1;
|
|
|
|
|
2017-10-23 20:52:36 +00:00
|
|
|
/* Query supported <fac>s */
|
|
|
|
return g_at_chat_send(sd->chat, "AT+CLCK=?", clck_prefix,
|
|
|
|
at_clck_query_cb, sim, NULL) ? 0 : -1;
|
2009-08-18 22:05:50 +00:00
|
|
|
}
|
|
|
|
|
2009-09-02 03:27:08 +00:00
|
|
|
static void at_sim_remove(struct ofono_sim *sim)
|
2009-08-18 22:05:50 +00:00
|
|
|
{
|
2009-11-11 21:58:45 +00:00
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
|
2012-12-04 15:33:47 +00:00
|
|
|
g_idle_remove_by_data(sim);
|
2012-04-18 12:39:48 +00:00
|
|
|
/* Cleanup potential SIM state polling */
|
|
|
|
at_util_sim_state_query_free(sd->sim_state_query);
|
|
|
|
|
2009-11-11 21:58:45 +00:00
|
|
|
ofono_sim_set_data(sim, NULL);
|
|
|
|
|
2010-08-12 21:40:40 +00:00
|
|
|
g_at_chat_unref(sd->chat);
|
2009-11-11 21:58:45 +00:00
|
|
|
g_free(sd);
|
2009-08-18 22:05:50 +00:00
|
|
|
}
|
|
|
|
|
2019-04-02 06:24:02 +00:00
|
|
|
static void xcmscsc_cb(gboolean ok, GAtResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
struct cb_data *cbd = user_data;
|
|
|
|
ofono_sim_set_active_card_slot_cb_t cb = cbd->cb;
|
|
|
|
struct ofono_error error;
|
|
|
|
|
|
|
|
decode_at_error(&error, g_at_result_final_response(result));
|
|
|
|
|
|
|
|
if (cb)
|
|
|
|
cb(&error, cbd->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void at_set_active_card_slot(struct ofono_sim *sim, unsigned int index,
|
|
|
|
ofono_sim_set_active_card_slot_cb_t cb, void *data)
|
|
|
|
{
|
|
|
|
struct sim_data *sd = ofono_sim_get_data(sim);
|
|
|
|
struct cb_data *cbd = cb_data_new(cb, data);
|
|
|
|
char cmd[43];
|
|
|
|
|
|
|
|
if (sd->vendor != OFONO_VENDOR_XMM) {
|
|
|
|
struct ofono_error error;
|
|
|
|
error.type = OFONO_ERROR_TYPE_CME;
|
|
|
|
error.error = 4;
|
|
|
|
|
|
|
|
cb(&error, data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable single SIM mode for indicated card slot id */
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+XCMSCSC=1,0,%u,1", index);
|
|
|
|
|
|
|
|
if (g_at_chat_send(sd->chat, cmd, none_prefix, xcmscsc_cb,
|
|
|
|
cbd, g_free) > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_free(cbd);
|
|
|
|
CALLBACK_WITH_FAILURE(cb, data);
|
|
|
|
}
|
|
|
|
|
2018-10-17 13:36:10 +00:00
|
|
|
static const struct ofono_sim_driver driver = {
|
2009-09-02 03:33:05 +00:00
|
|
|
.name = "atmodem",
|
2009-08-18 22:05:50 +00:00
|
|
|
.probe = at_sim_probe,
|
|
|
|
.remove = at_sim_remove,
|
2009-06-18 03:44:44 +00:00
|
|
|
.read_file_info = at_sim_read_info,
|
|
|
|
.read_file_transparent = at_sim_read_binary,
|
|
|
|
.read_file_linear = at_sim_read_record,
|
2009-06-21 01:30:14 +00:00
|
|
|
.read_file_cyclic = at_sim_read_record,
|
2009-06-18 03:44:44 +00:00
|
|
|
.write_file_transparent = at_sim_update_binary,
|
|
|
|
.write_file_linear = at_sim_update_record,
|
2009-06-21 01:30:14 +00:00
|
|
|
.write_file_cyclic = at_sim_update_cyclic,
|
2009-05-22 11:58:49 +00:00
|
|
|
.read_imsi = at_read_imsi,
|
2009-09-17 20:43:22 +00:00
|
|
|
.query_passwd_state = at_pin_query,
|
2011-01-10 21:59:53 +00:00
|
|
|
.query_pin_retries = at_pin_retries_query,
|
2009-09-17 20:43:22 +00:00
|
|
|
.send_passwd = at_pin_send,
|
|
|
|
.reset_passwd = at_pin_send_puk,
|
|
|
|
.lock = at_pin_enable,
|
|
|
|
.change_passwd = at_change_passwd,
|
2016-04-27 16:04:43 +00:00
|
|
|
.query_facility_lock = at_query_clck,
|
2017-11-03 23:30:49 +00:00
|
|
|
.list_apps = at_discover_apps,
|
|
|
|
.open_channel = at_open_channel,
|
|
|
|
.close_channel = at_close_channel,
|
|
|
|
.session_read_binary = at_session_read_binary,
|
|
|
|
.session_read_record = at_session_read_record,
|
|
|
|
.session_read_info = at_session_read_info,
|
2019-04-02 06:24:02 +00:00
|
|
|
.logical_access = at_logical_access,
|
|
|
|
.set_active_card_slot = at_set_active_card_slot
|
2009-05-22 11:58:49 +00:00
|
|
|
};
|
|
|
|
|
2018-10-17 13:36:10 +00:00
|
|
|
static const struct ofono_sim_driver driver_noef = {
|
2012-01-11 16:28:33 +00:00
|
|
|
.name = "atmodem-noef",
|
|
|
|
.probe = at_sim_probe,
|
|
|
|
.remove = at_sim_remove,
|
|
|
|
.read_imsi = at_read_imsi,
|
|
|
|
.query_passwd_state = at_pin_query,
|
|
|
|
.query_pin_retries = at_pin_retries_query,
|
|
|
|
.send_passwd = at_pin_send,
|
|
|
|
.reset_passwd = at_pin_send_puk,
|
|
|
|
.lock = at_pin_enable,
|
|
|
|
.change_passwd = at_change_passwd,
|
2016-04-27 16:04:43 +00:00
|
|
|
.query_facility_lock = at_query_clck,
|
2012-01-11 16:28:33 +00:00
|
|
|
};
|
|
|
|
|
2011-01-12 10:52:15 +00:00
|
|
|
void at_sim_init(void)
|
2009-05-22 11:58:49 +00:00
|
|
|
{
|
2009-08-18 22:05:50 +00:00
|
|
|
ofono_sim_driver_register(&driver);
|
2012-01-11 16:28:33 +00:00
|
|
|
ofono_sim_driver_register(&driver_noef);
|
2009-05-22 11:58:49 +00:00
|
|
|
}
|
|
|
|
|
2011-01-12 10:52:15 +00:00
|
|
|
void at_sim_exit(void)
|
2009-05-22 11:58:49 +00:00
|
|
|
{
|
2009-08-18 22:05:50 +00:00
|
|
|
ofono_sim_driver_unregister(&driver);
|
2012-01-11 16:28:33 +00:00
|
|
|
ofono_sim_driver_unregister(&driver_noef);
|
2009-05-22 11:58:49 +00:00
|
|
|
}
|