aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile.am5
-rw-r--r--tools/common/modem.c438
-rw-r--r--tools/common/modem.h62
-rw-r--r--tools/ipc-imei.c227
4 files changed, 732 insertions, 0 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 41e5441..ecf4047 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -6,6 +6,7 @@ AM_CFLAGS = \
bin_PROGRAMS = \
ipc-modem \
+ ipc-imei \
ipc-test \
nv_data-imei \
nv_data-md5 \
@@ -23,6 +24,10 @@ ipc_modem_SOURCES = ipc-modem.c
ipc_modem_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la
ipc_modem_LDFLAGS = -lpthread
+ipc_imei_SOURCES = ipc-imei.c common/modem.c
+ipc_imei_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la
+ipc_imei_LDFLAGS =
+
ipc_test_SOURCES = ipc-test.c
ipc_test_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la
ipc_test_LDFLAGS =
diff --git a/tools/common/modem.c b/tools/common/modem.c
new file mode 100644
index 0000000..9644ecb
--- /dev/null
+++ b/tools/common/modem.c
@@ -0,0 +1,438 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2014 Paul Kocialkowsk <contact@paulk.fr>
+ * Copyright (C) 2021 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
+ *
+ * libsamsung-ipc is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libsamsung-ipc 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 libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h> /* system("dmesg") */
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "modem.h"
+
+int seq;
+
+static enum modem_state current_state = MODEM_STATE_LPM;
+
+static enum modem_callback_state callback_state = MODEM_CALLBACK_STATE_UTILS;
+
+/* TODO: check authorship from git log in samsung-ipc/ipc.c */
+void common_modem_log(struct ipc_client *client, const char *message, ...)
+{
+ char buffer[4096];
+ va_list args;
+
+ if (client == NULL || message == NULL)
+ return;
+
+ va_start(args, message);
+ vsnprintf((char *) &buffer, sizeof(buffer), message, args);
+ /* TODO: Fixme: the log handler is from the app!!! */
+ modem_log_handler("mdm", buffer); /* No access to ipc_client) */
+ va_end(args);
+}
+
+/* Taken from tools/ipc-modem.c */
+int seq_get(void)
+{
+ if (seq == 0xff)
+ seq = 0x00;
+
+ seq++;
+
+ return seq;
+}
+
+static int modem_response_sec(struct ipc_client *client,
+ struct ipc_message *resp,
+ enum modem_state new_state)
+{
+ struct ipc_sec_pin_status_response_data *sim_status;
+ unsigned char type;
+
+ if (!client)
+ return 0;
+
+
+ switch (resp->command) {
+ case IPC_SEC_PIN_STATUS:
+ sim_status =
+ (struct ipc_sec_pin_status_response_data *)resp->data;
+
+ switch (sim_status->status) {
+ case IPC_SEC_PIN_STATUS_CARD_NOT_PRESENT:
+ common_modem_log(client, "[I] SIM card not found\n");
+
+ if (new_state == MODEM_STATE_SIM_OK)
+ return -ENODEV; /* SIM not found but required */
+ else
+ return 0; /* Modem init done */
+ case IPC_SEC_PIN_STATUS_LOCK_SC:
+ /* TODO */
+ switch (sim_status->facility_lock) {
+ case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ:
+ common_modem_log(client,
+ "[I] "
+ "The card is locked with the PIN1\n"
+ "TODO: implement unlocking the card"
+ );
+ break;
+ case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ:
+ common_modem_log(client,
+ "[I] "
+ "The card is locked with the PUK\n"
+ "TODO: implement unlocking the card"
+ );
+ break;
+ case IPC_SEC_FACILITY_LOCK_TYPE_SC_CARD_BLOCKED:
+ common_modem_log(client, "[I] "
+ "The SIM Card is blocked:\n"
+ "Unless you have a "
+ "programable card with the "
+ "ADM1 pin you might need to "
+ "contact your operator.\n");
+ break;
+ }
+
+ /* Only fail if the SIM card is required */
+ if (new_state == MODEM_STATE_SIM_OK)
+ return -EACCES;
+
+ break;
+ case IPC_SEC_PIN_STATUS_INIT_COMPLETE:
+ common_modem_log(client, "[3] SIM init complete\n");
+ if (current_state == MODEM_STATE_NORMAL) {
+ current_state = MODEM_STATE_SIM_OK;
+ /* In any case we're done when the SIM is
+ * ready
+ */
+ return 0;
+ }
+ break;
+ case IPC_SEC_PIN_STATUS_PB_INIT_COMPLETE:
+ common_modem_log(client,
+ "[I] SIM Phone Book init complete\n");
+ break;
+ }
+ break;
+ case IPC_SEC_SIM_ICC_TYPE:
+ type = *((char *) resp->data);
+ switch (type) {
+ case IPC_SEC_SIM_CARD_TYPE_UNKNOWN:
+ common_modem_log(client,
+ "[I] No SIM card type: unknown (absent?)"
+ "\n");
+
+ /* Only fail if the SIM card is required */
+ if (new_state == MODEM_STATE_SIM_OK)
+ return -ENODEV;
+ break;
+ case IPC_SEC_SIM_CARD_TYPE_SIM:
+ case IPC_SEC_SIM_CARD_TYPE_USIM:
+ common_modem_log(client, "[I] SIM card found\n");
+ break;
+ }
+ break;
+ }
+
+ return -EAGAIN;
+}
+
+int modem_stop(struct ipc_client *client)
+{
+ int rc;
+
+ common_modem_log(client, "%s: ipc_client_close", __FUNCTION__);
+ rc = ipc_client_close(client);
+ if (rc < 0) {
+ common_modem_log(client, "Closing failed: error %d\n", rc);
+ return rc;
+ }
+
+ common_modem_log(client, "%s: ipc_client_power_off", __FUNCTION__);
+ rc = ipc_client_power_off(client);
+ if (rc < 0) {
+ common_modem_log(client, "Powering on failed: error %d\n", rc);
+ return rc;
+ }
+
+ common_modem_log(client, "%s: Modem stopped", __FUNCTION__);
+
+ return 0;
+}
+
+/* TODO: share the code */
+static int modem_response_pwr(struct ipc_client *client,
+ struct ipc_message *resp,
+ __attribute__((unused)) enum modem_state new_state)
+{
+ int state_n;
+
+ if (!client)
+ return 0;
+
+ switch (resp->command) {
+ case IPC_PWR_PHONE_PWR_UP:
+ common_modem_log(client, "[2] Phone is powered up (LPM)!\n");
+ current_state = MODEM_STATE_LPM;
+ break;
+
+ case IPC_PWR_PHONE_STATE:
+ state_n = *((int *)resp->data);
+#if 0
+ switch (state_n) {
+ /* FIXME: Broken */
+ case IPC_PWR_PHONE_STATE_NORMAL:
+ common_modem_log(client, "Power state is now: NORMAL\n");
+ break;
+ case IPC_PWR_PHONE_STATE_LPM:
+ common_modem_log(client, "Power state is now: "
+ "LPM (Low Power Mode)?\n");
+ break;
+ }
+#else
+ common_modem_log(client, "Power state is now: 0x%x\n",
+ current_state);
+#endif
+ current_state = state_n;
+ break;
+
+ }
+
+ return 0;
+}
+
+/*
+ * -EAGAIN is returned when modem_response_handle handled a
+ * response and another value < 0 when there were errors.
+ * It returns 0 when it's done initializing the modem, so
+ * application writers can more easily run the code they
+ * whish at this point and handle the responses the way they
+ * whish.
+ */
+static int modem_start_response_handle(struct ipc_client *client,
+ struct ipc_message *resp,
+ enum modem_state new_state)
+{
+ int rc;
+
+ if (!client)
+ return 0;
+
+ switch (IPC_GROUP(resp->command)) {
+ case IPC_GROUP_PWR:
+ rc = modem_response_pwr(client, resp, new_state);
+ if (rc == 0)
+ return -EAGAIN;
+ return rc;
+ case IPC_GROUP_SEC:
+ return modem_response_sec(client, resp, new_state);
+ default:
+ common_modem_log(client, "Unhandled %s command",
+ ipc_group_string(IPC_GROUP(resp->command)));
+ return -EAGAIN;
+ }
+}
+
+int register_app_modem_response_handler(
+ struct ipc_client *client,
+ struct app_modem_response_handler *handler,
+ int (*handler_func)(struct ipc_client *client, struct ipc_message *resp, void *handler_data),
+ void *handler_func_data)
+{
+ if (!client)
+ return 0;
+
+ if (!handler)
+ return 0;
+
+ handler->handler = handler_func;
+ handler->data = handler_func_data;
+
+ return 0;
+}
+
+static int modem_response_handle(struct ipc_client *client,
+ struct ipc_message *resp,
+ enum modem_state new_state,
+ struct app_modem_response_handler *handler)
+{
+ int rc;
+
+ if (!client)
+ return 0;
+
+
+ if (callback_state == MODEM_CALLBACK_STATE_UTILS)
+ rc = modem_start_response_handle(client, resp, new_state);
+ else
+ rc = handler->handler(client, resp, handler->data);
+
+ return rc;
+}
+
+/* TODO: share modem_read_loop and fix it elsewhere too */
+/* TODO: new_state is not needed for the application */
+int modem_read_loop(struct ipc_client *client,
+ enum modem_state new_state,
+ struct app_modem_response_handler *handler)
+{
+ struct ipc_message resp;
+ int rc;
+
+ common_modem_log(client, "ENTER %s", __func__);
+
+ if (!client) {
+ common_modem_log(client, "%s: ipc_client is NULL", __func__);
+ return 0;
+ }
+
+ memset(&resp, 0, sizeof(resp));
+
+ while (1) {
+ usleep(3000);
+
+ common_modem_log(client, "%s: Starting ipc_client_poll", __func__);
+ rc = ipc_client_poll(client, NULL, NULL);
+
+ common_modem_log(client, "%s: ipc_client_poll: %d", __func__, rc);
+ if (rc < 0)
+ continue;
+
+ common_modem_log(client, "%s: ipc_client_poll done", __func__);
+
+ rc = ipc_client_recv(client, &resp);
+ if (rc < 0) {
+ if (resp.data != NULL)
+ free(resp.data);
+ return rc;
+ }
+
+ common_modem_log(client, "%s: Received response", __func__);
+
+ rc = modem_response_handle(client, &resp, new_state, handler);
+
+ common_modem_log(client, "modem_response_handle: rc=%d", rc);
+
+ if (resp.data != NULL)
+ free(resp.data);
+
+ if (rc == -EAGAIN) {
+ continue;
+ } else if (rc < 0) {
+ return rc;
+ } else if (rc == 0) {
+ /* The callback exited normally because it reached
+ * new_state.
+ * It's now to the app callback to take over
+ */
+ if (callback_state == MODEM_CALLBACK_STATE_UTILS)
+ callback_state = MODEM_CALLBACK_STATE_APP;
+ return 0;
+ }
+ }
+}
+
+static int _modem_start(struct ipc_client *client)
+{
+ int rc;
+
+ if (!client)
+ return 0;
+
+ rc = ipc_client_data_create(client);
+ if (rc < 0) {
+ common_modem_log(client, "Creating data failed: error %d\n", rc);
+ return rc;
+ }
+
+ rc = ipc_client_boot(client);
+ if (rc < 0) {
+ common_modem_log(client, "Booting failed: error %d\n", rc);
+ return rc;
+ }
+
+ rc = ipc_client_power_on(client);
+ if (rc < 0) {
+ common_modem_log(client, "Powering on failed: error %d\n", rc);
+ return rc;
+ }
+
+ rc = ipc_client_open(client);
+ if (rc < 0) {
+ common_modem_log(client, "ipc_client_open failed: error %d\n",
+ rc);
+ return rc;
+ }
+
+ rc = ipc_client_power_on(client);
+ if (rc < 0) {
+ common_modem_log(client,
+ "ipc_client_power_on failed: error %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+const char *modem_state_to_string(enum modem_state state)
+{
+ static char group_string[5] = { 0 };
+
+ switch (state) {
+ case MODEM_STATE_LPM:
+ return "MODEM_STATE_LPM";
+ case MODEM_STATE_NORMAL:
+ return "MODEM_STATE_NORMAL";
+ case MODEM_STATE_SIM_OK:
+ return "MODEM_STATE_SIM_OK";
+ default:
+ snprintf((char *) &group_string, sizeof(group_string), "0x%02x",
+ (unsigned int)group_string);
+ return group_string;
+ }
+};
+
+int modem_start(struct ipc_client *client, enum modem_state new_state,
+ struct app_modem_response_handler *handler)
+{
+ int rc;
+
+ if (!client)
+ return 0;
+
+ common_modem_log(client, "%s: requested state %s: %d",
+ __FUNCTION__,
+ modem_state_to_string(new_state),
+ new_state);
+
+ rc = _modem_start(client);
+ if (rc < 0) {
+ ipc_client_destroy(client);
+ return 1;
+ }
+
+ common_modem_log(client, "%s: modem_start done", __func__);
+
+ return 0;
+}
diff --git a/tools/common/modem.h b/tools/common/modem.h
new file mode 100644
index 0000000..0075c3b
--- /dev/null
+++ b/tools/common/modem.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2014 Paul Kocialkowsk <contact@paulk.fr>
+ * Copyright (C) 2021 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
+ *
+ * libsamsung-ipc is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libsamsung-ipc 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 libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TOOLS_UTILS_H
+#define TOOLS_UTILS_H
+
+#include <stddef.h> /*fixme */
+#include <samsung-ipc.h>
+
+#define BIT(n) (1<<n)
+
+int seq_get(void);
+
+struct app_modem_response_handler {
+ int (*handler)(struct ipc_client *client, struct ipc_message *resp, void *handler_data);
+ void *data;
+};
+
+enum modem_state {
+ MODEM_STATE_LPM = BIT(0),
+ MODEM_STATE_NORMAL = BIT(1),
+ MODEM_STATE_SIM_OK = BIT(2),
+};
+
+enum modem_callback_state {
+ MODEM_CALLBACK_STATE_UTILS = BIT(0),
+ MODEM_CALLBACK_STATE_APP = BIT(1),
+};
+
+int modem_start(struct ipc_client *client, enum modem_state state,
+ struct app_modem_response_handler *handler);
+int modem_stop(struct ipc_client *client);
+
+int modem_read_loop(struct ipc_client *client,
+ enum modem_state new_state,
+ struct app_modem_response_handler *handler);
+
+int register_app_modem_response_handler(
+ struct ipc_client *client,
+ struct app_modem_response_handler *handler,
+ int (*handler_func)(struct ipc_client *client, struct ipc_message *resp, void *handler_data),
+ void *handler_func_data);
+
+
+#endif /* TOOLS_UTILS_H */
diff --git a/tools/ipc-imei.c b/tools/ipc-imei.c
new file mode 100644
index 0000000..76fcead
--- /dev/null
+++ b/tools/ipc-imei.c
@@ -0,0 +1,227 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2014 Paul Kocialkowsk <contact@paulk.fr>
+ * Copyright (C) 2021 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
+ *
+ * libsamsung-ipc is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libsamsung-ipc 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 libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "common/modem.h"
+
+void modem_log_handler(void *user_data, const char *msg)
+{
+ int i, l;
+ char *message;
+
+ message = strdup(msg);
+ l = strlen(message);
+
+ if (l > 1) {
+ for (i = l ; i > 0 ; i--) {
+ if (message[i] == '\n')
+ message[i] = 0;
+ else if (message[i] != 0)
+ break;
+ }
+ if (user_data == NULL) {
+ printf("[ ipc ] %s\n", message);
+ }
+ if (user_data != NULL) {
+ printf("[ %s ] %s\n", user_data, message);
+ }
+ }
+
+ free(message);
+}
+
+static void usage(char* progname)
+{
+ printf("Usage: %s\n", progname);
+}
+
+/* TODO: check authorship from git log in samsung-ipc/ipc.c */
+void ipc_imei_log(struct ipc_client *client, const char *message, ...)
+{
+ char buffer[4096];
+ va_list args;
+
+ if (client == NULL || message == NULL)
+ return;
+
+ va_start(args, message);
+ vsnprintf((char *) &buffer, sizeof(buffer), message, args);
+ modem_log_handler("ipc-imei", buffer); /* No access to ipc_client) */
+ va_end(args);
+}
+
+int ipc_imei_request_imei(struct ipc_client *client)
+{
+ struct ipc_misc_me_sn_request_data request_data;
+ int rc;
+
+ if (!client)
+ return 0;
+
+ ipc_imei_log(client, "ENTER %s\n", __func__);
+
+ request_data.type = IPC_MISC_ME_SN_SERIAL_NUM;
+
+ rc = ipc_client_send(client, seq_get(), IPC_MISC_ME_SN, IPC_TYPE_GET,
+ (void *) &request_data, sizeof(request_data));
+ if (rc < 0)
+ ipc_imei_log(client, "ipc_client_send failed with error %d\n",
+ rc);
+
+ ipc_imei_log(client, "EXIT %s\n", __func__);
+ return rc;
+}
+
+int ipc_imei_parse_imei_response(struct ipc_client *client,
+ struct ipc_message *message,
+ __attribute__((unused)) void* app_data)
+{
+ struct ipc_misc_me_sn_response_data *data;
+ char *imei;
+
+ if (!client)
+ return 0;
+
+ if (message == NULL) {
+ ipc_imei_log(client,
+ "%s: ipc_message is null\n", __FUNCTION__);
+ return -EAGAIN;
+ }
+
+ data = (struct ipc_misc_me_sn_response_data *) message->data;
+
+ if (data->type != IPC_MISC_ME_SN_SERIAL_NUM)
+ return -EAGAIN;
+
+ imei = ipc_misc_me_sn_extract(data);
+
+ if (strlen (imei) > 15 * sizeof(char))
+ imei[15] = '\0';
+
+ ipc_imei_log(client, "%s: found IMEI '%s'\n", __FUNCTION__, imei);
+
+ free(imei);
+
+ /* Exit */
+ return 0;
+}
+
+static int ipc_imei_response_handle(struct ipc_client *client,
+ struct ipc_message *resp,
+ void *data)
+{
+ int rc;
+
+ if (!client)
+ return 0;
+
+ switch (IPC_GROUP(resp->command)) {
+ case IPC_GROUP_MISC:
+ rc = ipc_imei_parse_imei_response(client, resp, data);
+ return rc;
+ default:
+ ipc_imei_log(client, "Unhandled %s command",
+ ipc_group_string(IPC_GROUP(resp->command)));
+ return -EAGAIN;
+ }
+}
+
+
+int main(int argc, char** argv)
+{
+ struct ipc_client *client = NULL;
+ struct app_modem_response_handler handler;
+
+ int rc;
+
+ if (argc == 0) {
+ exit(EX_USAGE);
+ } else if (argc != 1) {
+ usage(argv[0]);
+ exit(EX_USAGE);
+ }
+
+ client = ipc_client_create(IPC_CLIENT_TYPE_FMT);
+ if (client == NULL) {
+ printf("Creating client failed\n");
+ return 1;
+ }
+
+ rc = ipc_client_log_callback_register(client, modem_log_handler, NULL);
+ if (rc < 0) {
+ printf("ipc_imei_log_callback_registerma failed:"
+ " error %d\n", rc);
+ return 1;
+ }
+ ipc_imei_log(client, "ipc_client_log_callback_register done");
+
+ /* register new callback that would take over after modem_start is
+ * done
+ */
+ rc = register_app_modem_response_handler(client, &handler,
+ ipc_imei_response_handle,
+ NULL);
+ if (rc < 0) {
+ ipc_imei_log(client,
+ "register_app_modem_response_handler failed: "
+ "error %d\n",
+ rc);
+ return 1;
+ }
+
+ ipc_imei_log(client, "Starting modem");
+
+ rc = modem_start(client, MODEM_STATE_LPM, &handler);
+ if (rc < 0) {
+ ipc_imei_log(client, "modem_start failed: error %d\n", rc);
+ return 1;
+ }
+
+ ipc_imei_log(client, "modem_start done\n");
+
+ ipc_imei_request_imei(client);
+
+ //ipc_imei_log(client, "ipc_imei_request_imei done\n");
+
+ /* TODO: MODEM_STATE_LPM is not needed here */
+ rc = modem_read_loop(client, MODEM_STATE_LPM, &handler);
+ if (rc < 0)
+ ipc_imei_log(client,
+ "ipc-imei: modem_read_loop failed: error %d\n",
+ rc);
+
+ ipc_imei_log(client, "ipc-imei: modem_read_loop done");
+
+ rc = modem_stop(client);
+ if (rc < 0) {
+ ipc_imei_log(client, "modem_stop failed: error %d\n", rc);
+ return 1;
+ }
+
+ return 0;
+}