aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.checkpatch.conf7
-rw-r--r--.gitignore42
-rw-r--r--Android.mk139
-rw-r--r--CONTRIBUTING2
-rw-r--r--MAINTAINERS2
-rw-r--r--Makefile.am84
-rw-r--r--README3
-rw-r--r--android_versions.mk39
-rw-r--r--configure.ac169
-rw-r--r--include/samsung-ipc.h13
-rw-r--r--samsung-ipc/Makefile.am49
-rw-r--r--samsung-ipc/devices/Makefile.am25
-rw-r--r--samsung-ipc/devices/aries/aries.c7
-rw-r--r--samsung-ipc/devices/crespo/crespo.c19
-rw-r--r--samsung-ipc/devices/galaxys2/galaxys2.c88
-rw-r--r--samsung-ipc/devices/herolte/herolte.c610
-rw-r--r--samsung-ipc/devices/herolte/herolte.h35
-rw-r--r--samsung-ipc/devices/i9300/i9300.c42
-rw-r--r--samsung-ipc/devices/ipc_devices.c10
-rw-r--r--samsung-ipc/devices/ipc_devices.h9
-rw-r--r--samsung-ipc/devices/n5100/n5100.c42
-rw-r--r--samsung-ipc/devices/n7100/n7100.c42
-rw-r--r--samsung-ipc/gprs.c6
-rw-r--r--samsung-ipc/ipc_strings.c409
-rw-r--r--samsung-ipc/ipc_utils.c316
-rw-r--r--samsung-ipc/modems/Makefile.am15
-rw-r--r--samsung-ipc/modems/xmm626/xmm626_kernel_smdk4412.c16
-rw-r--r--samsung-ipc/partitions/Makefile.am6
-rw-r--r--samsung-ipc/partitions/android/android.c118
-rw-r--r--samsung-ipc/partitions/android/android.h29
-rw-r--r--samsung-ipc/partitions/toc/toc.c44
-rw-r--r--samsung-ipc/partitions/toc/toc.h41
-rw-r--r--samsung-ipc/rfs.c26
-rw-r--r--samsung-ipc/tests/Makefile.am39
-rwxr-xr-xsamsung-ipc/tests/libsamsung-ipc-test.py66
-rw-r--r--samsung-ipc/tests/main.c157
-rw-r--r--samsung-ipc/tests/partitions/android.c212
-rw-r--r--samsung-ipc/tests/partitions/android.h25
-rw-r--r--samsung-ipc/utils.c110
-rw-r--r--scripts/PKGBUILD55
-rw-r--r--scripts/guix.scm336
-rw-r--r--scripts/manifest.scm59
-rwxr-xr-xscripts/rebase-build-check-android.sh102
-rwxr-xr-xscripts/rebase-build-check-gnu-linux.sh81
-rwxr-xr-xstrict-cflags.sh35
-rw-r--r--tools/Makefile.am33
-rw-r--r--tools/https-send-sms.c205
-rw-r--r--tools/include/glibc/sysexits.h114
-rw-r--r--tools/ipc-modem.c590
-rw-r--r--tools/ipc-modem/Makefile.am28
-rw-r--r--tools/ipc-modem/ipc-modem-log.c84
-rw-r--r--tools/ipc-modem/ipc-modem-log.h41
-rw-r--r--tools/ipc-modem/ipc-modem.c781
-rw-r--r--tools/ipc-modem/ipc-modem.h51
-rwxr-xr-xtools/ipc-modem/tests/ipc-modem.py145
-rw-r--r--tools/nv_data-imei.c1073
-rw-r--r--tools/nv_data-imei.h82
-rw-r--r--tools/nv_data-md5.c3
-rwxr-xr-xtools/tests/nv_data-imei.py144
-rwxr-xr-xtools/tests/nv_data-md5.py88
60 files changed, 6158 insertions, 1085 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf
index 32625b5..8ea7ed1 100644
--- a/.checkpatch.conf
+++ b/.checkpatch.conf
@@ -14,3 +14,10 @@
--ignore PREFER_PRINTF
--ignore PREFER_SCANF
--ignore PREFER_SECTION
+
+# We currently have only one maintainer. It would be great to have more
+# co-maintainers, however until then we don't need to check for file patch
+# changes. Feel free to step in if you want to maintain the devices you added,
+# especially if it's a device that is not supported by Replicant or that
+# Replicant doesn't want to support for some reason.
+--ignore FILE_PATH_CHANGES
diff --git a/.gitignore b/.gitignore
index 900dc6b..9bfa7dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,42 @@
+# Tests
+/samsung-ipc/tests/libsamsung-ipc-test
+/samsung-ipc/tests/libsamsung-ipc-test.log
+/samsung-ipc/tests/libsamsung-ipc-test.trs
+/samsung-ipc/tests/test-suite.log
+/test-driver
+/tools/ipc-modem.log
+/tools/ipc-modem/tests/ipc-modem.log
+/tools/ipc-modem/tests/ipc-modem.trs
+/tools/ipc-modem/test-suite.log
+/tools/ipc-modem.trs
+/tools/nv_data-imei.log
+/tools/nv_data-imei.trs
+/tools/nv_data-md5.log
+/tools/nv_data-md5.trs
+/tools/tests/nv_data-imei.log
+/tools/tests/nv_data-imei.trs
+/tools/tests/nv_data-md5.log
+/tools/tests/nv_data-md5.trs
+/tools/test-suite.log
+valgrind.*.log
+
+# scripts/PKGBUILD
+/scripts/libsamsung-ipc-git-*.pkg.tar.xz
+/scripts/libsamsung-ipc-git-debug-*.pkg.tar.xz
+/scripts/pkg/**
+/scripts/src/**
+
+# Tools
+/tools/https-send-sms
+/tools/ipc-modem/ipc-modem
+/tools/ipc-test
+/tools/nv_data-imei
+/tools/nv_data-md5
+
+# Text editors
+\#*\#
+*~
+
Makefile.in
Makefile
*.o
@@ -29,6 +68,3 @@ INSTALL
*.pc
build
core
-ipc-modem
-ipc-test
-nv_data-md5
diff --git a/Android.mk b/Android.mk
index b1aabbd..b51f9ba 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,65 +17,73 @@
LOCAL_PATH := $(call my-dir)
+ifneq (,$(filter galaxysmtd galaxytab,$(TARGET_DEVICE)))
+ ipc_device_name := aries
+endif
+
ifneq (,$(filter crespo,$(TARGET_DEVICE)))
ipc_device_name := crespo
endif
-ifneq (,$(filter galaxysmtd galaxytab,$(TARGET_DEVICE)))
- ipc_device_name := aries
+ifneq (,$(filter herolte,$(TARGET_DEVICE)))
+ ipc_device_name := herolte
endif
ifneq (,$(filter i9100 galaxys2 n7000,$(TARGET_DEVICE)))
ipc_device_name := galaxys2
endif
-ifneq (,$(filter maguro,$(TARGET_DEVICE)))
- ipc_device_name := maguro
+ifneq (,$(filter i9300,$(TARGET_DEVICE)))
+ ipc_device_name := i9300
endif
-ifneq (,$(filter p5100 p3100 espresso3g,$(TARGET_DEVICE)))
- ipc_device_name := piranha
+ifneq (,$(filter maguro,$(TARGET_DEVICE)))
+ ipc_device_name := maguro
endif
-ifneq (,$(filter i9300,$(TARGET_DEVICE)))
- ipc_device_name := i9300
+ifneq (,$(filter n5100,$(TARGET_DEVICE)))
+ ipc_device_name := n5100
endif
ifneq (,$(filter n7100,$(TARGET_DEVICE)))
ipc_device_name := n7100
endif
-ifneq (,$(filter n5100,$(TARGET_DEVICE)))
- ipc_device_name := n5100
+ifneq (,$(filter p5100 p3100 espresso3g,$(TARGET_DEVICE)))
+ ipc_device_name := piranha
endif
libsamsung_ipc_local_src_files := \
+ samsung-ipc/call.c \
+ samsung-ipc/gen.c \
+ samsung-ipc/gprs.c \
samsung-ipc/ipc.c \
+ samsung-ipc/ipc_strings.c \
samsung-ipc/ipc_utils.c \
- samsung-ipc/modems/xmm616/xmm616.c \
- samsung-ipc/modems/xmm626/xmm626.c \
- samsung-ipc/modems/xmm626/xmm626_hsic.c \
- samsung-ipc/modems/xmm626/xmm626_kernel_smdk4412.c \
- samsung-ipc/modems/xmm626/xmm626_mipi.c \
+ samsung-ipc/misc.c \
+ samsung-ipc/net.c \
+ samsung-ipc/rfs.c \
+ samsung-ipc/sec.c \
+ samsung-ipc/sms.c \
+ samsung-ipc/svc.c \
+ samsung-ipc/utils.c \
samsung-ipc/devices/ipc_devices.c \
- samsung-ipc/devices/crespo/crespo.c \
samsung-ipc/devices/aries/aries.c \
+ samsung-ipc/devices/crespo/crespo.c \
samsung-ipc/devices/galaxys2/galaxys2.c \
- samsung-ipc/devices/maguro/maguro.c \
- samsung-ipc/devices/piranha/piranha.c \
+ samsung-ipc/devices/herolte/herolte.c \
samsung-ipc/devices/i9300/i9300.c \
- samsung-ipc/devices/n7100/n7100.c \
+ samsung-ipc/devices/maguro/maguro.c \
samsung-ipc/devices/n5100/n5100.c \
- samsung-ipc/utils.c \
- samsung-ipc/call.c \
- samsung-ipc/sms.c \
- samsung-ipc/sec.c \
- samsung-ipc/net.c \
- samsung-ipc/misc.c \
- samsung-ipc/svc.c \
- samsung-ipc/gprs.c \
- samsung-ipc/rfs.c \
- samsung-ipc/gen.c
+ samsung-ipc/devices/n7100/n7100.c \
+ samsung-ipc/devices/piranha/piranha.c \
+ samsung-ipc/modems/xmm616/xmm616.c \
+ samsung-ipc/modems/xmm626/xmm626.c \
+ samsung-ipc/modems/xmm626/xmm626_hsic.c \
+ samsung-ipc/modems/xmm626/xmm626_kernel_smdk4412.c \
+ samsung-ipc/modems/xmm626/xmm626_mipi.c \
+ samsung-ipc/partitions/android/android.c \
+ samsung-ipc/partitions/toc/toc.c
libsamsung_ipc_local_export_headers := \
include/call.h \
@@ -105,9 +113,11 @@ libsamsung_ipc_local_c_includes := \
$(LOCAL_PATH)/samsung-ipc \
external/openssl/include
-libsamsung_local_cflags := \
- -DIPC_DEVICE_NAME=\"$(ipc_device_name)\" \
- -DDEBUG
+libsamsung_local_cflags := -DDEBUG
+
+ifneq ($(TARGET_DEVICE),)
+libsamsung_local_cflags += -DIPC_DEVICE_NAME=\"$(ipc_device_name)\"
+endif # ifneq ($(TARGET_DEVICE),)
libsamsung_ipc_local_shared_libraries := \
libutils \
@@ -117,6 +127,7 @@ libsamsung_ipc_local_shared_libraries := \
# Static library version of libsamsung-ipc #
############################################
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android_versions.mk
LOCAL_MODULE := libsamsung-ipc
LOCAL_MODULE_TAGS := optional
@@ -135,6 +146,7 @@ include $(BUILD_STATIC_LIBRARY)
# Shared library version of libsamsung-ipc #
############################################
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android_versions.mk
LOCAL_MODULE := libsamsung-ipc
LOCAL_MODULE_TAGS := optional
@@ -149,25 +161,64 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(local_export_c_include_dirs)
include $(BUILD_SHARED_LIBRARY)
+#######################
+# https-send-sms tool #
+#######################
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android_versions.mk
+
+LOCAL_MODULE := https-send-sms
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := tools/https-send-sms.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/tools/include/glibc
+LOCAL_SHARED_LIBRARIES := libcurl
+
+include $(BUILD_EXECUTABLE)
+
##################
# ipc-modem tool #
##################
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android_versions.mk
LOCAL_MODULE := ipc-modem
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := tools/ipc-modem.c
+LOCAL_SRC_FILES := \
+ tools/ipc-modem/ipc-modem.c \
+ tools/ipc-modem/ipc-modem-log.c
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/tools/include/glibc
LOCAL_SHARED_LIBRARIES := libsamsung-ipc
include $(BUILD_EXECUTABLE)
+#########################
+# ipc-modem-static tool #
+#########################
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android_versions.mk
+
+LOCAL_MODULE := ipc-modem-static
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ tools/ipc-modem/ipc-modem.c \
+ tools/ipc-modem/ipc-modem-log.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/tools/include/glibc
+LOCAL_STATIC_LIBRARIES := libsamsung-ipc
+LOCAL_SHARED_LIBRARIES := $(libsamsung_ipc_local_shared_libraries)
+
+include $(BUILD_EXECUTABLE)
+
#################
# ipc-test tool #
#################
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android_versions.mk
LOCAL_MODULE := ipc-test
LOCAL_MODULE_TAGS := optional
@@ -180,17 +231,35 @@ LOCAL_SHARED_LIBRARIES := libsamsung-ipc
include $(BUILD_EXECUTABLE)
+#####################
+# nv_data-imei tool #
+#####################
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android_versions.mk
+
+LOCAL_MODULE := nv_data-imei
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := tools/nv_data-imei.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/tools/include/glibc
+
+LOCAL_SHARED_LIBRARIES := libsamsung-ipc
+
+include $(BUILD_EXECUTABLE)
+
####################
# nv_data-md5 tool #
####################
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android_versions.mk
LOCAL_MODULE := nv_data-md5
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := tools/nv_data-md5.c
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/tools/include/glibc
LOCAL_SHARED_LIBRARIES := libsamsung-ipc
diff --git a/CONTRIBUTING b/CONTRIBUTING
index f032039..8f9e7a1 100644
--- a/CONTRIBUTING
+++ b/CONTRIBUTING
@@ -7,7 +7,7 @@ https://git.replicant.us/replicant/hardware_replicant_libsamsung-ipc
Policies
--------
While at the time of writing, Replicant is the main user of libsamsung-ipc, and
-maintain it, libsamsung-ipc usage is not limited to Replicant nor Android.
+maintains it, libsamsung-ipc usage is not limited to Replicant nor Android.
In the past, libsamsung-ipc was used in the SHR GNU/Linux distribution
as well, with the freesmartphone.org middleware.
diff --git a/MAINTAINERS b/MAINTAINERS
index f3053b8..51088ef 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2,7 +2,7 @@ Maintainers List
----------------
M: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
L: replicant@osuosl.org
-T: git git://git.replicant.us/replicant/external_libsamsung-ipc.git
+T: git https://git.replicant.us/replicant/hardware_replicant_libsamsung-ipc.git
S: Maintained
F: *
F: */
diff --git a/Makefile.am b/Makefile.am
index f036c81..376f52e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,17 +1,27 @@
NULL =
+EXTRA_DIST = $(NULL)
+
SUBDIRS = \
samsung-ipc \
+ samsung-ipc/tests \
include \
tools \
+ tools/ipc-modem \
$(NULL)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = samsung-ipc.pc
-EXTRA_DIST = \
+EXTRA_DIST += \
+ Android.mk \
+ android_versions.mk \
+ CONTRIBUTING \
+ INSTALL \
MAINTAINERS \
samsung-ipc.pc \
+ strict-cflags.sh \
+ tools/include/glibc/sysexits.h \
$(NULL)
MAINTAINERCLEANFILES = \
@@ -20,3 +30,75 @@ MAINTAINERCLEANFILES = \
Makefile.in missing config.h.in \
mkinstalldirs *~ \
$(NULL)
+
+################################################################################
+# Extra checks #
+################################################################################
+
+if WANT_CODE_COVERAGE
+check-local: build-code-coverage check-tarball-builds
+install-data-local: install-code-coverage
+clean-local: clean-code-coverage
+else # WANT_CODE_COVERAGE
+check-local: check-tarball-builds
+endif # WANT_CODE_COVERAGE
+
+# With the next release of libsamsung-ipc, we will also release
+# tarballs.
+#
+# Until now, no automatic testing was done with the libsamsung-ipc
+# tarballs (all tests were done with the libsamsung-ipc git
+# repository).
+#
+# We also need to verify that everything also builds and that the
+# tests also work with tarballs. This can spot mistakes where people
+# add new files that are not automatically picked up by automake and
+# forget to add these files to EXTRA_DIST.
+#
+# This test runs only from git because it is not necessary with a
+# tarball build. If we wanted to run it anyway we would end up in an
+# infinite recursion as a given test from a tarball would then spawn
+# another build and test from a tarball which would then spawn again
+# another build and test.
+check-tarball-builds: dist
+ if [ -d $(srcdir)/.git ] ; then \
+ BUILD_TMPDIR=`mktemp -d` && \
+ echo $$BUILD_TMPDIR && \
+ mkdir $$BUILD_TMPDIR/build $$BUILD_TMPDIR/destdir && \
+ tar xf $(srcdir)/libsamsung-ipc-$(VERSION).tar.xz \
+ -C $$BUILD_TMPDIR && \
+ cd $$BUILD_TMPDIR/build && \
+ ../libsamsung-ipc-$(VERSION)/configure \
+ $(CONFIGURE_ARGUMENTS) && \
+ make check && \
+ make install DESTDIR=`realpath $$BUILD_TMPDIR/destdir` && \
+ rm -rf $$BUILD_TMPDIR ; \
+ fi
+
+#################
+# Code coverage #
+#################
+if WANT_CODE_COVERAGE
+
+CODE_COVERAGE_DIR = lcov
+
+EXTRA_DIST += $(CODE_COVERAGE_DIR)
+
+build-code-coverage:
+ lcov \
+ --capture \
+ --compat-libtool \
+ --directory . \
+ --output-file libsamsung-ipc.info
+ genhtml -o $(CODE_COVERAGE_DIR) libsamsung-ipc.info
+
+install-code-coverage: check
+ install -d $(DESTDIR)/$(datadir)/libsamsung-ipc/$(CODE_COVERAGE_DIR)/
+ find $(srcdir)/$(CODE_COVERAGE_DIR) -type f | \
+ xargs -I src install -D src \
+ $(DESTDIR)/$(datadir)/libsamsung-ipc/$(CODE_COVERAGE_DIR)/
+
+clean-code-coverage:
+ rm -rf $(CODE_COVERAGE_DIR)
+
+endif # WANT_CODE_COVERAGE
diff --git a/README b/README
index 71d3331..0fb4bef 100644
--- a/README
+++ b/README
@@ -7,10 +7,11 @@ found in many Samsung devices.
Compilation and installation
============================
-In orderto compile the source code you need the following software packages
+In order to compile the source code you need the following software packages
- GCC compiler
- GNC C library
- OpenSSL >= 1.0.0e
+- curl >= 7.62.0
To configure run
./configure --prefix=/usr
diff --git a/android_versions.mk b/android_versions.mk
new file mode 100644
index 0000000..f34ce57
--- /dev/null
+++ b/android_versions.mk
@@ -0,0 +1,39 @@
+# This file is part of libsamsung-ipc.
+#
+# 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 3 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/>.
+
+# We need to keep the compatibility with older Replicant versions, at least for
+# testing purposes: some of the devices we support in libsamsung-ipc are not
+# supported (yet) in newer Android versions or recent GNU/Linux distributions,
+# and doing tests on older devices might enable us to also understand better
+# the modem protocol and/or the EFS.
+
+# To limit the amount of work, we need to avoid modifying older Android versions
+# to be able to use recent libsamsung-ril and libsamsung-ipc.
+
+# Here's how different Android distributions behave with
+# LOCAL_PROPRIETARY_MODULE := true in libsamsung-ipc's Android.mk:
+# Replicant 4.2: It probably breaks the modem support
+# Replicant 6.0: It break the modem support
+# Replicant 9.0: The modem integration doesn't work because it was not finished
+# Replicant 10.0: The modem integration doesn't work because it was not finished
+# Replicant 11.0: It is required for the modem to work
+
+# Set a default value for build systems like Guix
+PLATFORM_VERSION ?= 7
+ifneq (1,$(filter 1,$(shell echo "$$(( $$(echo $(PLATFORM_VERSION) | sed 's/\..*//g') < 7 ))" )))
+ LOCAL_PROPRIETARY_MODULE := true
+endif
diff --git a/configure.ac b/configure.ac
index 9665a96..501a386 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,20 +1,16 @@
-AC_INIT([libsamsung-ipc], [0.6.0], [replicant@osuosl.org], [libsamsung-ipc])
+AC_INIT([libsamsung-ipc], [0.7.0], [replicant@osuosl.org], [libsamsung-ipc])
+
+AC_SUBST(CONFIGURE_ARGUMENTS)
+: ${CONFIGURE_ARGUMENTS="$@"}
+
AC_CONFIG_SRCDIR([Makefile.am])
AC_CONFIG_HEADERS(config.h)
-AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects])
+AM_INIT_AUTOMAKE([dist-bzip2 dist-xz subdir-objects])
+XZ_OPT=-v9e
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
-AC_PROG_CC
-AM_PROG_CC_C_O
-AC_GNU_SOURCE
-AC_DISABLE_STATIC
-AC_PROG_LIBTOOL
-
-AC_SUBST(CFLAGS)
-AC_SUBST(CPPFLAGS)
-AC_SUBST(LDFLAGS)
-
OPENSSL_REQUIRED=1.0.0e
+LIBCURL_REQUIRED=7.62.0
#------------------------------------------------------------------------------
# pkg-config
@@ -29,38 +25,181 @@ AC_SUBST(OPENSSL_CFLAGS)
AC_SUBST(OPENSSL_LIBS)
#------------------------------------------------------------------------------
+# strict cflags
+AC_SUBST(STRICT_CFLAGS)
+
+#------------------------------------------------------------------------------
+# Static build of test utilities
+AC_SUBST(ALL_STATIC_LDFLAGS)
+
+#------------------------------------------------------------------------------
+# python
+AC_SUBST(PYTHON3)
+AC_CHECK_PROG([PYTHON3], [python3], [python3])
+#------------------------------------------------------------------------------
+# code coverage
+AC_SUBST(CODE_COVERAGE)
+#------------------------------------------------------------------------------
+# valgrind
+AC_SUBST(VALGRIND)
+
+#------------------------------------------------------------------------------
+# ipc device name
+AC_SUBST([IPC_DEVICE_NAME], [all])
+
+#------------------------------------------------------------------------------
+# libcurl
+PKG_CHECK_MODULES(LIBCURL, libcurl >= $LIBCURL_REQUIRED)
+AC_SUBST(LIBCURL_CFLAGS)
+AC_SUBST(LIBCURL_LIBS)
+
+#------------------------------------------------------------------------------
# check for debugging
AC_ARG_ENABLE(debug,
- [ --enable-debug Enable debug build (default=disabled)],
+ [AS_HELP_STRING([--enable-debug], [Enable debug build (default=disabled)])],
[debug=$enableval],
[debug="no"])
AM_CONDITIONAL( [WANT_DEBUG], [test x"$debug" = x"yes"])
#------------------------------------------------------------------------------
+AC_ARG_ENABLE(static-progs,
+ [AS_HELP_STRING([--enable-static-progs],
+ [Build static (test) tools (default=disabled)])],
+ [static_progs=$enableval],
+ [static_progs="no"])
+
+#------------------------------------------------------------------------------
+AC_ARG_ENABLE(strict-cflags,
+ [AS_HELP_STRING([--enable-strict-cflags],
+ [Build with strict cflags (default=disabled)])],
+ [strict_cflags=$enableval],
+ [strict_cflags="no"])
+AM_CONDITIONAL( [WANT_STRICT_CFLAGS], [test x"$strict_cflags" = x"yes"])
+
+#------------------------------------------------------------------------------
+# TODO: GCC has --enable-checking= for extensive runtime checks and one of the
+# available values is valgrind, so it would be a good idea to convert to
+# it for consistency across free software projects.
+AC_ARG_ENABLE(
+ [code-coverage-tests],
+ [AS_HELP_STRING([--enable-code-coverage-tests],
+ [Build with --coverage, -O0 and use lcov from PATH during
+ tests (default=disabled)])],
+ [code_coverage_tests=$enableval],
+ [code_coverage="no"])
+
+AM_CONDITIONAL( [WANT_CODE_COVERAGE], [test x"$code_coverage_tests" = x"yes"])
+
+AS_IF([test x"$code_coverage_tests" = x"yes"],
+ [AC_CHECK_PROG([CODE_COVERAGE], [lcov], [lcov])
+ AS_IF(
+ [test x"$CODE_COVERAGE" = x""],
+ [AC_MSG_ERROR(
+ [code coverage tests are enabled but lcov was not found in PATH ($PATH)])])])
+
+#------------------------------------------------------------------------------
+# TODO: GCC has --enable-checking= for extensive runtime checks and one of the
+# available values is valgrind, so it would be a good idea to convert to
+# it for consistency across free software projects.
+AC_ARG_ENABLE(
+ [valgrind-tests],
+ [AS_HELP_STRING([--enable-valgrind-tests],
+ [Build with -ggdb3, -O0 and use valgrind from PATH during
+ tests (default=disabled)])],
+ [valgrind_tests=$enableval],
+ [valgrind_tests="no"])
+
+AM_CONDITIONAL( [WANT_VALGRIND_CHECKING], [test x"$valgrind_tests" = x"yes"])
+
+AS_IF([test x"$valgrind_tests" = x"yes"],
+ [AC_CHECK_PROG([VALGRIND], [valgrind], [valgrind])
+ AS_IF(
+ [test x"$VALGRIND" = x""],
+ [AC_MSG_ERROR(
+ [valgrind tests are enabled but valgrind was not found in PATH ($PATH)])])])
+#------------------------------------------------------------------------------
+AC_ARG_ENABLE(samsung-ipc-device,
+ [ --enable-samsung-ipc-device=[DEVICE]
+ make libsamsung-ipc assumes that it runs on DEVICE
+ DEVICE={all,aries,crespo,galaxys2,herolte,i9300,maguro,n5100,n7100,piranha} (default=all)],
+ [AS_CASE([$enableval],
+ [aries|crespo|galaxys2|herolte|i9300|maguro|n5100|n7100|piranha],
+ [IPC_DEVICE_NAME=$enableval],
+ [AC_MSG_ERROR([Unknown device $enableval])])],
+ [IPC_DEVICE_NAME="all"])
+
+AM_CONDITIONAL( [WANT_IPC_DEVICE_NAME], [test x"$IPC_DEVICE_NAME" != x"all"])
+#------------------------------------------------------------------------------
+
AC_CONFIG_FILES([
Makefile
samsung-ipc.pc
include/Makefile
samsung-ipc/Makefile
+ samsung-ipc/tests/Makefile
tools/Makefile
+ tools/ipc-modem/Makefile
])
-AC_OUTPUT
+
#------------------------------------------------------------------------------
+AS_IF([test x"$static_progs" = x"yes"],
+ [ALL_STATIC_LDFLAGS=-all-static], [])
+
+AS_IF([test x"$strict_cflags" = x"yes"],
+ [STRICT_CFLAGS=`$srcdir/strict-cflags.sh`], [])
+
+AS_IF([test x"$valgrind_tests" = x"yes"], [: ${CFLAGS="-ggdb3 -O0"}],
+ [test x"$debug" = x"yes"], [: ${CFLAGS="-ggdb -O0"}], [])
+
+AS_IF([test x"$code_coverage_tests" = x"yes"],
+ [: ${LDFLAGS=" --coverage"}], [])
+
+AS_IF([test x"$code_coverage_tests" = x"yes"],
+ [ CFLAGS+=" --coverage"], [])
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_GNU_SOURCE
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+
+AC_SUBST(CFLAGS)
+AC_SUBST(CPPFLAGS)
+AC_SUBST(LDFLAGS)
+AC_SUBST(ALL_STATIC_LDFLAGS)
+
+AC_OUTPUT
+#------------------------------------------------------------------------------
# info
echo "------------------------------------------------------------------------"
echo "$PACKAGE_NAME $PACKAGE_VERSION"
echo "------------------------------------------------------------------------"
echo
+echo "Compiler flags:"
+echo
+echo " CFLAGS..................: $CFLAGS $STRICT_CFLAGS"
+echo " LDFLAGS.................: $LDFLAGS $ALL_STATIC_LDFLAGS"
+echo
+echo
+echo "Interpreters paths:"
+echo
+echo " PYTHON3..................: $PYTHON3"
+echo
+echo
echo "Configuration Options:"
echo
echo " debug build.............: $debug"
echo
+echo " device(s)...............: $IPC_DEVICE_NAME"
+echo
echo " prefix..................: $prefix"
echo
+echo " valgrind tests..........: $valgrind_tests"
+echo
+echo " code coverage tests.....: $code_coverage_tests"
echo "------------------------------------------------------------------------"
echo
echo "Now type 'make' to compile and 'make install' to install this package."
-
diff --git a/include/samsung-ipc.h b/include/samsung-ipc.h
index b5a8315..d9aa7c7 100644
--- a/include/samsung-ipc.h
+++ b/include/samsung-ipc.h
@@ -19,11 +19,14 @@
* along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sys/time.h>
-
#ifndef __SAMSUNG_IPC_H__
#define __SAMSUNG_IPC_H__
+#include <stddef.h>
+#include <unistd.h>
+
+#include <sys/time.h>
+
/*
* Values
*/
@@ -134,6 +137,8 @@ int ipc_seq_valid(unsigned char seq);
const char *ipc_request_type_string(unsigned char type);
const char *ipc_response_type_string(unsigned char type);
const char *ipc_command_string(unsigned short command);
+const char *ipc_group_string(unsigned char group);
+const char *ipc_client_type_string(unsigned char client_type);
int ipc_data_dump(struct ipc_client *client, const void *data, size_t size);
void ipc_client_log_send(struct ipc_client *client, struct ipc_message *message,
@@ -150,11 +155,15 @@ int ipc_rfs_header_setup(struct ipc_rfs_header *header,
int ipc_rfs_message_setup(const struct ipc_rfs_header *header,
struct ipc_message *message);
+ssize_t data_read(struct ipc_client *client, int fd, void *buf, size_t count);
+ssize_t data_write(struct ipc_client *client, int fd, const void *buf,
+ size_t count);
void *file_data_read(struct ipc_client *client, const char *path, size_t size,
size_t chunk_size, unsigned int offset);
int file_data_write(struct ipc_client *client, const char *path,
const void *data, size_t size, size_t chunk_size,
unsigned int offset);
+off_t file_data_size(struct ipc_client *client, const char *path);
int network_iface_up(const char *iface, int domain, int type);
int network_iface_down(const char *iface, int domain, int type);
int sysfs_value_read(const char *path);
diff --git a/samsung-ipc/Makefile.am b/samsung-ipc/Makefile.am
index 87becdd..47484e5 100644
--- a/samsung-ipc/Makefile.am
+++ b/samsung-ipc/Makefile.am
@@ -6,8 +6,16 @@ AM_CFLAGS = \
$(OPENSSL_CFLAGS) \
$(NULL)
+if WANT_STRICT_CFLAGS
+AM_CFLAGS += $(STRICT_CFLAGS)
+endif
+
if WANT_DEBUG
-AM_CFLAGS += -ggdb -O0 -DDEBUG
+AM_CFLAGS += -DDEBUG
+endif
+
+if WANT_IPC_DEVICE_NAME
+AM_CFLAGS += -DIPC_DEVICE_NAME=\"$(IPC_DEVICE_NAME)\"
endif
lib_LTLIBRARIES = \
@@ -17,41 +25,8 @@ lib_LTLIBRARIES = \
libsamsung_ipc_la_SOURCES = \
ipc.c \
ipc.h \
+ ipc_strings.c \
ipc_utils.c \
- modems/xmm616/xmm616.c \
- modems/xmm616/xmm616.h \
- modems/xmm626/xmm626.c \
- modems/xmm626/xmm626.h \
- modems/xmm626/xmm626_hsic.c \
- modems/xmm626/xmm626_hsic.h \
- modems/xmm626/xmm626_kernel_smdk4412.c \
- modems/xmm626/xmm626_kernel_smdk4412.h \
- modems/xmm626/xmm626_mipi.c \
- modems/xmm626/xmm626_mipi.h \
- modems/xmm626/xmm626_modem_if.h \
- modems/xmm626/xmm626_modem_link_device_hsic.h \
- modems/xmm626/xmm626_modem_prj.h \
- devices/ipc_devices.c \
- devices/ipc_devices.h \
- devices/crespo/crespo.c \
- devices/crespo/crespo.h \
- devices/crespo/crespo_modem_ctl.h \
- devices/aries/aries.c \
- devices/aries/aries.h \
- devices/aries/onedram.h \
- devices/aries/phonet.h \
- devices/galaxys2/galaxys2.c \
- devices/galaxys2/galaxys2.h \
- devices/maguro/maguro.c \
- devices/maguro/maguro.h \
- devices/piranha/piranha.c \
- devices/piranha/piranha.h \
- devices/i9300/i9300.c \
- devices/i9300/i9300.h \
- devices/n7100/n7100.c \
- devices/n7100/n7100.h \
- devices/n5100/n5100.c \
- devices/n5100/n5100.h \
utils.c \
call.c \
sms.c \
@@ -64,6 +39,10 @@ libsamsung_ipc_la_SOURCES = \
gen.c \
$(NULL)
+include devices/Makefile.am
+include modems/Makefile.am
+include partitions/Makefile.am
+
libsamsung_ipc_la_LIBADD = \
$(OPENSSL_LIBS) \
$(NULL)
diff --git a/samsung-ipc/devices/Makefile.am b/samsung-ipc/devices/Makefile.am
new file mode 100644
index 0000000..8257be3
--- /dev/null
+++ b/samsung-ipc/devices/Makefile.am
@@ -0,0 +1,25 @@
+libsamsung_ipc_la_SOURCES += \
+ devices/ipc_devices.c \
+ devices/ipc_devices.h \
+ devices/crespo/crespo.c \
+ devices/crespo/crespo.h \
+ devices/crespo/crespo_modem_ctl.h \
+ devices/aries/aries.c \
+ devices/aries/aries.h \
+ devices/aries/onedram.h \
+ devices/aries/phonet.h \
+ devices/galaxys2/galaxys2.c \
+ devices/galaxys2/galaxys2.h \
+ devices/maguro/maguro.c \
+ devices/maguro/maguro.h \
+ devices/piranha/piranha.c \
+ devices/piranha/piranha.h \
+ devices/i9300/i9300.c \
+ devices/i9300/i9300.h \
+ devices/n7100/n7100.c \
+ devices/n7100/n7100.h \
+ devices/n5100/n5100.c \
+ devices/n5100/n5100.h \
+ devices/herolte/herolte.c \
+ devices/herolte/herolte.h \
+ $(NULL)
diff --git a/samsung-ipc/devices/aries/aries.c b/samsung-ipc/devices/aries/aries.c
index 93d5d31..9fc905a 100644
--- a/samsung-ipc/devices/aries/aries.c
+++ b/samsung-ipc/devices/aries/aries.c
@@ -819,11 +819,16 @@ char *aries_gprs_get_iface(__attribute__((unused)) struct ipc_client *client,
unsigned int cid)
{
char *iface = NULL;
+ int rc;
if (cid > ARIES_GPRS_IFACE_COUNT)
return NULL;
- asprintf(&iface, "%s%d", ARIES_GPRS_IFACE_PREFIX, cid - 1);
+ rc = asprintf(&iface, "%s%d", ARIES_GPRS_IFACE_PREFIX, cid - 1);
+ if (rc == -1) {
+ ipc_client_log(client, "%s: asprintf failed", __func__);
+ return NULL;
+ }
return iface;
}
diff --git a/samsung-ipc/devices/crespo/crespo.c b/samsung-ipc/devices/crespo/crespo.c
index ebb6075..5399e77 100644
--- a/samsung-ipc/devices/crespo/crespo.c
+++ b/samsung-ipc/devices/crespo/crespo.c
@@ -553,13 +553,17 @@ int crespo_gprs_deactivate(__attribute__((unused)) struct ipc_client *client,
return 0;
}
-char *crespo_gprs_get_iface_single(
- __attribute__((unused)) struct ipc_client *client,
- __attribute__((unused)) unsigned int cid)
+char *crespo_gprs_get_iface_single(struct ipc_client *client,
+ __attribute__((unused)) unsigned int cid)
{
char *iface = NULL;
+ int rc;
- asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, 0);
+ rc = asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, 0);
+ if (rc == -1) {
+ ipc_client_log(client, "%s: asprintf failed", __func__);
+ return NULL;
+ }
return iface;
}
@@ -580,11 +584,16 @@ char *crespo_gprs_get_iface(__attribute__((unused)) struct ipc_client *client,
unsigned int cid)
{
char *iface = NULL;
+ int rc;
if (cid > CRESPO_GPRS_IFACE_COUNT)
return NULL;
- asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, cid - 1);
+ rc = asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, cid - 1);
+ if (rc == -1) {
+ ipc_client_log(client, "%s: asprintf failed", __func__);
+ return NULL;
+ }
return iface;
}
diff --git a/samsung-ipc/devices/galaxys2/galaxys2.c b/samsung-ipc/devices/galaxys2/galaxys2.c
index cdfe20c..954417f 100644
--- a/samsung-ipc/devices/galaxys2/galaxys2.c
+++ b/samsung-ipc/devices/galaxys2/galaxys2.c
@@ -78,29 +78,59 @@ int galaxys2_boot(struct ipc_client *client)
ipc_client_log(client, "Opened modem link device");
rc = xmm626_kernel_smdk4412_power(client, modem_boot_fd, 0);
- rc |= xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
- 0);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 0);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering off the modem failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
+ 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Disabling the modem link failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 0);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem off failed");
+ ipc_client_log(client, "Powering off the HCI bus failed");
goto error;
}
+
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Deactivating the modem link failed");
+ goto error;
+ }
+
ipc_client_log(client, "Turned the modem off");
rc = xmm626_kernel_smdk4412_power(client, modem_boot_fd, 1);
- rc |= xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
- 1);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 1);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering on the modem failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
+ 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Enabling the modem link failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_hci_power(client, 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering on the HCI bus failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 1);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem on failed");
+ ipc_client_log(client, "Activating the modem link failed");
goto error;
}
+
ipc_client_log(client, "Turned the modem on");
rc = xmm626_kernel_smdk4412_link_connected_wait(client, modem_link_fd);
@@ -188,12 +218,21 @@ int galaxys2_boot(struct ipc_client *client)
rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
0);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 0);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Disabling the modem link failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 0);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem off failed");
+ ipc_client_log(client, "Powering off the HCI bus failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Deactivating the modem link failed");
goto error;
}
@@ -207,12 +246,21 @@ int galaxys2_boot(struct ipc_client *client)
rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
1);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 1);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Enabling the modem link failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering on the HCI bus failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 1);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem on failed");
+ ipc_client_log(client, "Activating the modem link failed");
goto error;
}
diff --git a/samsung-ipc/devices/herolte/herolte.c b/samsung-ipc/devices/herolte/herolte.c
new file mode 100644
index 0000000..c5d15ef
--- /dev/null
+++ b/samsung-ipc/devices/herolte/herolte.c
@@ -0,0 +1,610 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ * Copyright (C) 2020 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
+ *
+ * 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 <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "devices/herolte/herolte.h"
+#include "ipc.h"
+#include "modems/xmm626/xmm626.h"
+#include "modems/xmm626/xmm626_kernel_smdk4412.h"
+#include "modems/xmm626/xmm626_modem_prj.h"
+#include "partitions/android/android.h"
+#include "partitions/toc/toc.h"
+
+struct __attribute__((__packed__)) security_req {
+ uint32_t mode;
+ uint32_t size_boot;
+ uint32_t size_main;
+ uint32_t pad_zero;
+};
+
+struct __attribute__((__packed__)) modem_firmware_partition_data {
+ uint8_t *binary;
+ uint32_t size;
+ uint32_t m_offset;
+ uint32_t b_offset;
+ uint32_t mode;
+ ssize_t len;
+};
+
+#define IOCTL_SECURITY_REQ _IO('o', 0x53)
+
+#define MAX_CHUNK_LEN (62 * 1024) /* This is just what cbd uses.
+ * Perhaps a larger value would also work.
+ */
+
+static int upload_chunk(struct ipc_client *client,
+ int device_fd,
+ int firmware_fd,
+ struct firmware_toc_entry const *toc,
+ char const *name,
+ uint32_t *size)
+{
+ int rc = -1;
+ struct modem_firmware_partition_data partition;
+ struct firmware_toc_entry const *boot_toc_entry;
+ struct firmware_toc_entry const *current_toc_entry;
+ uint32_t remaining;
+
+ ipc_client_log(client, "Uploading %s", name);
+
+ boot_toc_entry = find_toc_entry("BOOT", toc);
+ if (boot_toc_entry == NULL) {
+ ipc_client_log(client,
+ "%s: Failed to find BOOT entry in the TOC",
+ __func__);
+ goto exit;
+ }
+
+ current_toc_entry = find_toc_entry(name, toc);
+ if (current_toc_entry == NULL) {
+ ipc_client_log(client, "%s: Failed to find %s entry in the TOC",
+ __func__, name);
+ goto exit;
+ }
+
+ if (size != NULL)
+ *size = current_toc_entry->size;
+ ipc_client_log(client, " - blob size for %s is %lu", name,
+ current_toc_entry->size);
+
+ partition.binary = calloc(1, MAX_CHUNK_LEN);
+ if (partition.binary == NULL) {
+ rc = -errno;
+ ipc_client_log(client, "%s: calloc failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ partition.size = current_toc_entry->size;
+ partition.m_offset = current_toc_entry->loadaddr -
+ boot_toc_entry->loadaddr;
+ partition.b_offset = current_toc_entry->offset;
+ partition.mode = 0;
+ partition.len = 0;
+
+ if (lseek(firmware_fd, partition.b_offset, SEEK_SET) < 0) {
+ rc = -errno;
+ ipc_client_log(client, "%s: lseek failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ remaining = partition.size;
+ while (remaining > 0) {
+ partition.len = remaining < MAX_CHUNK_LEN ?
+ remaining : MAX_CHUNK_LEN;
+ if (data_read(client, firmware_fd, partition.binary,
+ partition.len) != partition.len) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: read failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ if (ioctl(device_fd, IOCTL_DPRAM_SEND_BOOT, &partition) == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: IOCTL_DPRAM_SEND_BOOT failed"
+ " with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ partition.m_offset += partition.len;
+ partition.b_offset += partition.len;
+ remaining -= partition.len;
+ }
+
+ rc = 0;
+
+exit:
+ if (partition.binary != NULL) {
+ partition.binary = NULL;
+ free(partition.binary);
+ }
+
+ return rc;
+}
+
+static int select_secure_mode(struct ipc_client *client,
+ int boot0_fd,
+ int secure,
+ uint32_t size_boot,
+ uint32_t size_main)
+{
+ struct security_req req;
+ int rc;
+
+ ipc_client_log(client,
+ "Issuing IOCTL_SECURITY_REQ - setting %s mode",
+ secure ? "secure" : "insecure");
+
+ req.mode = secure ? 0 : 2;
+ req.size_boot = size_boot;
+ req.size_main = size_main;
+ req.pad_zero = 0;
+
+ if (ioctl(boot0_fd, IOCTL_SECURITY_REQ, &req) == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: "
+ "IOCTL_SECURITY_REQ failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ return -1;
+ }
+
+ return 0;
+}
+
+static char const * const modem_image_devices[] = {
+ "/dev/disk/by-partlabel/RADIO", /* PostmarketOS */
+ "/dev/block/platform/155a0000.ufs/by-name/RADIO", /* LineageOS */
+ NULL
+};
+
+int herolte_boot(struct ipc_client *client)
+{
+ struct firmware_toc_entry toc[N_TOC_ENTRIES];
+ int boot0_fd = -1;
+ int imagefd = -1;
+ int nvfd = -1;
+ int rc = -1;
+ uint32_t size_boot;
+ uint32_t size_main;
+
+ ipc_client_log(client, "Loading firmware TOC");
+
+ imagefd = open_android_modem_partition(client, modem_image_devices);
+ if (imagefd == -1) {
+ rc = errno;
+ if (rc == ENOENT)
+ ipc_client_log(client,
+ "%s: no modem image block device found!",
+ __func__);
+ else
+ ipc_client_log(client,
+ "%s: "
+ "open_image_device failed with error %d:"
+ " %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ if (data_read(client, imagefd, &toc[0], sizeof(toc)) != sizeof(toc)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: read modem image block device failed "
+ " with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ ipc_client_log(client, "Loaded firmware TOC");
+
+ nvfd = open(herolte_nv_data_specs.nv_data_path, O_RDONLY | O_NOCTTY);
+ if (nvfd == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: opening %s failed with error %d: %s",
+ __func__, herolte_nv_data_specs.nv_data_path,
+ rc, strerror(rc));
+ goto exit;
+ }
+ ipc_client_log(client, "Opened NV data file");
+
+ boot0_fd = open(XMM626_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY);
+ if (boot0_fd < 0) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: opening %s failed with error %d: %s",
+ __func__, XMM626_SEC_MODEM_BOOT0_DEVICE,
+ rc, strerror(rc));
+ goto exit;
+ }
+
+ ipc_client_log(client, "Resetting modem");
+ if (ioctl(boot0_fd, IOCTL_MODEM_RESET, 0) == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: "
+ "IOCTL_MODEM_RESET failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ if (select_secure_mode(client, boot0_fd, 0, 0, 0) < 0)
+ goto exit;
+
+ if (upload_chunk(client, boot0_fd, imagefd, toc, "BOOT",
+ &size_boot) < 0)
+ goto exit;
+
+ if (upload_chunk(client, boot0_fd, imagefd, toc, "MAIN",
+ &size_main) < 0)
+ goto exit;
+
+ if (upload_chunk(client, boot0_fd, nvfd, toc, "NV", NULL) < 0)
+ goto exit;
+
+ if (select_secure_mode(client, boot0_fd, 1, size_boot, size_main) < 0)
+ goto exit;
+
+ ipc_client_log(client, "Powering on modem");
+ if (xmm626_kernel_smdk4412_power(client, boot0_fd, 1) == -1) {
+ ipc_client_log(client, "%s: Powering on modem failed",
+ __func__);
+ goto exit;
+ }
+
+ ipc_client_log(client, "Starting modem boot process");
+ if (xmm626_kernel_smdk4412_boot_power(client, boot0_fd, 1) == -1) {
+ ipc_client_log(client, "%s: Starting modem boot process failed",
+ __func__);
+ goto exit;
+ }
+
+ ipc_client_log(client, "Kicking off firmware download");
+ if (ioctl(boot0_fd, IOCTL_MODEM_DL_START, 0) < 0) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: "
+ "IOCTL_MODEM_RESET failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ ipc_client_log(client, "Handshaking with modem");
+ /* At this point, cbd engages in a little dance with the
+ * newly-booted modem, apparently to verify that it is running
+ * as expected. I don’t know the sources of these magic
+ * numbers, I just faithfully reproduce them.
+ */
+ {
+ uint32_t buf;
+
+ buf = 0x900d;
+ if (data_write(client, boot0_fd, &buf, sizeof(buf)) !=
+ sizeof(buf)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: write failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ if (data_read(client, boot0_fd, &buf, sizeof(buf)) !=
+ sizeof(buf)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: read failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ if (buf != 0xa00d) {
+ ipc_client_log(client,
+ "%s: Handshake stage I failed: "
+ "expected 0xa00d, got 0x%x instead",
+ __func__, buf);
+ goto exit;
+ }
+ ipc_client_log(client, "Handshake stage I passed");
+
+ buf = 0x9f00;
+ if (data_write(client, boot0_fd, &buf,
+ sizeof(buf)) != sizeof(buf)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: write failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ if (data_read(client, boot0_fd, &buf,
+ sizeof(buf)) != sizeof(buf)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: read failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ if (buf != 0xaf00) {
+ ipc_client_log(client,
+ "%s: Handshake stage II failed: "
+ "expected 0xaf00, got 0x%x instead",
+ __func__, buf);
+ goto exit;
+ }
+ ipc_client_log(client, "Handshake stage II passed");
+ }
+
+ ipc_client_log(client, "Finishing modem boot process");
+ if (xmm626_kernel_smdk4412_boot_power(client, boot0_fd, 0) == -1) {
+ ipc_client_log(client,
+ "%s: xmm626_kernel_smdk4412_boot_power failed",
+ __func__);
+ goto exit;
+ }
+
+ ipc_client_log(client, "Modem boot complete");
+ rc = 0;
+
+ /* Samsung's official daemons continue to read from umts_boot0
+ * (XMM626_SEC_MODEM_BOOT0_DEVICE) at this point. It may be
+ * done to restart the modem in case of errors. The fact that
+ * I have never seen anything actually come out of umts_boot0
+ * after booting is complete with libsamsung-ipc seem to be
+ * consistent with that hypothesis. With libsamsung-ipc,
+ * it's up to the daemon using it (like libsamsung-ril) to restart
+ * the boot sequence if .poll (here herolte_poll) fails.
+ * For that to work, the kernel driver needs to return an error
+ * if the modem crash for instance.
+ */
+
+ /* The kernel modem driver for this device[1] checks if both the FMT
+ * and the RFS channels are open (in the rild_ready function) and will
+ * refuse to work if both channels aren't open. Note that even if
+ * libsamsung-ipc opens both channels, at the time of writing, none
+ * of the tools in tools/ opens the RFS channel.
+ *
+ * [1]See the rild_ready function and its usage in
+ * drivers/misc/modem_v1/link_device_shmem.c in the lineage-17.0 branch
+ * https://github.com/ivanmeler/android_kernel_samsung_herolte
+ */
+
+exit:
+ if (boot0_fd != -1)
+ close(boot0_fd);
+ if (imagefd != -1)
+ close(imagefd);
+ if (nvfd != -1)
+ close(nvfd);
+ return rc;
+}
+
+int herolte_open(__attribute__((unused)) struct ipc_client *client, void *data,
+ int type)
+{
+ struct herolte_transport_data *transport_data;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ transport_data->fd = xmm626_kernel_smdk4412_open(client, type);
+ if (transport_data->fd < 0)
+ return -1;
+
+ return 0;
+}
+
+int herolte_close(__attribute__((unused)) struct ipc_client *client, void *data)
+{
+ struct herolte_transport_data *transport_data;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ xmm626_kernel_smdk4412_close(client, transport_data->fd);
+ transport_data->fd = -1;
+
+ return 0;
+}
+
+int herolte_read(__attribute__((unused)) struct ipc_client *client, void *data,
+ void *buffer, size_t length)
+{
+ struct herolte_transport_data *transport_data;
+ int rc;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ rc = xmm626_kernel_smdk4412_read(client, transport_data->fd, buffer,
+ length);
+
+ return rc;
+}
+
+int herolte_write(__attribute__((unused)) struct ipc_client *client, void *data,
+ const void *buffer, size_t length)
+{
+ struct herolte_transport_data *transport_data;
+ int rc;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ rc = xmm626_kernel_smdk4412_write(client, transport_data->fd, buffer,
+ length);
+
+ return rc;
+}
+
+int herolte_poll(__attribute__((unused)) struct ipc_client *client, void *data,
+ struct ipc_poll_fds *fds, struct timeval *timeout)
+{
+ struct herolte_transport_data *transport_data;
+ int rc;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ rc = xmm626_kernel_smdk4412_poll(client, transport_data->fd, fds,
+ timeout);
+
+ return rc;
+}
+
+int herolte_power_on(__attribute__((unused)) struct ipc_client *client,
+ __attribute__((unused)) void *data)
+{
+ return 0;
+}
+
+int herolte_power_off(__attribute__((unused)) struct ipc_client *client,
+ __attribute__((unused)) void *data)
+{
+ int fd;
+ int rc;
+
+ fd = open(XMM626_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY |
+ O_NONBLOCK);
+ if (fd < 0)
+ return -1;
+
+ rc = xmm626_kernel_smdk4412_power(client, fd, 0);
+
+ close(fd);
+
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int herolte_gprs_activate(__attribute__((unused)) struct ipc_client *client,
+ __attribute__((unused)) void *data,
+ __attribute__((unused)) unsigned int cid)
+{
+ /* TODO: For now, we don't have enough information to
+ * implement this sensibly, hence this placeholder.
+ */
+
+ return 0;
+}
+
+int herolte_gprs_deactivate(__attribute__((unused)) struct ipc_client *client,
+ __attribute__((unused)) void *data,
+ __attribute__((unused)) unsigned int cid)
+{
+ /* TODO: For now, we don't have enough information to
+ * implement this sensibly, hence this placeholder.
+ */
+
+ return 0;
+}
+
+int herolte_data_create(__attribute__((unused)) struct ipc_client *client,
+ void **transport_data,
+ __attribute__((unused)) void **power_data,
+ __attribute__((unused)) void **gprs_data)
+{
+ if (transport_data == NULL)
+ return -1;
+
+ *transport_data = calloc(1, sizeof(struct herolte_transport_data));
+
+ return 0;
+}
+
+int herolte_data_destroy(__attribute__((unused)) struct ipc_client *client,
+ void *transport_data,
+ __attribute__((unused)) void *power_data,
+ __attribute__((unused)) void *gprs_data)
+{
+ if (transport_data == NULL)
+ return -1;
+
+ free(transport_data);
+
+ return 0;
+}
+
+struct ipc_client_ops herolte_fmt_ops = {
+ .boot = herolte_boot,
+ .send = xmm626_kernel_smdk4412_fmt_send,
+ .recv = xmm626_kernel_smdk4412_fmt_recv,
+};
+
+struct ipc_client_ops herolte_rfs_ops = {
+ .boot = NULL,
+ .send = xmm626_kernel_smdk4412_rfs_send,
+ .recv = xmm626_kernel_smdk4412_rfs_recv,
+};
+
+struct ipc_client_handlers herolte_handlers = {
+ .read = herolte_read,
+ .write = herolte_write,
+ .open = herolte_open,
+ .close = herolte_close,
+ .poll = herolte_poll,
+ .transport_data = NULL,
+ .power_on = herolte_power_on,
+ .power_off = herolte_power_off,
+ .power_data = NULL,
+ .gprs_activate = herolte_gprs_activate,
+ .gprs_deactivate = herolte_gprs_deactivate,
+ .gprs_data = NULL,
+ .data_create = herolte_data_create,
+ .data_destroy = herolte_data_destroy,
+};
+
+struct ipc_client_gprs_specs herolte_gprs_specs = {
+ .gprs_get_iface = xmm626_kernel_smdk4412_gprs_get_iface,
+ .gprs_get_capabilities = xmm626_kernel_smdk4412_gprs_get_capabilities,
+};
+
+struct ipc_client_nv_data_specs herolte_nv_data_specs = {
+ .nv_data_path = XMM626_NV_DATA_PATH,
+ .nv_data_md5_path = XMM626_NV_DATA_MD5_PATH,
+ .nv_data_backup_path = XMM626_NV_DATA_BACKUP_PATH,
+ .nv_data_backup_md5_path = XMM626_NV_DATA_BACKUP_MD5_PATH,
+ .nv_data_secret = XMM626_NV_DATA_SECRET,
+ .nv_data_size = XMM626_NV_DATA_SIZE,
+ .nv_data_chunk_size = XMM626_NV_DATA_CHUNK_SIZE,
+};
diff --git a/samsung-ipc/devices/herolte/herolte.h b/samsung-ipc/devices/herolte/herolte.h
new file mode 100644
index 0000000..32d1638
--- /dev/null
+++ b/samsung-ipc/devices/herolte/herolte.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ * Copyright (C) 2020 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
+ *
+ * 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 __HEROLTE_H__
+#define __HEROLTE_H__
+
+struct herolte_transport_data {
+ int fd;
+};
+
+extern struct ipc_client_ops herolte_fmt_ops;
+extern struct ipc_client_ops herolte_rfs_ops;
+extern struct ipc_client_handlers herolte_handlers;
+extern struct ipc_client_gprs_specs herolte_gprs_specs;
+extern struct ipc_client_nv_data_specs herolte_nv_data_specs;
+
+#endif /* __HEROLTE_H__ */
diff --git a/samsung-ipc/devices/i9300/i9300.c b/samsung-ipc/devices/i9300/i9300.c
index 85709a8..a2c2b92 100644
--- a/samsung-ipc/devices/i9300/i9300.c
+++ b/samsung-ipc/devices/i9300/i9300.c
@@ -85,10 +85,14 @@ int i9300_boot(struct ipc_client *client)
ipc_client_log(client, "Turned the modem off");
rc = xmm626_kernel_smdk4412_power(client, modem_boot_fd, 1);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering on the modem failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 1);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem on failed");
+ ipc_client_log(client, "Powering on the HCI bus failed");
goto error;
}
ipc_client_log(client, "Turned the modem on");
@@ -178,12 +182,21 @@ int i9300_boot(struct ipc_client *client)
rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
0);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 0);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Disabling the modem link failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 0);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem off failed");
+ ipc_client_log(client, "Powering off the HCI bus failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Deactivating the modem link failed");
goto error;
}
@@ -197,12 +210,21 @@ int i9300_boot(struct ipc_client *client)
rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
1);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 1);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Enabling the modem link failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering on the HCI bus failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 1);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem on failed");
+ ipc_client_log(client, "Activating the modem link failed");
goto error;
}
diff --git a/samsung-ipc/devices/ipc_devices.c b/samsung-ipc/devices/ipc_devices.c
index 91663f6..a0fe955 100644
--- a/samsung-ipc/devices/ipc_devices.c
+++ b/samsung-ipc/devices/ipc_devices.c
@@ -154,6 +154,16 @@ struct ipc_device_desc ipc_devices[] = {
.gprs_specs = &n5100_gprs_specs,
.nv_data_specs = &n5100_nv_data_specs,
},
+ {
+ .name = "herolte",
+ .board_name = NULL,
+ .kernel_version = NULL,
+ .fmt_ops = &herolte_fmt_ops,
+ .rfs_ops = &herolte_rfs_ops,
+ .handlers = &herolte_handlers,
+ .gprs_specs = &herolte_gprs_specs,
+ .nv_data_specs = &herolte_nv_data_specs,
+ },
};
unsigned int ipc_devices_count = sizeof(ipc_devices) /
diff --git a/samsung-ipc/devices/ipc_devices.h b/samsung-ipc/devices/ipc_devices.h
index 176607c..8160ee1 100644
--- a/samsung-ipc/devices/ipc_devices.h
+++ b/samsung-ipc/devices/ipc_devices.h
@@ -20,14 +20,15 @@
#include <samsung-ipc.h>
-#include "devices/crespo/crespo.h"
#include "devices/aries/aries.h"
+#include "devices/crespo/crespo.h"
#include "devices/galaxys2/galaxys2.h"
-#include "devices/maguro/maguro.h"
-#include "devices/piranha/piranha.h"
+#include "devices/herolte/herolte.h"
#include "devices/i9300/i9300.h"
-#include "devices/n7100/n7100.h"
+#include "devices/maguro/maguro.h"
#include "devices/n5100/n5100.h"
+#include "devices/n7100/n7100.h"
+#include "devices/piranha/piranha.h"
#ifndef __IPC_DEVICES_H__
#define __IPC_DEVICES_H__
diff --git a/samsung-ipc/devices/n5100/n5100.c b/samsung-ipc/devices/n5100/n5100.c
index 0abe896..f7055bf 100644
--- a/samsung-ipc/devices/n5100/n5100.c
+++ b/samsung-ipc/devices/n5100/n5100.c
@@ -86,10 +86,14 @@ int n5100_boot(struct ipc_client *client)
ipc_client_log(client, "Turned the modem off");
rc = xmm626_kernel_smdk4412_power(client, modem_boot_fd, 1);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering on the modem failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 1);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem on failed");
+ ipc_client_log(client, "Powering on the HCI bus failed");
goto error;
}
ipc_client_log(client, "Turned the modem on");
@@ -179,12 +183,21 @@ int n5100_boot(struct ipc_client *client)
rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
0);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 0);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Disabling the modem link failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 0);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem off failed");
+ ipc_client_log(client, "Powering off the HCI bus failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Deactivating the modem link failed");
goto error;
}
@@ -198,12 +211,21 @@ int n5100_boot(struct ipc_client *client)
rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
1);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 1);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Enabling the modem link failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering on the HCI bus failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 1);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem on failed");
+ ipc_client_log(client, "Activating the modem link failed");
goto error;
}
diff --git a/samsung-ipc/devices/n7100/n7100.c b/samsung-ipc/devices/n7100/n7100.c
index d5091a2..6312c18 100644
--- a/samsung-ipc/devices/n7100/n7100.c
+++ b/samsung-ipc/devices/n7100/n7100.c
@@ -85,10 +85,14 @@ int n7100_boot(struct ipc_client *client)
ipc_client_log(client, "Turned the modem off");
rc = xmm626_kernel_smdk4412_power(client, modem_boot_fd, 1);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering on the modem failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 1);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem on failed");
+ ipc_client_log(client, "Powering on the HCI bus failed");
goto error;
}
ipc_client_log(client, "Turned the modem on");
@@ -178,12 +182,21 @@ int n7100_boot(struct ipc_client *client)
rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
0);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 0);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Disabling the modem link failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 0);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem off failed");
+ ipc_client_log(client, "Powering off the HCI bus failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 0);
+ if (rc < 0) {
+ ipc_client_log(client, "Deactivating the modem link failed");
goto error;
}
@@ -197,12 +210,21 @@ int n7100_boot(struct ipc_client *client)
rc = xmm626_kernel_smdk4412_link_control_enable(client, modem_link_fd,
1);
- rc |= xmm626_kernel_smdk4412_hci_power(client, 1);
- rc |= xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
- 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Enabling the modem link failed");
+ goto error;
+ }
+ rc = xmm626_kernel_smdk4412_hci_power(client, 1);
+ if (rc < 0) {
+ ipc_client_log(client, "Powering on the HCI bus failed");
+ goto error;
+ }
+
+ rc = xmm626_kernel_smdk4412_link_control_active(client, modem_link_fd,
+ 1);
if (rc < 0) {
- ipc_client_log(client, "Turning the modem on failed");
+ ipc_client_log(client, "Activating the modem link failed");
goto error;
}
diff --git a/samsung-ipc/gprs.c b/samsung-ipc/gprs.c
index 89f06e7..c9722e5 100644
--- a/samsung-ipc/gprs.c
+++ b/samsung-ipc/gprs.c
@@ -35,7 +35,7 @@ int ipc_gprs_define_pdp_context_setup(
data->cid = cid;
data->magic = 0x02;
- strncpy((char *) data->apn, apn, sizeof(data->apn));
+ memcpy(data->apn, apn, sizeof(data->apn));
return 0;
}
@@ -56,9 +56,9 @@ int ipc_gprs_pdp_context_request_set_setup(
data->magic1[2] = 0x13;
data->magic2 = 0x01;
- strncpy((char *) data->username, username,
+ memcpy(data->username, username,
sizeof(data->username));
- strncpy((char *) data->password, password,
+ memcpy(data->password, password,
sizeof(data->password));
}
diff --git a/samsung-ipc/ipc_strings.c b/samsung-ipc/ipc_strings.c
new file mode 100644
index 0000000..e7e6e8b
--- /dev/null
+++ b/samsung-ipc/ipc_strings.c
@@ -0,0 +1,409 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com>
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
+ *
+ * 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 <stdio.h>
+
+#include <samsung-ipc.h>
+
+const char *ipc_request_type_string(unsigned char type)
+{
+ static char type_string[5] = { 0 };
+
+ switch (type) {
+ case IPC_TYPE_EXEC:
+ return "IPC_TYPE_EXEC";
+ case IPC_TYPE_GET:
+ return "IPC_TYPE_GET";
+ case IPC_TYPE_SET:
+ return "IPC_TYPE_SET";
+ case IPC_TYPE_CFRM:
+ return "IPC_TYPE_CFRM";
+ case IPC_TYPE_EVENT:
+ return "IPC_TYPE_EVENT";
+ default:
+ snprintf((char *) &type_string, sizeof(type_string), "0x%02x",
+ type);
+ return type_string;
+ }
+}
+
+const char *ipc_response_type_string(unsigned char type)
+{
+ static char type_string[5] = { 0 };
+
+ switch (type) {
+ case IPC_TYPE_INDI:
+ return "IPC_TYPE_INDI";
+ case IPC_TYPE_RESP:
+ return "IPC_TYPE_RESP";
+ case IPC_TYPE_NOTI:
+ return "IPC_TYPE_NOTI";
+ default:
+ snprintf((char *) &type_string, sizeof(type_string), "0x%02x",
+ type);
+ return type_string;
+ }
+}
+
+const char *ipc_command_string(unsigned short command)
+{
+ static char command_string[7] = { 0 };
+
+ switch (command) {
+ case IPC_PWR_PHONE_PWR_UP:
+ return "IPC_PWR_PHONE_PWR_UP";
+ case IPC_PWR_PHONE_PWR_OFF:
+ return "IPC_PWR_PHONE_PWR_OFF";
+ case IPC_PWR_PHONE_RESET:
+ return "IPC_PWR_PHONE_RESET";
+ case IPC_PWR_BATT_STATUS:
+ return "IPC_PWR_BATT_STATUS";
+ case IPC_PWR_BATT_TYPE:
+ return "IPC_PWR_BATT_TYPE";
+ case IPC_PWR_BATT_COMP:
+ return "IPC_PWR_BATT_COMP";
+ case IPC_PWR_PHONE_STATE:
+ return "IPC_PWR_PHONE_STATE";
+ case IPC_CALL_OUTGOING:
+ return "IPC_CALL_OUTGOING";
+ case IPC_CALL_INCOMING:
+ return "IPC_CALL_INCOMING";
+ case IPC_CALL_RELEASE:
+ return "IPC_CALL_RELEASE";
+ case IPC_CALL_ANSWER:
+ return "IPC_CALL_ANSWER";
+ case IPC_CALL_STATUS:
+ return "IPC_CALL_STATUS";
+ case IPC_CALL_LIST:
+ return "IPC_CALL_LIST";
+ case IPC_CALL_BURST_DTMF:
+ return "IPC_CALL_BURST_DTMF";
+ case IPC_CALL_CONT_DTMF:
+ return "IPC_CALL_CONT_DTMF";
+ case IPC_CALL_WAITING:
+ return "IPC_CALL_WAITING";
+ case IPC_CALL_LINE_ID:
+ return "IPC_CALL_LINE_ID";
+ case IPC_SMS_SEND_MSG:
+ return "IPC_SMS_SEND_MSG";
+ case IPC_SMS_INCOMING_MSG:
+ return "IPC_SMS_INCOMING_MSG";
+ case IPC_SMS_READ_MSG:
+ return "IPC_SMS_READ_MSG";
+ case IPC_SMS_SAVE_MSG:
+ return "IPC_SMS_SAVE_MSG";
+ case IPC_SMS_DEL_MSG:
+ return "IPC_SMS_DEL_MSG";
+ case IPC_SMS_DELIVER_REPORT:
+ return "IPC_SMS_DELIVER_REPORT";
+ case IPC_SMS_DEVICE_READY:
+ return "IPC_SMS_DEVICE_READY";
+ case IPC_SMS_SEL_MEM:
+ return "IPC_SMS_SEL_MEM";
+ case IPC_SMS_STORED_MSG_COUNT:
+ return "IPC_SMS_STORED_MSG_COUNT";
+ case IPC_SMS_SVC_CENTER_ADDR:
+ return "IPC_SMS_SVC_CENTER_ADDR";
+ case IPC_SMS_SVC_OPTION:
+ return "IPC_SMS_SVC_OPTION";
+ case IPC_SMS_MEM_STATUS:
+ return "IPC_SMS_MEM_STATUS";
+ case IPC_SMS_CBS_MSG:
+ return "IPC_SMS_CBS_MSG";
+ case IPC_SMS_CBS_CFG:
+ return "IPC_SMS_CBS_CFG";
+ case IPC_SMS_STORED_MSG_STATUS:
+ return "IPC_SMS_STORED_MSG_STATUS";
+ case IPC_SMS_PARAM_COUNT:
+ return "IPC_SMS_PARAM_COUNT";
+ case IPC_SMS_PARAM:
+ return "IPC_SMS_PARAM";
+ case IPC_SEC_PIN_STATUS:
+ return "IPC_SEC_PIN_STATUS";
+ case IPC_SEC_PHONE_LOCK:
+ return "IPC_SEC_PHONE_LOCK";
+ case IPC_SEC_CHANGE_LOCKING_PW:
+ return "IPC_SEC_CHANGE_LOCKING_PW";
+ case IPC_SEC_SIM_LANG:
+ return "IPC_SEC_SIM_LANG";
+ case IPC_SEC_RSIM_ACCESS:
+ return "IPC_SEC_RSIM_ACCESS";
+ case IPC_SEC_GSIM_ACCESS:
+ return "IPC_SEC_GSIM_ACCESS";
+ case IPC_SEC_SIM_ICC_TYPE:
+ return "IPC_SEC_SIM_ICC_TYPE";
+ case IPC_SEC_LOCK_INFORMATION:
+ return "IPC_SEC_LOCK_INFORMATION";
+ case IPC_SEC_IMS_AUTH:
+ return "IPC_SEC_IMS_AUTH";
+ case IPC_PB_ACCESS:
+ return "IPC_PB_ACCESS";
+ case IPC_PB_STORAGE:
+ return "IPC_PB_STORAGE";
+ case IPC_PB_STORAGE_LIST:
+ return "IPC_PB_STORAGE_LIST";
+ case IPC_PB_ENTRY_INFO:
+ return "IPC_PB_ENTRY_INFO";
+ case IPC_PB_3GPB_CAPA:
+ return "IPC_PB_3GPB_CAPA";
+ case IPC_DISP_ICON_INFO:
+ return "IPC_DISP_ICON_INFO";
+ case IPC_DISP_HOMEZONE_INFO:
+ return "IPC_DISP_HOMEZONE_INFO";
+ case IPC_DISP_RSSI_INFO:
+ return "IPC_DISP_RSSI_INFO";
+ case IPC_NET_PREF_PLMN:
+ return "IPC_NET_PREF_PLMN";
+ case IPC_NET_PLMN_SEL:
+ return "IPC_NET_PLMN_SEL";
+ case IPC_NET_SERVING_NETWORK:
+ return "IPC_NET_SERVING_NETWORK";
+ case IPC_NET_PLMN_LIST:
+ return "IPC_NET_PLMN_LIST";
+ case IPC_NET_REGIST:
+ return "IPC_NET_REGIST";
+ case IPC_NET_SUBSCRIBER_NUM:
+ return "IPC_NET_SUBSCRIBER_NUM";
+ case IPC_NET_BAND_SEL:
+ return "IPC_NET_BAND_SEL";
+ case IPC_NET_SERVICE_DOMAIN_CONFIG:
+ return "IPC_NET_SERVICE_DOMAIN_CONFIG";
+ case IPC_NET_POWERON_ATTACH:
+ return "IPC_NET_POWERON_ATTACH";
+ case IPC_NET_MODE_SEL:
+ return "IPC_NET_MODE_SEL";
+ case IPC_NET_ACQ_ORDER:
+ return "IPC_NET_ACQ_ORDER";
+ case IPC_NET_IDENTITY:
+ return "IPC_NET_IDENTITY";
+ case IPC_NET_PREFERRED_NETWORK_INFO:
+ return "IPC_NET_PREFERRED_NETWORK_INFO";
+ case IPC_SND_SPKR_VOLUME_CTRL:
+ return "IPC_SND_SPKR_VOLUME_CTRL";
+ case IPC_SND_MIC_MUTE_CTRL:
+ return "IPC_SND_MIC_MUTE_CTRL";
+ case IPC_SND_AUDIO_PATH_CTRL:
+ return "IPC_SND_AUDIO_PATH_CTRL";
+ case IPC_SND_AUDIO_SOURCE_CTRL:
+ return "IPC_SND_AUDIO_SOURCE_CTRL";
+ case IPC_SND_LOOPBACK_CTRL:
+ return "IPC_SND_LOOPBACK_CTRL";
+ case IPC_SND_VOICE_RECORDING_CTRL:
+ return "IPC_SND_VOICE_RECORDING_CTRL";
+ case IPC_SND_VIDEO_CALL_CTRL:
+ return "IPC_SND_VIDEO_CALL_CTRL";
+ case IPC_SND_RINGBACK_TONE_CTRL:
+ return "IPC_SND_RINGBACK_TONE_CTRL";
+ case IPC_SND_CLOCK_CTRL:
+ return "IPC_SND_CLOCK_CTRL";
+ case IPC_SND_WB_AMR_STATUS:
+ return "IPC_SND_WB_AMR_STATUS";
+ case IPC_MISC_ME_VERSION:
+ return "IPC_MISC_ME_VERSION";
+ case IPC_MISC_ME_IMSI:
+ return "IPC_MISC_ME_IMSI";
+ case IPC_MISC_ME_SN:
+ return "IPC_MISC_ME_SN";
+ case IPC_MISC_TIME_INFO:
+ return "IPC_MISC_TIME_INFO";
+ case IPC_MISC_DEBUG_LEVEL:
+ return "IPC_MISC_DEBUG_LEVEL";
+ case IPC_SVC_ENTER:
+ return "IPC_SVC_ENTER";
+ case IPC_SVC_END:
+ return "IPC_SVC_END";
+ case IPC_SVC_PRO_KEYCODE:
+ return "IPC_SVC_PRO_KEYCODE";
+ case IPC_SVC_SCREEN_CFG:
+ return "IPC_SVC_SCREEN_CFG";
+ case IPC_SVC_DISPLAY_SCREEN:
+ return "IPC_SVC_DISPLAY_SCREEN";
+ case IPC_SVC_CHANGE_SVC_MODE:
+ return "IPC_SVC_CHANGE_SVC_MODE";
+ case IPC_SVC_DEVICE_TEST:
+ return "IPC_SVC_DEVICE_TEST";
+ case IPC_SVC_DEBUG_DUMP:
+ return "IPC_SVC_DEBUG_DUMP";
+ case IPC_SVC_DEBUG_STRING:
+ return "IPC_SVC_DEBUG_STRING";
+ case IPC_SS_WAITING:
+ return "IPC_SS_WAITING";
+ case IPC_SS_CLI:
+ return "IPC_SS_CLI";
+ case IPC_SS_BARRING:
+ return "IPC_SS_BARRING";
+ case IPC_SS_BARRING_PW:
+ return "IPC_SS_BARRING_PW";
+ case IPC_SS_FORWARDING:
+ return "IPC_SS_FORWARDING";
+ case IPC_SS_INFO:
+ return "IPC_SS_INFO";
+ case IPC_SS_MANAGE_CALL:
+ return "IPC_SS_MANAGE_CALL";
+ case IPC_SS_USSD:
+ return "IPC_SS_USSD";
+ case IPC_SS_AOC:
+ return "IPC_SS_AOC";
+ case IPC_SS_RELEASE_COMPLETE:
+ return "IPC_SS_RELEASE_COMPLETE";
+ case IPC_GPRS_DEFINE_PDP_CONTEXT:
+ return "IPC_GPRS_DEFINE_PDP_CONTEXT";
+ case IPC_GPRS_QOS:
+ return "IPC_GPRS_QOS";
+ case IPC_GPRS_PS:
+ return "IPC_GPRS_PS";
+ case IPC_GPRS_PDP_CONTEXT:
+ return "IPC_GPRS_PDP_CONTEXT";
+ case IPC_GPRS_ENTER_DATA:
+ return "IPC_GPRS_ENTER_DATA";
+ case IPC_GPRS_SHOW_PDP_ADDR:
+ return "IPC_GPRS_SHOW_PDP_ADDR";
+ case IPC_GPRS_MS_CLASS:
+ return "IPC_GPRS_MS_CLASS";
+ case IPC_GPRS_3G_QUAL_SRVC_PROFILE:
+ return "IPC_GPRS_3G_QUAL_SRVC_PROFILE";
+ case IPC_GPRS_IP_CONFIGURATION:
+ return "IPC_GPRS_IP_CONFIGURATION";
+ case IPC_GPRS_DEFINE_SEC_PDP_CONTEXT:
+ return "IPC_GPRS_DEFINE_SEC_PDP_CONTEXT";
+ case IPC_GPRS_TFT:
+ return "IPC_GPRS_TFT";
+ case IPC_GPRS_HSDPA_STATUS:
+ return "IPC_GPRS_HSDPA_STATUS";
+ case IPC_GPRS_CURRENT_SESSION_DATA_COUNTER:
+ return "IPC_GPRS_CURRENT_SESSION_DATA_COUNTER";
+ case IPC_GPRS_DATA_DORMANT:
+ return "IPC_GPRS_DATA_DORMANT";
+ case IPC_GPRS_PIN_CTRL:
+ return "IPC_GPRS_PIN_CTRL";
+ case IPC_GPRS_CALL_STATUS:
+ return "IPC_GPRS_CALL_STATUS";
+ case IPC_GPRS_PORT_LIST:
+ return "IPC_GPRS_PORT_LIST";
+ case IPC_SAT_PROFILE_DOWNLOAD:
+ return "IPC_SAT_PROFILE_DOWNLOAD";
+ case IPC_SAT_ENVELOPE_CMD:
+ return "IPC_SAT_ENVELOPE_CMD";
+ case IPC_SAT_PROACTIVE_CMD:
+ return "IPC_SAT_PROACTIVE_CMD";
+ case IPC_SAT_TERMINATE_USAT_SESSION:
+ return "IPC_SAT_TERMINATE_USAT_SESSION";
+ case IPC_SAT_EVENT_DOWNLOAD:
+ return "IPC_SAT_EVENT_DOWNLOAD";
+ case IPC_SAT_PROVIDE_LOCAL_INFO:
+ return "IPC_SAT_PROVIDE_LOCAL_INFO";
+ case IPC_SAT_POLLING:
+ return "IPC_SAT_POLLING";
+ case IPC_SAT_REFRESH:
+ return "IPC_SAT_REFRESH";
+ case IPC_SAT_SETUP_EVENT_LIST:
+ return "IPC_SAT_SETUP_EVENT_LIST";
+ case IPC_SAT_CALL_CONTROL_RESULT:
+ return "IPC_SAT_CALL_CONTROL_RESULT";
+ case IPC_SAT_IMAGE_CLUT:
+ return "IPC_SAT_IMAGE_CLUT";
+ case IPC_SAT_SETUP_CALL_PROCESSING:
+ return "IPC_SAT_SETUP_CALL_PROCESSING";
+ case IPC_IMEI_START:
+ return "IPC_IMEI_START";
+ case IPC_IMEI_CHECK_DEVICE_INFO:
+ return "IPC_IMEI_CHECK_DEVICE_INFO";
+ case IPC_RFS_NV_READ_ITEM:
+ return "IPC_RFS_NV_READ_ITEM";
+ case IPC_RFS_NV_WRITE_ITEM:
+ return "IPC_RFS_NV_WRITE_ITEM";
+ case IPC_GEN_PHONE_RES:
+ return "IPC_GEN_PHONE_RES";
+ default:
+ snprintf((char *) &command_string, sizeof(command_string),
+ "0x%04x", command);
+ return command_string;
+ }
+}
+
+const char *ipc_group_string(unsigned char group)
+{
+ static char group_string[5] = { 0 };
+
+ switch (group) {
+ case IPC_GROUP_PWR:
+ return "IPC_GROUP_PWR";
+ case IPC_GROUP_CALL:
+ return "IPC_GROUP_CALL";
+ case IPC_GROUP_SMS:
+ return "IPC_GROUP_SMS";
+ case IPC_GROUP_SEC:
+ return "IPC_GROUP_SEC";
+ case IPC_GROUP_PB:
+ return "IPC_GROUP_PB";
+ case IPC_GROUP_DISP:
+ return "IPC_GROUP_DISP";
+ case IPC_GROUP_NET:
+ return "IPC_GROUP_NET";
+ case IPC_GROUP_SND:
+ return "IPC_GROUP_SND";
+ case IPC_GROUP_MISC:
+ return "IPC_GROUP_MISC";
+ case IPC_GROUP_SVC:
+ return "IPC_GROUP_SVC";
+ case IPC_GROUP_SS:
+ return "IPC_GROUP_SS";
+ case IPC_GROUP_GPRS:
+ return "IPC_GROUP_GPRS";
+ case IPC_GROUP_SAT:
+ return "IPC_GROUP_SAT";
+ case IPC_GROUP_CFG:
+ return "IPC_GROUP_CFG";
+ case IPC_GROUP_IMEI:
+ return "IPC_GROUP_IMEI";
+ case IPC_GROUP_GPS:
+ return "IPC_GROUP_GPS";
+ case IPC_GROUP_SAP:
+ return "IPC_GROUP_SAP";
+ case IPC_GROUP_RFS:
+ return "IPC_GROUP_RFS";
+ case IPC_GROUP_GEN:
+ return "IPC_GROUP_GEN";
+ default:
+ snprintf((char *) &group_string, sizeof(group_string), "0x%02x",
+ (unsigned int)group);
+ return group_string;
+ }
+}
+
+const char *ipc_client_type_string(unsigned char client_type)
+{
+ static char client_type_string[5] = { 0 };
+
+ switch (client_type) {
+ case IPC_CLIENT_TYPE_FMT:
+ return "FMT";
+ case IPC_CLIENT_TYPE_RFS:
+ return "RFS";
+ case IPC_CLIENT_TYPE_DUMMY:
+ return "DUMMY";
+ default:
+ snprintf((char *) &client_type_string,
+ sizeof(client_type_string),
+ "0x%02x",
+ client_type);
+ return client_type_string;
+ }
+}
diff --git a/samsung-ipc/ipc_utils.c b/samsung-ipc/ipc_utils.c
index d8b69b7..3518475 100644
--- a/samsung-ipc/ipc_utils.c
+++ b/samsung-ipc/ipc_utils.c
@@ -41,322 +41,6 @@ int ipc_seq_valid(unsigned char seq)
return 1;
}
-const char *ipc_request_type_string(unsigned char type)
-{
- static char type_string[5] = { 0 };
-
- switch (type) {
- case IPC_TYPE_EXEC:
- return "IPC_TYPE_EXEC";
- case IPC_TYPE_GET:
- return "IPC_TYPE_GET";
- case IPC_TYPE_SET:
- return "IPC_TYPE_SET";
- case IPC_TYPE_CFRM:
- return "IPC_TYPE_CFRM";
- case IPC_TYPE_EVENT:
- return "IPC_TYPE_EVENT";
- default:
- snprintf((char *) &type_string, sizeof(type_string), "0x%02x",
- type);
- return type_string;
- }
-}
-
-const char *ipc_response_type_string(unsigned char type)
-{
- static char type_string[5] = { 0 };
-
- switch (type) {
- case IPC_TYPE_INDI:
- return "IPC_TYPE_INDI";
- case IPC_TYPE_RESP:
- return "IPC_TYPE_RESP";
- case IPC_TYPE_NOTI:
- return "IPC_TYPE_NOTI";
- default:
- snprintf((char *) &type_string, sizeof(type_string), "0x%02x",
- type);
- return type_string;
- }
-}
-
-const char *ipc_command_string(unsigned short command)
-{
- static char command_string[7] = { 0 };
-
- switch (command) {
- case IPC_PWR_PHONE_PWR_UP:
- return "IPC_PWR_PHONE_PWR_UP";
- case IPC_PWR_PHONE_PWR_OFF:
- return "IPC_PWR_PHONE_PWR_OFF";
- case IPC_PWR_PHONE_RESET:
- return "IPC_PWR_PHONE_RESET";
- case IPC_PWR_BATT_STATUS:
- return "IPC_PWR_BATT_STATUS";
- case IPC_PWR_BATT_TYPE:
- return "IPC_PWR_BATT_TYPE";
- case IPC_PWR_BATT_COMP:
- return "IPC_PWR_BATT_COMP";
- case IPC_PWR_PHONE_STATE:
- return "IPC_PWR_PHONE_STATE";
- case IPC_CALL_OUTGOING:
- return "IPC_CALL_OUTGOING";
- case IPC_CALL_INCOMING:
- return "IPC_CALL_INCOMING";
- case IPC_CALL_RELEASE:
- return "IPC_CALL_RELEASE";
- case IPC_CALL_ANSWER:
- return "IPC_CALL_ANSWER";
- case IPC_CALL_STATUS:
- return "IPC_CALL_STATUS";
- case IPC_CALL_LIST:
- return "IPC_CALL_LIST";
- case IPC_CALL_BURST_DTMF:
- return "IPC_CALL_BURST_DTMF";
- case IPC_CALL_CONT_DTMF:
- return "IPC_CALL_CONT_DTMF";
- case IPC_CALL_WAITING:
- return "IPC_CALL_WAITING";
- case IPC_CALL_LINE_ID:
- return "IPC_CALL_LINE_ID";
- case IPC_SMS_SEND_MSG:
- return "IPC_SMS_SEND_MSG";
- case IPC_SMS_INCOMING_MSG:
- return "IPC_SMS_INCOMING_MSG";
- case IPC_SMS_READ_MSG:
- return "IPC_SMS_READ_MSG";
- case IPC_SMS_SAVE_MSG:
- return "IPC_SMS_SAVE_MSG";
- case IPC_SMS_DEL_MSG:
- return "IPC_SMS_DEL_MSG";
- case IPC_SMS_DELIVER_REPORT:
- return "IPC_SMS_DELIVER_REPORT";
- case IPC_SMS_DEVICE_READY:
- return "IPC_SMS_DEVICE_READY";
- case IPC_SMS_SEL_MEM:
- return "IPC_SMS_SEL_MEM";
- case IPC_SMS_STORED_MSG_COUNT:
- return "IPC_SMS_STORED_MSG_COUNT";
- case IPC_SMS_SVC_CENTER_ADDR:
- return "IPC_SMS_SVC_CENTER_ADDR";
- case IPC_SMS_SVC_OPTION:
- return "IPC_SMS_SVC_OPTION";
- case IPC_SMS_MEM_STATUS:
- return "IPC_SMS_MEM_STATUS";
- case IPC_SMS_CBS_MSG:
- return "IPC_SMS_CBS_MSG";
- case IPC_SMS_CBS_CFG:
- return "IPC_SMS_CBS_CFG";
- case IPC_SMS_STORED_MSG_STATUS:
- return "IPC_SMS_STORED_MSG_STATUS";
- case IPC_SMS_PARAM_COUNT:
- return "IPC_SMS_PARAM_COUNT";
- case IPC_SMS_PARAM:
- return "IPC_SMS_PARAM";
- case IPC_SEC_PIN_STATUS:
- return "IPC_SEC_PIN_STATUS";
- case IPC_SEC_PHONE_LOCK:
- return "IPC_SEC_PHONE_LOCK";
- case IPC_SEC_CHANGE_LOCKING_PW:
- return "IPC_SEC_CHANGE_LOCKING_PW";
- case IPC_SEC_SIM_LANG:
- return "IPC_SEC_SIM_LANG";
- case IPC_SEC_RSIM_ACCESS:
- return "IPC_SEC_RSIM_ACCESS";
- case IPC_SEC_GSIM_ACCESS:
- return "IPC_SEC_GSIM_ACCESS";
- case IPC_SEC_SIM_ICC_TYPE:
- return "IPC_SEC_SIM_ICC_TYPE";
- case IPC_SEC_LOCK_INFORMATION:
- return "IPC_SEC_LOCK_INFORMATION";
- case IPC_SEC_IMS_AUTH:
- return "IPC_SEC_IMS_AUTH";
- case IPC_PB_ACCESS:
- return "IPC_PB_ACCESS";
- case IPC_PB_STORAGE:
- return "IPC_PB_STORAGE";
- case IPC_PB_STORAGE_LIST:
- return "IPC_PB_STORAGE_LIST";
- case IPC_PB_ENTRY_INFO:
- return "IPC_PB_ENTRY_INFO";
- case IPC_PB_3GPB_CAPA:
- return "IPC_PB_3GPB_CAPA";
- case IPC_DISP_ICON_INFO:
- return "IPC_DISP_ICON_INFO";
- case IPC_DISP_HOMEZONE_INFO:
- return "IPC_DISP_HOMEZONE_INFO";
- case IPC_DISP_RSSI_INFO:
- return "IPC_DISP_RSSI_INFO";
- case IPC_NET_PREF_PLMN:
- return "IPC_NET_PREF_PLMN";
- case IPC_NET_PLMN_SEL:
- return "IPC_NET_PLMN_SEL";
- case IPC_NET_SERVING_NETWORK:
- return "IPC_NET_SERVING_NETWORK";
- case IPC_NET_PLMN_LIST:
- return "IPC_NET_PLMN_LIST";
- case IPC_NET_REGIST:
- return "IPC_NET_REGIST";
- case IPC_NET_SUBSCRIBER_NUM:
- return "IPC_NET_SUBSCRIBER_NUM";
- case IPC_NET_BAND_SEL:
- return "IPC_NET_BAND_SEL";
- case IPC_NET_SERVICE_DOMAIN_CONFIG:
- return "IPC_NET_SERVICE_DOMAIN_CONFIG";
- case IPC_NET_POWERON_ATTACH:
- return "IPC_NET_POWERON_ATTACH";
- case IPC_NET_MODE_SEL:
- return "IPC_NET_MODE_SEL";
- case IPC_NET_ACQ_ORDER:
- return "IPC_NET_ACQ_ORDER";
- case IPC_NET_IDENTITY:
- return "IPC_NET_IDENTITY";
- case IPC_NET_PREFERRED_NETWORK_INFO:
- return "IPC_NET_PREFERRED_NETWORK_INFO";
- case IPC_SND_SPKR_VOLUME_CTRL:
- return "IPC_SND_SPKR_VOLUME_CTRL";
- case IPC_SND_MIC_MUTE_CTRL:
- return "IPC_SND_MIC_MUTE_CTRL";
- case IPC_SND_AUDIO_PATH_CTRL:
- return "IPC_SND_AUDIO_PATH_CTRL";
- case IPC_SND_AUDIO_SOURCE_CTRL:
- return "IPC_SND_AUDIO_SOURCE_CTRL";
- case IPC_SND_LOOPBACK_CTRL:
- return "IPC_SND_LOOPBACK_CTRL";
- case IPC_SND_VOICE_RECORDING_CTRL:
- return "IPC_SND_VOICE_RECORDING_CTRL";
- case IPC_SND_VIDEO_CALL_CTRL:
- return "IPC_SND_VIDEO_CALL_CTRL";
- case IPC_SND_RINGBACK_TONE_CTRL:
- return "IPC_SND_RINGBACK_TONE_CTRL";
- case IPC_SND_CLOCK_CTRL:
- return "IPC_SND_CLOCK_CTRL";
- case IPC_SND_WB_AMR_STATUS:
- return "IPC_SND_WB_AMR_STATUS";
- case IPC_MISC_ME_VERSION:
- return "IPC_MISC_ME_VERSION";
- case IPC_MISC_ME_IMSI:
- return "IPC_MISC_ME_IMSI";
- case IPC_MISC_ME_SN:
- return "IPC_MISC_ME_SN";
- case IPC_MISC_TIME_INFO:
- return "IPC_MISC_TIME_INFO";
- case IPC_MISC_DEBUG_LEVEL:
- return "IPC_MISC_DEBUG_LEVEL";
- case IPC_SVC_ENTER:
- return "IPC_SVC_ENTER";
- case IPC_SVC_END:
- return "IPC_SVC_END";
- case IPC_SVC_PRO_KEYCODE:
- return "IPC_SVC_PRO_KEYCODE";
- case IPC_SVC_SCREEN_CFG:
- return "IPC_SVC_SCREEN_CFG";
- case IPC_SVC_DISPLAY_SCREEN:
- return "IPC_SVC_DISPLAY_SCREEN";
- case IPC_SVC_CHANGE_SVC_MODE:
- return "IPC_SVC_CHANGE_SVC_MODE";
- case IPC_SVC_DEVICE_TEST:
- return "IPC_SVC_DEVICE_TEST";
- case IPC_SVC_DEBUG_DUMP:
- return "IPC_SVC_DEBUG_DUMP";
- case IPC_SVC_DEBUG_STRING:
- return "IPC_SVC_DEBUG_STRING";
- case IPC_SS_WAITING:
- return "IPC_SS_WAITING";
- case IPC_SS_CLI:
- return "IPC_SS_CLI";
- case IPC_SS_BARRING:
- return "IPC_SS_BARRING";
- case IPC_SS_BARRING_PW:
- return "IPC_SS_BARRING_PW";
- case IPC_SS_FORWARDING:
- return "IPC_SS_FORWARDING";
- case IPC_SS_INFO:
- return "IPC_SS_INFO";
- case IPC_SS_MANAGE_CALL:
- return "IPC_SS_MANAGE_CALL";
- case IPC_SS_USSD:
- return "IPC_SS_USSD";
- case IPC_SS_AOC:
- return "IPC_SS_AOC";
- case IPC_SS_RELEASE_COMPLETE:
- return "IPC_SS_RELEASE_COMPLETE";
- case IPC_GPRS_DEFINE_PDP_CONTEXT:
- return "IPC_GPRS_DEFINE_PDP_CONTEXT";
- case IPC_GPRS_QOS:
- return "IPC_GPRS_QOS";
- case IPC_GPRS_PS:
- return "IPC_GPRS_PS";
- case IPC_GPRS_PDP_CONTEXT:
- return "IPC_GPRS_PDP_CONTEXT";
- case IPC_GPRS_ENTER_DATA:
- return "IPC_GPRS_ENTER_DATA";
- case IPC_GPRS_SHOW_PDP_ADDR:
- return "IPC_GPRS_SHOW_PDP_ADDR";
- case IPC_GPRS_MS_CLASS:
- return "IPC_GPRS_MS_CLASS";
- case IPC_GPRS_3G_QUAL_SRVC_PROFILE:
- return "IPC_GPRS_3G_QUAL_SRVC_PROFILE";
- case IPC_GPRS_IP_CONFIGURATION:
- return "IPC_GPRS_IP_CONFIGURATION";
- case IPC_GPRS_DEFINE_SEC_PDP_CONTEXT:
- return "IPC_GPRS_DEFINE_SEC_PDP_CONTEXT";
- case IPC_GPRS_TFT:
- return "IPC_GPRS_TFT";
- case IPC_GPRS_HSDPA_STATUS:
- return "IPC_GPRS_HSDPA_STATUS";
- case IPC_GPRS_CURRENT_SESSION_DATA_COUNTER:
- return "IPC_GPRS_CURRENT_SESSION_DATA_COUNTER";
- case IPC_GPRS_DATA_DORMANT:
- return "IPC_GPRS_DATA_DORMANT";
- case IPC_GPRS_PIN_CTRL:
- return "IPC_GPRS_PIN_CTRL";
- case IPC_GPRS_CALL_STATUS:
- return "IPC_GPRS_CALL_STATUS";
- case IPC_GPRS_PORT_LIST:
- return "IPC_GPRS_PORT_LIST";
- case IPC_SAT_PROFILE_DOWNLOAD:
- return "IPC_SAT_PROFILE_DOWNLOAD";
- case IPC_SAT_ENVELOPE_CMD:
- return "IPC_SAT_ENVELOPE_CMD";
- case IPC_SAT_PROACTIVE_CMD:
- return "IPC_SAT_PROACTIVE_CMD";
- case IPC_SAT_TERMINATE_USAT_SESSION:
- return "IPC_SAT_TERMINATE_USAT_SESSION";
- case IPC_SAT_EVENT_DOWNLOAD:
- return "IPC_SAT_EVENT_DOWNLOAD";
- case IPC_SAT_PROVIDE_LOCAL_INFO:
- return "IPC_SAT_PROVIDE_LOCAL_INFO";
- case IPC_SAT_POLLING:
- return "IPC_SAT_POLLING";
- case IPC_SAT_REFRESH:
- return "IPC_SAT_REFRESH";
- case IPC_SAT_SETUP_EVENT_LIST:
- return "IPC_SAT_SETUP_EVENT_LIST";
- case IPC_SAT_CALL_CONTROL_RESULT:
- return "IPC_SAT_CALL_CONTROL_RESULT";
- case IPC_SAT_IMAGE_CLUT:
- return "IPC_SAT_IMAGE_CLUT";
- case IPC_SAT_SETUP_CALL_PROCESSING:
- return "IPC_SAT_SETUP_CALL_PROCESSING";
- case IPC_IMEI_START:
- return "IPC_IMEI_START";
- case IPC_IMEI_CHECK_DEVICE_INFO:
- return "IPC_IMEI_CHECK_DEVICE_INFO";
- case IPC_RFS_NV_READ_ITEM:
- return "IPC_RFS_NV_READ_ITEM";
- case IPC_RFS_NV_WRITE_ITEM:
- return "IPC_RFS_NV_WRITE_ITEM";
- case IPC_GEN_PHONE_RES:
- return "IPC_GEN_PHONE_RES";
- default:
- snprintf((char *) &command_string, sizeof(command_string),
- "0x%04x", command);
- return command_string;
- }
-}
-
int ipc_data_dump(struct ipc_client *client, const void *data, size_t size)
{
unsigned int cols = 8;
diff --git a/samsung-ipc/modems/Makefile.am b/samsung-ipc/modems/Makefile.am
new file mode 100644
index 0000000..f59258a
--- /dev/null
+++ b/samsung-ipc/modems/Makefile.am
@@ -0,0 +1,15 @@
+libsamsung_ipc_la_SOURCES += \
+ modems/xmm616/xmm616.c \
+ modems/xmm616/xmm616.h \
+ modems/xmm626/xmm626.c \
+ modems/xmm626/xmm626.h \
+ modems/xmm626/xmm626_hsic.c \
+ modems/xmm626/xmm626_hsic.h \
+ modems/xmm626/xmm626_kernel_smdk4412.c \
+ modems/xmm626/xmm626_kernel_smdk4412.h \
+ modems/xmm626/xmm626_mipi.c \
+ modems/xmm626/xmm626_mipi.h \
+ modems/xmm626/xmm626_modem_if.h \
+ modems/xmm626/xmm626_modem_link_device_hsic.h \
+ modems/xmm626/xmm626_modem_prj.h \
+ $(NULL)
diff --git a/samsung-ipc/modems/xmm626/xmm626_kernel_smdk4412.c b/samsung-ipc/modems/xmm626/xmm626_kernel_smdk4412.c
index c6b1578..cdac3e4 100644
--- a/samsung-ipc/modems/xmm626/xmm626_kernel_smdk4412.c
+++ b/samsung-ipc/modems/xmm626/xmm626_kernel_smdk4412.c
@@ -19,11 +19,13 @@
*/
#define _GNU_SOURCE
-#include <stdlib.h>
+
+#include <fcntl.h>
#include <stdio.h>
-#include <unistd.h>
+#include <stdlib.h>
#include <string.h>
-#include <fcntl.h>
+#include <unistd.h>
+
#include <sys/ioctl.h>
#include <sys/select.h>
@@ -582,11 +584,17 @@ char *xmm626_kernel_smdk4412_gprs_get_iface(
__attribute__((unused)) struct ipc_client *client, unsigned int cid)
{
char *iface = NULL;
+ int rc;
if (cid > XMM626_SEC_MODEM_GPRS_IFACE_COUNT)
return NULL;
- asprintf(&iface, "%s%d", XMM626_SEC_MODEM_GPRS_IFACE_PREFIX, cid - 1);
+ rc = asprintf(&iface, "%s%d",
+ XMM626_SEC_MODEM_GPRS_IFACE_PREFIX, cid - 1);
+ if (rc == -1) {
+ ipc_client_log(client, "%s: asprintf failed", __func__);
+ return NULL;
+ }
return iface;
}
diff --git a/samsung-ipc/partitions/Makefile.am b/samsung-ipc/partitions/Makefile.am
new file mode 100644
index 0000000..5248869
--- /dev/null
+++ b/samsung-ipc/partitions/Makefile.am
@@ -0,0 +1,6 @@
+libsamsung_ipc_la_SOURCES += \
+ partitions/android/android.c \
+ partitions/android/android.h \
+ partitions/toc/toc.c \
+ partitions/toc/toc.h \
+ $(NULL)
diff --git a/samsung-ipc/partitions/android/android.c b/samsung-ipc/partitions/android/android.c
new file mode 100644
index 0000000..9d2322f
--- /dev/null
+++ b/samsung-ipc/partitions/android/android.c
@@ -0,0 +1,118 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ * Copyright (C) 2020 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
+ * 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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <samsung-ipc.h>
+
+static char const * const partitions_dirnames[] = {
+ "/dev/disk/by-partlabel/", /* GNU/Linux */
+ "/dev/block/by-name/", /* Android */
+ NULL
+};
+
+int open_android_modem_partition(struct ipc_client *client,
+ char const * const *path_names)
+{
+ int i;
+
+ for (i = 0; path_names[i] != NULL; i++) {
+ char const * const path = path_names[i];
+ int fd;
+
+ ipc_client_log(client, "%s: Trying to open %s",
+ __func__, path);
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ if (errno == ENOENT)
+ continue;
+ /* Normally errno should be passed to the caller here */
+ return -1;
+ }
+ return fd;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+int open_android_modem_partition_by_name(struct ipc_client *client,
+ const char *name, char **out_path)
+{
+ int i;
+ int rc;
+
+ for (i = 0; partitions_dirnames[i] != NULL; i++) {
+ char *path = NULL;
+ int fd;
+ size_t len;
+
+ len = strlen(partitions_dirnames[i]) + strlen(name) + 1;
+ path = calloc(1, len);
+ if (path == NULL) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: calloc failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ return -errno;
+ }
+
+ strcpy(path, partitions_dirnames[i]);
+ strcat(path, name);
+
+ ipc_client_log(client, "%s: Trying to open %s",
+ __func__, path);
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ rc = -errno;
+ if (out_path)
+ *out_path = path;
+ else
+ free(path);
+
+ if (rc == -ENOENT)
+ continue;
+
+ errno = -rc;
+ return -1;
+ }
+
+ if (out_path)
+ *out_path = path;
+ else
+ free(path);
+
+ return fd;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
diff --git a/samsung-ipc/partitions/android/android.h b/samsung-ipc/partitions/android/android.h
new file mode 100644
index 0000000..e2f23f7
--- /dev/null
+++ b/samsung-ipc/partitions/android/android.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ * Copyright (C) 2020 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
+ * 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 __ANDROID_PARTITIONS_H__
+#define __ANDROID_PARTITIONS_H__
+int open_android_modem_partition(struct ipc_client *client,
+ char const * const *path_names);
+int open_android_modem_partition_by_name(struct ipc_client *client,
+ const char *name, char **out_path);
+#endif /* __ANDROID_PARTITIONS_H__ */
diff --git a/samsung-ipc/partitions/toc/toc.c b/samsung-ipc/partitions/toc/toc.c
new file mode 100644
index 0000000..ec62ea9
--- /dev/null
+++ b/samsung-ipc/partitions/toc/toc.c
@@ -0,0 +1,44 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2020 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
+ *
+ * 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 <stddef.h>
+#include <string.h>
+
+#include "toc.h"
+
+struct firmware_toc_entry const *find_toc_entry(
+ char const *name,
+ struct firmware_toc_entry const *toc)
+{
+ unsigned int index;
+
+ /* We don't know all the details of the TOC format yet; for now, we
+ * assume two things:
+ * 1. reading 512 bytes of TOC is enough, and
+ * 2. the first entry with an empty name field ends the list.
+ */
+ for (index = 0; index < N_TOC_ENTRIES; index++) {
+ if (toc[index].name[0] == '\0')
+ break;
+ if (strncmp(toc[index].name, name,
+ sizeof(toc[index].name)) == 0)
+ return &toc[index];
+ }
+ return NULL;
+}
diff --git a/samsung-ipc/partitions/toc/toc.h b/samsung-ipc/partitions/toc/toc.h
new file mode 100644
index 0000000..416a45f
--- /dev/null
+++ b/samsung-ipc/partitions/toc/toc.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2020 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
+ * 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 __TOC_PARTITION_TABLE_H__
+#define __TOC_PARTITION_TABLE_H__
+
+#include <stdint.h>
+
+struct __attribute__((__packed__)) firmware_toc_entry {
+ char name[12];
+ uint32_t offset; /* offset within firmware file/partition */
+ uint32_t loadaddr; /* target memory address for this blob */
+ uint32_t size; /* size of this blob in bytes */
+ uint32_t crc;
+ uint32_t entryid;
+};
+
+#define N_TOC_ENTRIES (512 / sizeof(struct firmware_toc_entry))
+
+struct firmware_toc_entry const *find_toc_entry(
+ char const *name,
+ struct firmware_toc_entry const *toc);
+
+#endif /* __TOC_PARTITION_TABLE_H__ */
diff --git a/samsung-ipc/rfs.c b/samsung-ipc/rfs.c
index 114df99..c9cee1b 100644
--- a/samsung-ipc/rfs.c
+++ b/samsung-ipc/rfs.c
@@ -32,20 +32,40 @@
#include "ipc.h"
+#define MD5_DIGEST_LENGTH_ASCII (2 * MD5_DIGEST_LENGTH)
+
char *ipc_nv_data_md5_calculate(struct ipc_client *client,
const char *path, const char *secret,
size_t size, size_t chunk_size)
{
+ struct stat st;
void *data = NULL;
char *md5_string = NULL;
unsigned char md5_hash[MD5_DIGEST_LENGTH] = { 0 };
MD5_CTX ctx;
+ int rc;
if (secret == NULL) {
ipc_client_log(client, "%s: Failed: secret is NULL", __func__);
return NULL;
}
+ rc = stat(path, &st);
+ if (rc == -1) {
+ rc = errno;
+ ipc_client_log(client, "%s: stat failed with error %d",
+ __func__, rc, strerror(rc));
+ return NULL;
+ }
+
+ if ((unsigned long)st.st_size != size) {
+ ipc_client_log(client,
+ "%s: Checking %s size failed: "
+ "requested size: %d, file size: %d\n",
+ __func__, path, size, st.st_size);
+ return NULL;
+ }
+
data = file_data_read(client, path, size, chunk_size, 0);
if (data == NULL) {
ipc_client_log(client, "%s failed: data is NULL", __func__);
@@ -112,7 +132,7 @@ int ipc_nv_data_md5_path_check(struct ipc_client *client)
return -1;
}
- if (st.st_size < 2 * sizeof(char) * MD5_DIGEST_LENGTH) {
+ if (st.st_size != MD5_DIGEST_LENGTH_ASCII) {
ipc_client_log(client, "Checking nv_data md5 size failed");
return -1;
}
@@ -173,7 +193,7 @@ int ipc_nv_data_backup_md5_path_check(struct ipc_client *client)
return -1;
}
- if (st.st_size < 2 * sizeof(char) * MD5_DIGEST_LENGTH) {
+ if (st.st_size != MD5_DIGEST_LENGTH_ASCII) {
ipc_client_log(client,
"Checking nv_data backup md5 size failed");
return -1;
@@ -493,7 +513,7 @@ int ipc_nv_data_restore(struct ipc_client *client)
free(data);
data = NULL;
- length = 2 * sizeof(char) * MD5_DIGEST_LENGTH;
+ length = MD5_DIGEST_LENGTH_ASCII;
data = file_data_read(client, backup_md5_path, length, length, 0);
if (data == NULL) {
diff --git a/samsung-ipc/tests/Makefile.am b/samsung-ipc/tests/Makefile.am
new file mode 100644
index 0000000..ad4280e
--- /dev/null
+++ b/samsung-ipc/tests/Makefile.am
@@ -0,0 +1,39 @@
+NULL =
+EXTRA_DIST = $(NULL)
+
+AM_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/samsung-ipc \
+ $(OPENSSL_CFLAGS) \
+ $(NULL)
+
+AM_LDFLAGS = $(ALL_STATIC_LDFLAGS)
+
+if WANT_STRICT_CFLAGS
+AM_CFLAGS += $(STRICT_CFLAGS)
+endif
+
+if WANT_DEBUG
+AM_CFLAGS += -DDEBUG
+endif
+
+bin_PROGRAMS = libsamsung-ipc-test
+
+libsamsung_ipc_test_SOURCES = \
+ main.c \
+ partitions/android.c \
+ partitions/android.h \
+ $(NULL)
+
+libsamsung_ipc_test_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la
+
+# TODO: Find a way to make test more modular and represent each run of
+# libsamsung-ipc-test in TEST while having it implemented in a single
+# python file
+if WANT_VALGRIND_CHECKING
+AM_TESTS_ENVIRONMENT = VALGRIND='$(VALGRIND)'; export VALGRIND;
+endif
+PY_LOG_COMPILER = $(PYTHON3)
+TEST_EXTENSIONS = .py
+TESTS = libsamsung-ipc-test.py
+EXTRA_DIST += $(TESTS)
diff --git a/samsung-ipc/tests/libsamsung-ipc-test.py b/samsung-ipc/tests/libsamsung-ipc-test.py
new file mode 100755
index 0000000..5435013
--- /dev/null
+++ b/samsung-ipc/tests/libsamsung-ipc-test.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+#
+# This file is part of libsamsung-ipc.
+#
+# Copyright (C) 2020 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/>.
+
+import os
+import re
+import sys
+import sh
+
+class libsamsung_ipc_test(object):
+ def __init__(self):
+ srcdir = os.environ.get('srcdir', None)
+
+ command_path = ''
+ if srcdir:
+ command_path = '.' + os.sep + 'libsamsung-ipc-test'
+ # Enable to run tests without automake
+ else:
+ command_path = os.path.dirname(sys.argv[0]) \
+ + os.sep \
+ + 'libsamsung-ipc-test'
+
+ if 'VALGRIND' in os.environ:
+ self.run = sh.Command(os.environ['VALGRIND'])
+ self.run = self.run.bake('-v',
+ '--log-file=valgrind.%p.log',
+ '--leak-check=full',
+ command_path)
+ else:
+ self.run = sh.Command(command_path)
+
+ def run_all_tests(self):
+ output = str(self.run('list-tests')).split(os.linesep)
+ # Remove the last line break from the output
+ output.remove('')
+
+ # Also Remove the first line from the output: We have an output like
+ # that:
+ # Available tests:
+ # [list of tests]
+ output.pop(0)
+
+ for test_name in output:
+ self.run('test', test_name.replace(' ', ''))
+
+def main():
+ tests = libsamsung_ipc_test()
+ tests.run_all_tests()
+
+if __name__ == '__main__':
+ main()
diff --git a/samsung-ipc/tests/main.c b/samsung-ipc/tests/main.c
new file mode 100644
index 0000000..ffb855d
--- /dev/null
+++ b/samsung-ipc/tests/main.c
@@ -0,0 +1,157 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2016 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include <samsung-ipc.h>
+
+/* libsamsung-ipc internal headers */
+#include <ipc.h>
+#include "partitions/android.h"
+
+struct test {
+ char *name;
+ int (*func)(struct ipc_client *client);
+};
+
+static struct test tests[] = {
+ {
+ "open_android_modem_partition",
+ test_open_android_modem_partition
+ },
+};
+
+static void usage(const char *progname)
+{
+ printf("Usage: %s list-tests\n", progname);
+ printf("Usage: %s test <test>\n", progname);
+}
+
+static void list_tests(void)
+{
+ unsigned int i;
+
+ printf("Available tests:\n");
+
+ for (i = 0; i < sizeof(tests) / sizeof(struct test); i++)
+ printf(" %s\n", tests[i].name);
+}
+
+static struct test *get_test(char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof(tests) / sizeof(struct test); i++) {
+ if (!strcmp(tests[i].name, name))
+ return &(tests[i]);
+ }
+
+ return NULL;
+}
+
+static void log_callback(__attribute__((unused)) void *data,
+ __attribute__((unused)) const char *message)
+{
+ /* TODO: add better logging mechanism in libsamsung-ipc with
+ * tags and log levels which would enable to filter the
+ * messages from different provenance (this file, the code
+ * under test, other parts of libsamsung-ipc, etc).
+ */
+#ifdef DEBUG
+ char *buffer;
+ size_t length;
+ int i;
+
+ if (message == NULL)
+ return;
+
+ buffer = strdup(message);
+ length = strlen(message);
+
+ for (i = length; i > 0; i--) {
+ if (buffer[i] == '\n')
+ buffer[i] = '\0';
+ else if (buffer[i] != '\0')
+ break;
+ }
+
+ printf("[ipc] %s\n", buffer);
+
+ free(buffer);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ struct ipc_client *client = NULL;
+ const char *progname = "libsamsung-ipc-test";
+ char *given_test_name;
+ struct test *test;
+ int rc = 0;
+
+ if (argc == 2 && !strcmp("list-tests", argv[1])) {
+ list_tests();
+ return 0;
+ } else if (argc == 3 && !strcmp("test", argv[1])) {
+ given_test_name = argv[2];
+ } else {
+ usage(progname);
+ return EX_USAGE;
+ }
+
+ test = get_test(given_test_name);
+ if (test == NULL) {
+ printf("Unknown test %s\n", given_test_name);
+ return EX_USAGE;
+ }
+
+ client = ipc_client_create(IPC_CLIENT_TYPE_DUMMY);
+ if (client == NULL) {
+ printf("[ !! ] Creating client failed\n");
+ goto error;
+ }
+
+ rc = ipc_client_log_callback_register(client, log_callback, NULL);
+ if (rc < 0) {
+ printf("[ !! ] Registering log callback failed: error %d\n",
+ rc);
+ goto error;
+ }
+
+ rc = test->func(client);
+ if (rc == 0) {
+ printf("[ OK ] %s succedded\n", test->name);
+ } else {
+ printf("[ !! ] %s failed\n", test->name);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (client != NULL)
+ ipc_client_destroy(client);
+
+ return EX_SOFTWARE;
+}
diff --git a/samsung-ipc/tests/partitions/android.c b/samsung-ipc/tests/partitions/android.c
new file mode 100644
index 0000000..7b067e9
--- /dev/null
+++ b/samsung-ipc/tests/partitions/android.c
@@ -0,0 +1,212 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * 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 <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <samsung-ipc.h>
+
+#include <partitions/android/android.h>
+#include "android.h"
+
+static char const * const dummy_modem_image_paths[] = {
+ /* We can't use mktemp here since everything is const
+ * echo libsamsung-ipc | sha1sum | cut -c-20
+ * gives 55f4731d2e11e85bd889
+ */
+ "/tmp/libsamsung-ipc.55f4731d2e11e85bd889/modem.img",
+ NULL
+};
+
+int delete_dummy_modem_image(struct ipc_client *client,
+ __attribute__((unused)) const char * const path)
+{
+ int rc;
+ char *endp;
+ char *dir;
+
+ rc = unlink(path);
+ if (rc == -1) {
+ rc = errno;
+ if (rc != ENOENT) {
+ ipc_client_log(client,
+ "%s: unlink %s failed with error %d: %s",
+ __func__, path, rc, strerror(rc));
+ errno = rc;
+ return -1;
+ }
+ }
+
+ endp = strrchr(path, '/');
+
+ dir = malloc(endp - path + 1);
+ if (dir == NULL) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: calloc failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ errno = rc;
+ return -1;
+
+ }
+
+ memcpy(dir, path, endp - path);
+ dir[endp - path] = '\0';
+
+ rc = rmdir(dir);
+ if (rc == -1) {
+ rc = errno;
+ if (rc != ENOENT) {
+ ipc_client_log(client,
+ "%s: rmdir %s failed with error %d: %s",
+ __func__, dir, rc, strerror(rc));
+
+ free(dir);
+ errno = rc;
+ return -1;
+ }
+ }
+
+ free(dir);
+ return 0;
+}
+
+
+int create_dummy_modem_image(struct ipc_client *client,
+ __attribute__((unused)) const char * const path)
+{
+ int fd;
+ int rc;
+
+ rc = mkdir("/tmp/", 0755);
+ if (rc == -1) {
+ rc = errno;
+ if (rc != EEXIST) {
+ ipc_client_log(client,
+ "%s: mkdir %s failed with error %d: %s",
+ __func__, "/tmp/", rc, strerror(rc));
+ return -1;
+ }
+ }
+
+ rc = mkdir("/tmp/libsamsung-ipc.55f4731d2e11e85bd889/", 0755);
+ if (rc == -1) {
+ rc = errno;
+ if (rc != EEXIST) {
+ ipc_client_log(client,
+ "%s: mkdir %s failed with error %d: %s",
+ __func__,
+ "/tmp/libsamsung-ipc.55f4731d2e11e85bd889/",
+ rc, strerror(rc));
+ return -1;
+ }
+ }
+
+ fd = open("/tmp/libsamsung-ipc.55f4731d2e11e85bd889/modem.img",
+ O_CREAT, 0755);
+ if (fd == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: open %s failed with error %d: %s",
+ __func__,
+ "/tmp/libsamsung-ipc.55f4731d2e11e85bd889/modem.img",
+ rc, strerror(rc));
+ goto error;
+ }
+
+ rc = close(fd);
+ if (rc == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: close %s failed with error %d: %s",
+ __func__,
+ "/tmp/libsamsung-ipc.55f4731d2e11e85bd889/modem.img",
+ rc, strerror(rc));
+ goto error;
+ }
+
+ return 0;
+
+error:
+ rc = delete_dummy_modem_image(
+ client, "/tmp/libsamsung-ipc.55f4731d2e11e85bd889/modem.img");
+ if (rc == -1)
+ ipc_client_log(client,
+ "%s: delete_dummy_modem_image %s failed with error -1",
+ __func__);
+ return -1;
+}
+
+int test_open_android_modem_partition(struct ipc_client *client)
+{
+ int i;
+ int rc;
+
+ for (i = 0; dummy_modem_image_paths[i] != NULL; i++) {
+ rc = create_dummy_modem_image(client,
+ dummy_modem_image_paths[i]);
+ if (rc == -1) {
+ ipc_client_log(
+ client,
+ "%s: create_dummy_modem_image(client, %s)"
+ " failed\n",
+ __func__, dummy_modem_image_paths[i]);
+ return -1;
+ }
+ }
+
+ rc = open_android_modem_partition(client, dummy_modem_image_paths);
+ if (rc == -1) {
+ rc = errno;
+ ipc_client_log(client, "%s: open_android_modem_partition"
+ " failed with errror %d: %s\n",
+ __func__, rc, strerror(rc));
+ errno = rc;
+ return -1;
+ }
+
+ rc = close(rc);
+ if (rc == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: close() failed with errror %d: %s\n",
+ __func__, rc, strerror(rc));
+ return -1;
+ }
+
+ rc = delete_dummy_modem_image(
+ client, "/tmp/libsamsung-ipc.55f4731d2e11e85bd889/modem.img");
+ if (rc == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: delete_dummy_modem_image() failed with errror %d: %s\n",
+ __func__, rc, strerror(rc));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/samsung-ipc/tests/partitions/android.h b/samsung-ipc/tests/partitions/android.h
new file mode 100644
index 0000000..a386bb7
--- /dev/null
+++ b/samsung-ipc/tests/partitions/android.h
@@ -0,0 +1,25 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * 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 __TESTS_PARTITIONS_ANDROID_H__
+#define __TESTS_PARTITIONS_ANDROID_H__
+
+int test_open_android_modem_partition(struct ipc_client *client);
+
+#endif /* __TESTS_PARTITIONS_ANDROID_H__ */
diff --git a/samsung-ipc/utils.c b/samsung-ipc/utils.c
index 0e6bc2f..18f5d2b 100644
--- a/samsung-ipc/utils.c
+++ b/samsung-ipc/utils.c
@@ -38,6 +38,49 @@
#include <samsung-ipc.h>
+ssize_t data_read(__attribute__((unused)) struct ipc_client *client, int fd,
+ void *buf, size_t count)
+{
+ /* From read(2): "According to POSIX.1, if count is greater than
+ * SSIZE_MAX, the result is implementation-defined"
+ */
+ ssize_t remaining = (ssize_t)count;
+
+ while (remaining > 0) {
+ ssize_t rc;
+
+ rc = read(fd, buf, count);
+ if (rc == -1)
+ /* errno is passed to the caller */
+ return rc;
+ remaining -= rc;
+ }
+
+ return count;
+}
+
+ssize_t data_write(__attribute__((unused)) struct ipc_client *client, int fd,
+ const void *buf, size_t count)
+{
+ /* From write(2): "According to POSIX.1, if count is greater than
+ * SSIZE_MAX, the result is implementation-defined"
+ */
+ ssize_t remaining = (ssize_t)count;
+
+ while (remaining > 0) {
+ ssize_t rc;
+
+ rc = write(fd, buf, count);
+ if (rc == -1)
+ /* errno is passed to the caller */
+ return rc;
+ remaining -= rc;
+ }
+
+ return count;
+
+}
+
void *file_data_read(struct ipc_client *client, const char *path, size_t size,
size_t chunk_size, unsigned int offset)
{
@@ -93,8 +136,14 @@ void *file_data_read(struct ipc_client *client, const char *path, size_t size,
rc = read(fd, p,
size - count > chunk_size ?
chunk_size : size - count);
- if (rc <= 0) {
- ipc_client_log(client, "%s: Error: rc < 0", __func__);
+ if (rc == -1) {
+ rc = errno;
+ ipc_client_log(client, "%s: read error: %d: %s",
+ __func__, rc, strerror(rc));
+ goto error;
+ } else if (rc == 0) {
+ ipc_client_log(client, "%s: read error: end of file",
+ __func__);
goto error;
}
@@ -145,6 +194,7 @@ int file_data_write(struct ipc_client *client, const char *path,
ipc_client_log(client, "%s failed: chunk_size > size",
__func__);
}
+ errno = EINVAL;
return -1;
}
@@ -158,6 +208,7 @@ int file_data_write(struct ipc_client *client, const char *path,
seek = lseek(fd, (off_t) offset, SEEK_SET);
if (seek < (off_t) offset) {
+ rc = errno;
ipc_client_log(client, "%s failed: seek < (off_t) offset",
__func__);
goto error;
@@ -180,17 +231,58 @@ int file_data_write(struct ipc_client *client, const char *path,
count += rc;
}
- rc = 0;
- goto complete;
+ if (fd >= 0)
+ close(fd);
+
+ return 0;
error:
- rc = -1;
+ if (fd >= 0)
+ close(fd);
-complete:
+ errno = rc;
+ return -1;
+}
+
+off_t file_data_size(struct ipc_client *client, const char *path)
+{
+ int fd = -1;
+ off_t rc = 0;
+ int err = 0;
+
+ if (path == NULL) {
+ ipc_client_log(client, "%s: Failed: path is NULL",
+ __func__);
+ err = ENOENT;
+ goto error;
+ }
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ err = errno;
+ ipc_client_log(client, "%s: open %s failed with error %d: %s",
+ __func__, path, err, strerror(err));
+ goto error;
+ }
+
+ rc = lseek(fd, 0, SEEK_END);
+ if (rc == -1) {
+ err = errno;
+ ipc_client_log(client, "%s: seek %s failed with error %d: %s",
+ __func__, path, err, strerror(err));
+ goto error;
+ }
+
+error:
if (fd >= 0)
close(fd);
- return rc;
+ if (err) {
+ errno = err;
+ return -1;
+ } else {
+ return rc;
+ }
}
int network_iface_up(const char *iface, int domain, int type)
@@ -203,7 +295,7 @@ int network_iface_up(const char *iface, int domain, int type)
return -1;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+ memcpy(ifr.ifr_name, iface, IFNAMSIZ);
fd = socket(domain, type, 0);
if (fd < 0)
@@ -242,7 +334,7 @@ int network_iface_down(const char *iface, int domain, int type)
return -1;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+ memcpy(ifr.ifr_name, iface, IFNAMSIZ);
fd = socket(domain, type, 0);
if (fd < 0)
diff --git a/scripts/PKGBUILD b/scripts/PKGBUILD
new file mode 100644
index 0000000..155a765
--- /dev/null
+++ b/scripts/PKGBUILD
@@ -0,0 +1,55 @@
+# Copyright (C) 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
+# This program 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 3 of the License, or
+# (at your option) any later version.
+
+pkgname=libsamsung-ipc-git
+pkgver=0.3.1.r703.7c5e96a
+pkgrel=1
+pkgdesc="samsung-ipc modem protocol implementation."
+arch=('armv7h' 'i686' 'x86_64')
+license=('GPL2')
+makedepends=('autoconf'
+ 'automake'
+ 'coreutils'
+ 'ddrescue'
+ 'gawk'
+ 'grep'
+ 'libtool'
+ 'pkg-config'
+ 'python'
+ 'python-sh'
+ 'sed'
+ 'valgrind')
+depends=('openssl')
+
+pkgver() {
+ _base_version="0.3.1"
+ _base_revision="5cb3e7cb99701cae738693f2d6a6797a4d2df679"
+
+ if [ -d ../../.git ] ; then
+ printf "%s.r%s.%s" \
+ "${_base_version}" \
+ "$(git -C ../../ rev-list --count HEAD)" \
+ "$(git -C ../../ rev-parse --short HEAD)"
+ else
+ date "+%Y%m%d"
+ fi
+}
+
+build() {
+ ../../autogen.sh
+ ../../configure \
+ --prefix=/usr \
+ --enable-debug --enable-valgrind-tests --enable-strict-cflags
+ make
+}
+
+check() {
+ make check
+}
+
+package(){
+ make DESTDIR="$pkgdir" install
+}
diff --git a/scripts/guix.scm b/scripts/guix.scm
new file mode 100644
index 0000000..6343208
--- /dev/null
+++ b/scripts/guix.scm
@@ -0,0 +1,336 @@
+;;; Copyright © 2020 Denis Carikli <GNUtoo@cyberdimension.org>
+;;;
+;;; This file 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 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; This file 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 GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+;;; The guix.scm file is a convention: A file named guix.scm is
+;;; found in several project source code, either in the top
+;;; directory or in sub-directories like contrib for instance.
+
+;;; The guix.scm files typically contain package definitions that
+;;; are not meant to be used as regular packages but are meant for
+;;; testing or developing on the given project.
+;;;
+;;; For instance here it is used to build libsamsung-ipc in various
+;;; configurations. Instead distributions would typically be interested
+;;; in only one of the configurations.
+;;;
+;;; It also copies the sources that are present in the directory that
+;;; contains the guix.scm, and builds them. Distributions would instead
+;;; be interested in retrieving the source from git or releases tarballs.
+;;;
+;;; Once you have Guix installed, to build libsamsung-ipc with the
+;;; guix.scm file, you can use the 'guix build --file=scripts/guix.scm'
+;;; command, however as explained above, keep in mind that it will copy
+;;; all the files in the same directory than guix.scm, so you might want
+;;; to make sure that the sources are clean (with 'make distclean') if
+;;; you already built libsamsung-ipc in that directory.
+;;;
+;;; While this file could also serve as a basis to make a libsamsung-ipc
+;;; package in Guix, it is probably a good idea to wait until the API
+;;; and ABI changes are complete, ie when the ipc_client has been passed
+;;; to all the exported functions, and make a new release when that is
+;;; done.
+
+(use-modules (ice-9 popen)
+ (ice-9 rdelim)
+ (ice-9 regex)
+ (ice-9 textual-ports)
+ (sxml ssax input-parse)
+ ((guix licenses)
+ #:prefix license:)
+ (guix build-system android-ndk)
+ (guix build-system gnu)
+ (guix gexp)
+ (guix git-download)
+ (guix packages)
+ (guix profiles)
+ (guix transformations)
+ (gnu packages)
+ (gnu packages android)
+ (gnu packages autotools)
+ (gnu packages base)
+ (gnu packages curl)
+ (gnu packages disk)
+ (gnu packages linux)
+ (gnu packages llvm)
+ (gnu packages pkg-config)
+ (gnu packages python)
+ (gnu packages python-xyz)
+ (gnu packages tls)
+ (gnu packages valgrind))
+
+;; We need a more recent version of android-make-stub as it now
+;; support passing LOCAL_MODULE= to make to build specific local
+;; modules. This is needed because android-make-stub doesn't handle
+;; dependencies, so we need to make sure that libsamsung-ipc is built
+;; first. In addition we need a fix to make the applications that
+;; depend on libsamsung-ipc find libsamsung-ipc's includes directory.
+(define with-fixed-android-make-stub
+ (options->transformation '((with-commit . "android-make-stub=4bc0e068c32fe525741da00af064ddc079de7e4b"))))
+
+(define (parse-android.mk port modules-list)
+ (let* ((line (read-line port)))
+ (if (not (eof-object? line))
+ (let* ((line-parts (string-split line #\space)))
+ (if (string=? (car line-parts) "LOCAL_MODULE")
+ (if (not (string=? (list-ref line-parts 2) "libsamsung-ipc"))
+ (if (string=? modules-list "")
+ (parse-android.mk port
+ (list-ref line-parts 2))
+ (parse-android.mk port
+ (string-append modules-list " "
+ (list-ref line-parts 2))))
+ (parse-android.mk port modules-list))
+ (parse-android.mk port modules-list))) modules-list)))
+
+(define android-local-modules-list
+ (let* ((port (open-input-file "./Android.mk"))
+ (local-modules (parse-android.mk port "")))
+ (close-input-port port)
+ (string-split local-modules #\space)))
+
+(define %common-strict-cflags
+ (let* ((port (open-input-pipe "./strict-cflags.sh"))
+ (str (read-line port)))
+ (close-pipe port)
+ (string-append "CFLAGS=" str)))
+
+(define %clang-strict-cflags
+ (string-append "-Werror=non-virtual-dtor"))
+
+(define %commit
+ (let* ((port (open-input-pipe
+ "git --no-pager log --oneline HEAD -1 --format='%H'"))
+ (str (read-line port)))
+ (close-pipe port) str))
+
+(define %local-source
+ (local-file (dirname (dirname (current-filename)))
+ #:recursive? #t))
+
+(define android-make
+ #~(lambda (target android-local-modules)
+ (lambda* (#:key inputs make-flags native-inputs outputs
+ #:allow-other-keys)
+ (substitute* "Android.mk"
+ (("BUILD_SHARED_LIBRARY")
+ "BUILD_HOST_SHARED_LIBRARY")
+ (("BUILD_EXECUTABLE")
+ "BUILD_HOST_EXECUTABLE"))
+ ((assoc-ref %standard-phases target)
+ #:inputs inputs
+ #:outputs outputs
+ #:make-flags (append make-flags
+ '("LDFLAGS=-lssl -lcrypto"
+ "LOCAL_MODULE=libsamsung-ipc"
+ "SO=libsamsung-ipc.so")))
+ (map-in-order (lambda (local-module)
+ ((assoc-ref %standard-phases target)
+ #:inputs inputs
+ #:outputs outputs
+ #:make-flags (append make-flags
+ (list (string-append
+ "LDFLAGS=-Wl,-rpath="
+ #$output
+ "/lib -lssl -lcrypto -L .")
+ (string-append
+ "LOCAL_MODULE="
+ local-module)))))
+ android-local-modules))))
+
+(define android-phases
+ #~(modify-phases %standard-phases
+ (delete 'bootstrap)
+ (replace 'build
+ (#$android-make
+ 'build
+ '#$android-local-modules-list))
+ (replace 'install
+ (#$android-make
+ 'install
+ '#$android-local-modules-list))))
+
+(define-public libsamsung-ipc
+ (package
+ (name "libsamsung-ipc")
+ (version (git-version "0.0" "HEAD" %commit))
+ (source %local-source)
+ (build-system gnu-build-system)
+ (native-inputs (list autoconf
+ automake
+ ddrescue
+ `(,(canonical-package glibc) "debug")
+ libtool
+ pkg-config
+ python
+ python-sh
+ valgrind))
+ (inputs (list curl libressl))
+ (arguments
+ (list #:phases #~(modify-phases %standard-phases
+ (add-before 'build 'fix-valgrind
+ (lambda _
+ (substitute* (find-files "." ".*\\.py$")
+ (("'--leak-check=full',")
+ (string-append
+ "'--leak-check=full', '--extra-debuginfo-path="
+ (ungexp (this-package-native-input "glibc")
+ "debug") "/lib/debug',"))))))
+ #:configure-flags #~(list "--enable-debug"
+ "--enable-valgrind-tests")))
+ (synopsis
+ "libsamsung-ipc is a free software implementation of the Samsung IPC modem protocol")
+ (description
+ "libsamsung-ipc is a free software implementation of the Samsung IPC modem protocol,
+found in many Samsung smartphones and tablets.")
+ (home-page "https://www.replicant.us")
+ (license license:gpl2+)))
+
+(define is-file-static
+ #~(lambda (readelf path)
+ ;; str is also eof if the file doesn't exist
+ (if (not (file-exists? tool)) #f
+ (let* ((port (open-input-pipe (string-append readelf " --dyn-syms "
+ path)))
+ (str (read-line port)))
+ (close-pipe port)
+ (eof-object? str)))))
+
+(define-public libsamsung-ipc-static
+ (package
+ (inherit libsamsung-ipc)
+ (name "libsamsung-ipc-static")
+ (native-inputs (list autoconf
+ automake
+ binutils
+ ddrescue
+ libtool
+ pkg-config
+ python
+ python-sh))
+ ;; The libressl package contains .a in
+ ;; /gnu/store/[...]-libressl-[...]/lib/*.a
+ (inputs (list curl libressl))
+ (arguments
+ (list #:modules '((ice-9 popen)
+ (ice-9 rdelim)
+ (guix build utils)
+ (guix build gnu-build-system))
+ #:tests? #f
+ #:phases #~(modify-phases %standard-phases
+ ;; https-send-sms depends on curl and Guix doesn't have
+ ;; a static libcurl.
+ (add-after 'unpack 'remove-https-send-sms
+ (lambda _
+ (substitute* "tools/Makefile.am"
+ (("https-send-sms \\\\")
+ "\\"))))
+ (add-after 'compress-documentation 'check-static-files
+ (lambda _
+ (display "Checking static files:\n")
+ (map-in-order (lambda (tool)
+ (if (#$is-file-static
+ (string-append #$(this-package-native-input
+ "binutils")
+ "/bin/readelf") tool)
+ (display (string-append
+ "[ OK ] "
+ (basename tool) ": "
+ tool "\n"))
+ ((lambda _
+ (display (string-append
+ "[ !! ] "
+ (basename tool)
+ ": " tool "\n"))
+ (#f)))))
+ (list
+ "samsung-ipc/tests/libsamsung-ipc-test"
+ "tools/ipc-test"
+ "tools/nv_data-imei"
+ "tools/nv_data-md5"
+ "tools/ipc-modem/ipc-modem")))))
+ #:configure-flags #~(list "--enable-debug" "--enable-static=yes"
+ "--enable-shared=no"
+ "--enable-static-progs")))))
+
+(define-public libsamsung-ipc-gcc-android
+ (package
+ (inherit libsamsung-ipc)
+ (name "libsamsung-ipc-gcc-android")
+ (build-system android-ndk-build-system)
+ (inputs (list android-libutils curl libressl))
+ (native-inputs '())
+ (arguments
+ (list #:make-flags #~(list #$%common-strict-cflags
+ #$%clang-strict-cflags)
+ #:phases android-phases))))
+
+(define-public libsamsung-ipc-gcc-autotools
+ (package
+ (inherit libsamsung-ipc)
+ (name "libsamsung-ipc-gcc-autotools")
+ (arguments
+ (list #:configure-flags #~(list "--enable-debug")
+ #:make-flags #~(list #$%common-strict-cflags)))))
+
+(define-public libsamsung-ipc-clang-autotools
+ (package
+ (inherit libsamsung-ipc)
+ (name "libsamsung-ipc-clang-autotools")
+ (native-inputs (list autoconf
+ automake
+ ddrescue
+ libtool
+ pkg-config
+ python
+ python-sh
+ clang))
+ (arguments
+ (list #:configure-flags #~(list "--enable-debug")
+ #:make-flags #~(list #$%common-strict-cflags
+ #$%clang-strict-cflags)))))
+
+(define-public libsamsung-ipc-clang-android
+ (package
+ (inherit libsamsung-ipc)
+ (name "libsamsung-ipc-clang-android")
+ (build-system android-ndk-build-system)
+ (inputs (list android-libutils clang curl libressl))
+ (native-inputs '())
+ (arguments
+ (list #:make-flags #~(list #$%common-strict-cflags
+ #$%clang-strict-cflags)
+ #:phases android-phases))))
+
+;; Combinaisons:
+;; +--------------------------------+----------+----------+--------------+--------------+
+;; | Package name | Compiler | Compiler | Build system | Comments |
+;; | | | flags | | |
+;; +--------------------------------+----------+----------+--------------+--------------+
+;; | libsamsung-ipc | GCC | none | autotools | Base package |
+;; +--------------------------------+----------+----------+--------------+--------------+
+;; | libsamsung-ipc-gcc-android | GCC | strict | Android.mk | |
+;; +--------------------------------+----------+----------+--------------+--------------+
+;; | libsamsung-ipc-gcc-autotools | GCC | strict | autotools | |
+;; +--------------------------------+----------+----------+--------------+--------------+
+;; | libsamsung-ipc-clang-android | clang | strict | Android.mk | |
+;; +--------------------------------+----------+----------+--------------+--------------+
+;; | libsamsung-ipc-clang-autotools | clang | strict | autotools | |
+;; +--------------------------------+----------+----------+--------------+--------------+
+
+(list libsamsung-ipc
+ libsamsung-ipc-static
+ (with-fixed-android-make-stub libsamsung-ipc-clang-android)
+ (with-fixed-android-make-stub libsamsung-ipc-gcc-android)
+ libsamsung-ipc-clang-autotools
+ libsamsung-ipc-gcc-autotools)
diff --git a/scripts/manifest.scm b/scripts/manifest.scm
new file mode 100644
index 0000000..dfc82c7
--- /dev/null
+++ b/scripts/manifest.scm
@@ -0,0 +1,59 @@
+;;; Copyright © 2021 Denis Carikli <GNUtoo@cyberdimension.org>
+;;;
+;;; This file 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 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; This file 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 GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+;;; The guix.scm file is a convention: A file named guix.scm is
+;;; found in several project source code, either in the top
+;;; directory or in sub-directories like contrib for instance.
+
+;;; This file can be used to setup a development environment for Guix
+;;; users with the following command:
+;;; guix shell --pure --container -f scripts/manifest.scm
+
+(use-modules
+ (gnu packages autotools)
+ (gnu packages base)
+ (gnu packages code)
+ (gnu packages commencement)
+ (gnu packages compression)
+ (gnu packages curl)
+ (gnu packages disk)
+ (gnu packages gawk)
+ (gnu packages pkg-config)
+ (gnu packages python)
+ (gnu packages python-xyz)
+ (gnu packages tls))
+
+(list
+ autoconf
+ automake
+ bzip2
+ coreutils
+ curl
+ ddrescue
+ diffutils
+ findutils
+ gawk
+ gzip
+ gcc-toolchain
+ grep
+ lcov
+ libtool
+ gnu-make
+ openssl
+ pkg-config
+ python
+ python-sh
+ sed
+ tar
+ xz)
diff --git a/scripts/rebase-build-check-android.sh b/scripts/rebase-build-check-android.sh
new file mode 100755
index 0000000..e43e3c6
--- /dev/null
+++ b/scripts/rebase-build-check-android.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+# -*- coding: utf-8 -*-
+# Copyright (C) 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+set -e
+
+usage()
+{
+ printf "Usage:\n"
+ printf "%s build-from <base-commit-ref> " "$0"
+ printf "# Build all commits since <base-commit-ref>\n" "%0"
+ printf "%s continue " "$0"
+ printf "# Continue rebasing and building commits\n" "%0"
+ exit 64; # EX_USAGE from sysexits.h
+}
+
+print_header()
+{
+ set +e
+ message="$1"
+
+ len=$(expr $(echo -n ${message} | wc -c) + 2)
+
+ nr_chars=$(expr $(expr 80 - ${len}) / 2)
+
+ i="${nr_chars}"
+
+ while [ ${i} -gt 0 ] ; do
+ echo -n "#"
+ i="$(expr ${i} - 1)"
+ done
+
+ echo -n " ${message} "
+
+ i="${nr_chars}"
+
+ while [ ${i} -gt 0 ] ; do
+ echo -n "#"
+ i="$(expr ${i} - 1)"
+ done
+ echo
+ set -e
+}
+
+build_and_git_rebase_continue()
+{
+ total_commits="$1"
+
+ total_targets="$(./vendor/replicant/build.sh targets | wc -l)"
+ parallel_tasks=$(echo "$(grep 'processor' /proc/cpuinfo | wc -l ) + 1" | bc)
+
+ local_modules="$(grep \
+ "^LOCAL_MODULE := " \
+ hardware/replicant/libsamsung-ipc/Android.mk | \
+ awk '{print $3}' | sort -u)"
+
+ source build/envsetup.sh
+
+ # Currently all the Replicant versions supported by libsamsung-ipc
+ # have an aosp_arm-eng target. Using aosp_arm-eng also ensures
+ # that TARGET_DEVICE isn't set by the device repository. This also
+ # leaves us more freedom in libsamsung-ipc as we could for
+ # instance decide to not build unused code based on TARGET_DEVICE.
+ lunch aosp_arm-eng
+
+ commit_nr=1
+ while true ; do
+ print_header "[ commit ${commit_nr} of ${total_commits} ]"
+ make "-j${parallel_tasks}" ${local_modules}
+ git -C hardware/replicant/libsamsung-ipc rebase --continue || break
+ commit_nr="$(expr ${commit_nr} + 1)"
+ done
+}
+
+if [ $# -eq 2 ] && [ "$1" == "build-from" ] ; then
+ base_commit="$2"
+ nr_commits="$(git -C hardware/replicant/libsamsung-ipc log --oneline \
+ ${base_commit}~1..HEAD --oneline | wc -l)"
+ GIT_EDITOR="sed 's#^pick #edit #g' -i " \
+ git -C hardware/replicant/libsamsung-ipc \
+ rebase -i "${base_commit}"
+
+ build_and_git_rebase_continue "${nr_commits}"
+elif [ $# -eq 1 ] && [ "$1" == "continue" ] ; then
+ nr_commits="$(git -C hardware/replicant/libsamsung-ipc \
+ log --oneline REBASE_HEAD~1..ORIG_HEAD --oneline | wc -l)"
+ build_and_git_rebase_continue "${nr_commits}"
+else
+ usage
+fi
diff --git a/scripts/rebase-build-check-gnu-linux.sh b/scripts/rebase-build-check-gnu-linux.sh
new file mode 100755
index 0000000..a909290
--- /dev/null
+++ b/scripts/rebase-build-check-gnu-linux.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+# -*- coding: utf-8 -*-
+# Copyright (C) 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+die()
+{
+ echo "$@"
+ exit 1;
+}
+
+usage()
+{
+ printf "Usage:\n"
+ printf "%s build-from <base-commit-ref> " "$0"
+ printf "# Build all commits since <base-commit-ref>\n" "%0"
+ printf "%s continue " "$0"
+ printf "# Continue rebasing and building commits\n" "%0"
+ exit 64; # EX_USAGE from sysexits.h
+}
+
+print_header()
+{
+ message="$1"
+
+ len=$(expr $(echo -n ${message} | wc -c) + 2)
+
+ nr_chars=$(expr $(expr 80 - ${len}) / 2)
+
+ i="${nr_chars}"
+ while [ ${i} -gt 0 ] ; do
+ echo -n "#"
+ i="$(expr ${i} - 1)"
+ done
+
+ echo -n " ${message} "
+
+ i="${nr_chars}"
+ while [ ${i} -gt 0 ] ; do
+ echo -n "#"
+ i="$(expr ${i} - 1)"
+ done
+ echo
+}
+
+build_and_git_rebase_continue()
+{
+ commits="$1"
+ commit=1
+
+ while true ; do
+ print_header "[ ${commit} of ${commits} ]"
+ guix build --file=scripts/guix.scm || die "guix build failed"
+ commit="$(expr ${commit} + 1)"
+ git rebase --continue || break
+ done
+}
+
+if [ $# -eq 2 ] && [ "$1" == "build-from" ] ; then
+ base_commit="$2"
+ nr_commits="$(git log --oneline ${base_commit}~1..HEAD --oneline | wc -l)"
+ GIT_EDITOR="sed 's#^pick #edit #g' -i " git rebase -i "${base_commit}"
+ build_and_git_rebase_continue "${nr_commits}"
+elif [ $# -eq 1 ] && [ "$1" == "continue" ] ; then
+ nr_commits="$(git log --oneline REBASE_HEAD~1..ORIG_HEAD --oneline | wc -l)"
+ build_and_git_rebase_continue "${nr_commits}"
+else
+ usage
+fi
diff --git a/strict-cflags.sh b/strict-cflags.sh
new file mode 100755
index 0000000..55380f3
--- /dev/null
+++ b/strict-cflags.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# This file is part of libsamsung-ipc.
+#
+# Copyright (C) 2022 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/>.
+
+strict_cflags="\
+ -W \
+ -Wall \
+ -Werror \
+ -Werror=address \
+ -Werror=return-type \
+ -Werror=sequence-point \
+ -Winit-self \
+ -Wno-unused \
+ -Wpedantic \
+ -Wpointer-arith \
+ -Wunused \
+ -Wunused-function \
+"
+
+echo ${strict_cflags}
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 9336a64..024df50 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,23 +1,44 @@
NULL =
+EXTRA_DIST = $(NULL)
AM_CFLAGS = \
-I$(top_srcdir)/include \
+ $(LIBCURL_CFLAGS) \
$(NULL)
+AM_LDFLAGS = $(ALL_STATIC_LDFLAGS)
+
+if WANT_STRICT_CFLAGS
+AM_CFLAGS += $(STRICT_CFLAGS)
+endif
+
bin_PROGRAMS = \
- ipc-modem \
+ https-send-sms \
ipc-test \
+ nv_data-imei \
nv_data-md5 \
$(NULL)
-ipc_modem_SOURCES = ipc-modem.c
-ipc_modem_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la
-ipc_modem_LDFLAGS =
+# TODO: Find a way to make test more modular and represent each run of the
+# nv_data-imei in TEST while having it implemented in a single python file
+if WANT_VALGRIND_CHECKING
+AM_TESTS_ENVIRONMENT = VALGRIND='$(VALGRIND)'; export VALGRIND;
+endif
+PY_LOG_COMPILER = $(PYTHON3)
+TEST_EXTENSIONS = .py
+TESTS = \
+ tests/nv_data-imei.py \
+ tests/nv_data-md5.py
+EXTRA_DIST += $(TESTS)
+
+https_send_sms_SOURCES = https-send-sms.c
+https_send_sms_LDADD = $(LIBCURL_LIBS)
ipc_test_SOURCES = ipc-test.c
ipc_test_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la
-ipc_test_LDFLAGS =
nv_data_md5_SOURCES = nv_data-md5.c
nv_data_md5_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la
-nv_data_md5_LDFLAGS =
+
+nv_data_imei_SOURCES = nv_data-imei.c nv_data-imei.h
+nv_data_imei_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la
diff --git a/tools/https-send-sms.c b/tools/https-send-sms.c
new file mode 100644
index 0000000..80ad00b
--- /dev/null
+++ b/tools/https-send-sms.c
@@ -0,0 +1,205 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2022 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 <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include <curl/curl.h>
+
+/* CURL documentation for curl_easy_escape[1] mentions that "This
+ * function does not accept input strings longer than
+ * CURL_MAX_INPUT_LENGTH (8 MB)." but CURL_MAX_INPUT_LENGTH is not
+ * exported in the curl public headers (in /usr/include/curl).
+ */
+#define CURL_MAX_INPUT_LENGTH 8000000
+
+long send_https(CURL *hnd, char *url, __attribute__((unused)) char *post_data)
+{
+ CURLcode ret;
+ long return_code;
+
+ curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
+ curl_easy_setopt(hnd, CURLOPT_URL, url);
+ curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
+ curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION,
+ (long)CURL_HTTP_VERSION_2TLS);
+ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+
+ ret = curl_easy_perform(hnd);
+ assert(ret == CURLE_OK);
+
+ curl_easy_getinfo(hnd, CURLINFO_RESPONSE_CODE, &return_code);
+
+ return return_code;
+}
+
+int create_parameter(CURL *hnd,
+ char **out, const char *parameter, const char *value)
+{
+ char *result = NULL;
+ char *encoded_value;
+ size_t size = 0;
+ size_t rc;
+
+ assert(strlen(value) < CURL_MAX_INPUT_LENGTH);
+ encoded_value = curl_easy_escape(hnd, value, 0);
+ assert(encoded_value != NULL);
+
+ rc = snprintf(result, size, "%s=%s", parameter, encoded_value);
+
+ assert(rc > 0);
+ size = rc;
+
+ result = malloc(size + 1);
+ if (result == NULL) {
+ rc = -errno;
+ printf("%s: error %zd: %s\n", __func__, rc, strerror(rc));
+ return rc;
+ }
+
+ rc = snprintf(result, size + 1, "%s=%s", parameter, encoded_value);
+ assert(rc == size);
+
+ assert(rc < CURL_MAX_INPUT_LENGTH);
+
+ *out = result;
+
+ curl_free(encoded_value);
+
+ return 0;
+}
+
+int send_sms_get(const char *username, const char *password,
+ const char *message)
+{
+ CURL *hnd;
+ char *parameter = NULL;
+ int rc;
+ CURLU *url;
+ char *url_string;
+
+ url = curl_url();
+ hnd = curl_easy_init();
+
+ rc = curl_url_set(url, CURLUPART_URL,
+ "https://smsapi.free-mobile.fr/sendmsg", 0);
+ assert(rc == 0);
+
+ rc = create_parameter(hnd, &parameter, "user", username);
+ assert(rc == 0);
+ rc = curl_url_set(url, CURLUPART_QUERY, parameter, CURLU_APPENDQUERY);
+ assert(rc == 0);
+ free(parameter);
+
+ rc = create_parameter(hnd, &parameter, "pass", password);
+ rc = curl_url_set(url, CURLUPART_QUERY, parameter, CURLU_APPENDQUERY);
+ assert(rc == 0);
+ free(parameter);
+
+ rc = create_parameter(hnd, &parameter, "msg", message);
+ rc = curl_url_set(url, CURLUPART_QUERY, parameter, CURLU_APPENDQUERY);
+ assert(rc == 0);
+ free(parameter);
+
+ rc = curl_url_get(url, CURLUPART_URL, &url_string, 0);
+ assert(rc == 0);
+
+ rc = send_https(hnd, url_string, NULL);
+
+ switch (rc) {
+ case 200:
+ /* SMS SENT */
+ rc = 0;
+ break;
+ case 400:
+ printf("Error %d: %s\n",
+ rc,
+ "Missing parameter (user, login, message).");
+ rc = EX_USAGE;
+ break;
+ case 402:
+ printf("Error %d: %s\n",
+ rc,
+ "Too many SMS sent in too little time: Retry later.\n");
+ rc = EX_TEMPFAIL;
+ break;
+ case 403:
+ printf("Error %d: %s\n",
+ rc,
+ "Possible causes:\n"
+ "- Service is not enabled in your account settings.\n"
+ "- Wrong login or password.\n");
+ rc = EX_CONFIG;
+ break;
+ case 500:
+ printf("Error %d: %s\n",
+ rc,
+ "Service unavailable: Retry later");
+ rc = EX_UNAVAILABLE;
+ break;
+ default:
+ printf("Unknown error %d.\n", rc);
+ rc = EX_PROTOCOL;
+ break;
+ }
+
+ curl_easy_cleanup(hnd);
+ curl_url_cleanup(url);
+
+ return rc;
+}
+
+void usage(char *progname)
+{
+ printf("Usage: %s free-mobile <username> <token> <message>\n\n",
+ progname);
+ printf("Example:\n\t%s %s \"%s\" \"%s\" \"%s\"\n",
+ progname,
+ "free-mobile",
+ "12345678",
+ "1234abcdEFGH",
+ "hello world!");
+}
+
+int main(int argc, char *argv[])
+{
+ char *message;
+ char *password;
+ char *username;
+ int rc;
+
+ if (argc != 5 || strncmp("free-mobile", argv[1],
+ strlen("free-mobile"))) {
+ usage(argv[0]);
+ return EX_USAGE;
+ }
+
+ username = argv[2];
+ password = argv[3];
+ message = argv[4];
+
+ rc = send_sms_get(username, password, message);
+ if (rc == 0)
+ printf("OK\n");
+ return rc;
+}
diff --git a/tools/include/glibc/sysexits.h b/tools/include/glibc/sysexits.h
new file mode 100644
index 0000000..37246b6
--- /dev/null
+++ b/tools/include/glibc/sysexits.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sysexits.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _SYSEXITS_H
+#define _SYSEXITS_H 1
+
+/*
+ * SYSEXITS.H -- Exit status codes for system programs.
+ *
+ * This include file attempts to categorize possible error
+ * exit statuses for system programs, notably delivermail
+ * and the Berkeley network.
+ *
+ * Error numbers begin at EX__BASE to reduce the possibility of
+ * clashing with other exit statuses that random programs may
+ * already return. The meaning of the codes is approximately
+ * as follows:
+ *
+ * EX_USAGE -- The command was used incorrectly, e.g., with
+ * the wrong number of arguments, a bad flag, a bad
+ * syntax in a parameter, or whatever.
+ * EX_DATAERR -- The input data was incorrect in some way.
+ * This should only be used for user's data & not
+ * system files.
+ * EX_NOINPUT -- An input file (not a system file) did not
+ * exist or was not readable. This could also include
+ * errors like "No message" to a mailer (if it cared
+ * to catch it).
+ * EX_NOUSER -- The user specified did not exist. This might
+ * be used for mail addresses or remote logins.
+ * EX_NOHOST -- The host specified did not exist. This is used
+ * in mail addresses or network requests.
+ * EX_UNAVAILABLE -- A service is unavailable. This can occur
+ * if a support program or file does not exist. This
+ * can also be used as a catchall message when something
+ * you wanted to do doesn't work, but you don't know
+ * why.
+ * EX_SOFTWARE -- An internal software error has been detected.
+ * This should be limited to non-operating system related
+ * errors as possible.
+ * EX_OSERR -- An operating system error has been detected.
+ * This is intended to be used for such things as "cannot
+ * fork", "cannot create pipe", or the like. It includes
+ * things like getuid returning a user that does not
+ * exist in the passwd file.
+ * EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
+ * etc.) does not exist, cannot be opened, or has some
+ * sort of error (e.g., syntax error).
+ * EX_CANTCREAT -- A (user specified) output file cannot be
+ * created.
+ * EX_IOERR -- An error occurred while doing I/O on some file.
+ * EX_TEMPFAIL -- temporary failure, indicating something that
+ * is not really an error. In sendmail, this means
+ * that a mailer (e.g.) could not create a connection,
+ * and the request should be reattempted later.
+ * EX_PROTOCOL -- the remote system returned something that
+ * was "not possible" during a protocol exchange.
+ * EX_NOPERM -- You did not have sufficient permission to
+ * perform the operation. This is not intended for
+ * file system problems, which should use NOINPUT or
+ * CANTCREAT, but rather for higher level permissions.
+ */
+
+#define EX_OK 0 /* successful termination */
+
+#define EX__BASE 64 /* base value for error messages */
+
+#define EX_USAGE 64 /* command line usage error */
+#define EX_DATAERR 65 /* data format error */
+#define EX_NOINPUT 66 /* cannot open input */
+#define EX_NOUSER 67 /* addressee unknown */
+#define EX_NOHOST 68 /* host name unknown */
+#define EX_UNAVAILABLE 69 /* service unavailable */
+#define EX_SOFTWARE 70 /* internal software error */
+#define EX_OSERR 71 /* system error (e.g., can't fork) */
+#define EX_OSFILE 72 /* critical OS file missing */
+#define EX_CANTCREAT 73 /* can't create (user) output file */
+#define EX_IOERR 74 /* input/output error */
+#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
+#define EX_PROTOCOL 76 /* remote error in protocol */
+#define EX_NOPERM 77 /* permission denied */
+#define EX_CONFIG 78 /* configuration error */
+
+#define EX__MAX 78 /* maximum listed value */
+
+#endif /* sysexits.h */
diff --git a/tools/ipc-modem.c b/tools/ipc-modem.c
deleted file mode 100644
index 9314de6..0000000
--- a/tools/ipc-modem.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * This file is part of libsamsung-ipc.
- *
- * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
- * Copyright (C) 2011 Paul Kocialkowsk <contact@paulk.fr>
- *
- * 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 <fcntl.h>
-#include <getopt.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <samsung-ipc.h>
-
-#define MODEM_STATE_LPM 0
-#define MODEM_STATE_NORMAL 2
-#define MODEM_STATE_SIM_OK 4
-
-#define DEF_CALL_NUMBER "950"
-#define DEF_SIM_PIN "1234"
-
-int state = MODEM_STATE_LPM;
-int seq;
-int in_call;
-int out_call;
-int call_done;
-
-char sim_pin[8];
-
-int seq_get(void)
-{
- if (seq == 0xff)
- seq = 0x00;
-
- seq++;
-
- return seq;
-}
-
-void modem_snd_no_mic_mute(struct ipc_client *client)
-{
- uint8_t data = 0;
-
- ipc_client_send(client, seq_get(), IPC_SND_MIC_MUTE_CTRL, IPC_TYPE_SET,
- (void *) &data, 1);
-}
-
-void modem_snd_clock_ctrl(struct ipc_client *client)
-{
- uint8_t data = 0x01;
-
- ipc_client_send(client, seq_get(), IPC_SND_CLOCK_CTRL, IPC_TYPE_EXEC,
- (void *) &data, 1);
-}
-
-void modem_snd_spkr_volume_ctrl(struct ipc_client *client)
-{
- uint16_t data = 0x0411;
-
- ipc_client_send(client, seq_get(), IPC_SND_SPKR_VOLUME_CTRL,
- IPC_TYPE_SET, (void *) &data, 2);
-}
-
-void modem_snd_audio_path_ctrl(struct ipc_client *client)
-{
- uint8_t data = 0x01;
-
- ipc_client_send(client, seq_get(), IPC_SND_AUDIO_PATH_CTRL,
- IPC_TYPE_SET, (void *) &data, 1);
-}
-
-
-void modem_exec_call_out(struct ipc_client *client, char *num)
-{
- struct ipc_call_outgoing_data call_out;
-
- modem_snd_no_mic_mute(client);
-
- memset(&call_out, 0, sizeof(struct ipc_call_outgoing_data));
-
- call_out.type = IPC_CALL_TYPE_VOICE;
- call_out.identity = IPC_CALL_IDENTITY_DEFAULT;
- call_out.number_length = strlen(num);
- /* 0x21 = +33 */
- call_out.prefix = IPC_CALL_PREFIX_NONE; //0x21;//IPC_CALL_PREFIX_NONE;
- memcpy(call_out.number, num, call_out.number_length);
-
- ipc_client_send(client, seq_get(), IPC_CALL_OUTGOING, IPC_TYPE_EXEC,
- (void *) &call_out,
- sizeof(struct ipc_call_outgoing_data));
-
- out_call = 1;
-
- modem_snd_no_mic_mute(client);
- modem_snd_spkr_volume_ctrl(client);
- modem_snd_audio_path_ctrl(client);
-}
-
-void modem_exec_call_answer(struct ipc_client *client)
-{
- modem_snd_clock_ctrl(client);
-
- ipc_client_send(client, seq_get(), IPC_CALL_ANSWER, IPC_TYPE_EXEC, NULL,
- 0);
-
- modem_snd_no_mic_mute(client);
-}
-
-void modem_get_call_list(struct ipc_client *client)
-{
- ipc_client_send(client, seq_get(), IPC_CALL_LIST, IPC_TYPE_GET, NULL,
- 0);
-
- modem_snd_no_mic_mute(client);
-}
-
-void modem_exec_power_normal(struct ipc_client *client)
-{
- uint16_t data = 0x0202;
-
- ipc_client_send(client, seq_get(), IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC,
- (void *) &data, sizeof(data));
-}
-
-void modem_set_sms_device_ready(struct ipc_client *client)
-{
- ipc_client_send(client, seq_get(), IPC_SMS_DEVICE_READY, IPC_TYPE_SET,
- NULL, 0);
-}
-
-void modem_set_sec_pin_status(struct ipc_client *client, char *pin1, char *pin2)
-{
- struct ipc_sec_pin_status_request_data pin_status;
-
- printf("[I] Sending PIN1 unlock request\n");
-
- ipc_sec_pin_status_setup(&pin_status, IPC_SEC_PIN_TYPE_PIN1, pin1,
- pin2);
-
- ipc_client_send(client, seq_get(), IPC_SEC_PIN_STATUS, IPC_TYPE_SET,
- (void *) &pin_status, sizeof(pin_status));
-}
-
-void modem_response_sec(struct ipc_client *client, struct ipc_message *resp)
-{
- struct ipc_sec_pin_status_response_data *sim_status;
- unsigned char type;
-
- 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:
- printf("[I] SIM card is definitely absent\n");
- break;
- case IPC_SEC_PIN_STATUS_LOCK_SC:
- switch (sim_status->facility_lock) {
- case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ:
- printf("[I] "
- "We need the PIN1 to unlock the card!"
- "\n");
- if (strlen(sim_pin) > 0) {
- modem_set_sec_pin_status(client,
- sim_pin, NULL);
- } else {
- printf("[E] No SIM Pin, use --pin\n");
- }
- break;
- case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ:
- printf("[I] Please provide the SIM card PUK!"
- "\n");
- break;
- case IPC_SEC_FACILITY_LOCK_TYPE_SC_CARD_BLOCKED:
- printf("[I] Ouch, the SIM Card is blocked.\n");
- break;
- }
- break;
- case IPC_SEC_PIN_STATUS_INIT_COMPLETE:
- printf("[3] SIM init complete\n");
- if (state == MODEM_STATE_NORMAL)
- state = MODEM_STATE_SIM_OK;
- break;
- case IPC_SEC_PIN_STATUS_PB_INIT_COMPLETE:
- printf("[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:
- printf("[I] No SIM card type: unknown (absent?)\n");
- break;
- case IPC_SEC_SIM_CARD_TYPE_SIM:
- case IPC_SEC_SIM_CARD_TYPE_USIM:
- printf("[I] SIM card found\n");
- break;
- }
- break;
- }
-}
-
-void modem_response_sms(struct ipc_client *client, struct ipc_message *resp)
-{
- switch (resp->command) {
- case IPC_SMS_DEVICE_READY:
- if (state == MODEM_STATE_LPM) {
- printf("[4] "
- "Modem is ready, requesting normal power mode"
- "\n");
- modem_exec_power_normal(client);
- } else if (state == MODEM_STATE_SIM_OK) {
- printf("[5] Modem is fully ready\n");
- modem_set_sms_device_ready(client);
- }
- break;
- }
-}
-
-void modem_response_call(struct ipc_client *client, struct ipc_message *resp)
-{
- struct ipc_call_status_data *stat;
-
- switch (resp->command) {
- case IPC_CALL_LIST:
- /*
- * if (in_call)
- * modem_exec_call_answer(client);
- * if (out_call)
- * modem_snd_no_mic_mute(client);
- */
- break;
- case IPC_CALL_INCOMING:
- printf("[I] Got an incoming call!\n");
- in_call = 1;
- modem_get_call_list(client);
- break;
- case IPC_CALL_STATUS:
- stat = (struct ipc_call_status_data *)resp->data;
-
- if (stat->status == IPC_CALL_STATUS_DIALING) {
- printf("[I] Sending clock ctrl and restore alsa\n");
- modem_snd_clock_ctrl(client);
- /*
- * system("alsa_ctl -f /data/alsa_state_modem restore");
- */
-
- printf("[I] CALL STATUS DIALING!!!\n");
-
- modem_snd_spkr_volume_ctrl(client);
- modem_snd_audio_path_ctrl(client);
-
- modem_get_call_list(client);
- }
-
- if (stat->status == IPC_CALL_STATUS_CONNECTED) {
- printf("[I] CALL STATUS CONNECTED!!!\n");
- modem_snd_no_mic_mute(client);
- }
-
- if (stat->status == IPC_CALL_STATUS_RELEASED) {
- printf("[I] CALL STATUS RELEASED!!!\n");
- modem_snd_no_mic_mute(client);
- }
- break;
- }
-}
-
-void modem_response_pwr(__attribute__((unused)) struct ipc_client *client,
- struct ipc_message *resp)
-{
- int state_n;
-
- switch (resp->command) {
- case IPC_PWR_PHONE_PWR_UP:
- printf("[2] Phone is powered up (LPM)!\n");
- 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:
- printf("Power state is now: NORMAL\n");
- break;
- case IPC_PWR_PHONE_STATE_LPM:
- printf("Power state is now: LPM (Low Power Mode)?\n");
- break;
- }
-#endif
- state = state_n;
- break;
-
- }
-}
-
-void modem_response_net(__attribute__((unused)) struct ipc_client *client,
- struct ipc_message *resp)
-{
- struct ipc_net_regist_response_data *regi;
- char mnc[6];
-
- switch (resp->command) {
- case IPC_NET_REGIST:
- regi = (struct ipc_net_regist_response_data *) resp->data;
- if (regi->status == IPC_NET_REGISTRATION_STATUS_HOME)
- printf("[I] Registered with network successfully!\n");
- break;
- case IPC_NET_SERVING_NETWORK:
- memcpy(mnc, (char *)((char *) resp->data + 3), 5);
- mnc[5] = 0;
- printf("[6] Registered with network! "
- "Got PLMN (Mobile Network Code): '%s'\n",
- mnc);
- /*
- * if (call_done == 0)
- * {
- * printf("Requesting outgoing call to %s!\n", DEF_CALL_NUMBER);
- * modem_exec_call_out(client, DEF_CALL_NUMBER);
- * }
- * call_done = 1;
- */
- break;
- }
-}
-
-void modem_response_handle(struct ipc_client *client, struct ipc_message *resp)
-{
- switch (IPC_GROUP(resp->command)) {
- case IPC_GROUP_NET:
- modem_response_net(client, resp);
- break;
- case IPC_GROUP_PWR:
- modem_response_pwr(client, resp);
- break;
- case IPC_GROUP_SEC:
- modem_response_sec(client, resp);
- break;
- case IPC_GROUP_SMS:
- modem_response_sms(client, resp);
- break;
- case IPC_GROUP_CALL:
- modem_response_call(client, resp);
- break;
- case IPC_GROUP_DISP:
- if (in_call)
- modem_snd_no_mic_mute(client);
- break;
- }
-}
-
-
-int modem_read_loop(struct ipc_client *client)
-{
- struct ipc_message resp;
- int rc;
-
- memset(&resp, 0, sizeof(resp));
-
- while (1) {
- usleep(3000);
-
- rc = ipc_client_poll(client, NULL, NULL);
- if (rc < 0)
- continue;
-
- rc = ipc_client_recv(client, &resp);
- if (rc < 0) {
- printf("[E] "
- "Can't RECV from modem: please run this again"
- "\n");
- break;
- }
-
- modem_response_handle(client, &resp);
-
- if (resp.data != NULL)
- free(resp.data);
- }
-
- return 0;
-}
-
-void modem_log_handler(__attribute__((unused)) 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;
- }
-
- printf("[D] %s\n", message);
- }
-
- free(message);
-}
-
-void modem_log_handler_quiet(__attribute__((unused)) void *user_data,
- __attribute__((unused)) const char *msg)
-{
-}
-
-int modem_start(struct ipc_client *client)
-{
- int rc = -1;
-
- ipc_client_data_create(client);
- rc = ipc_client_boot(client);
- if (rc < 0)
- return -1;
-
- usleep(300);
-
- rc = ipc_client_open(client);
- if (rc < 0)
- return -1;
-
- rc = ipc_client_power_on(client);
- if (rc < 0)
- return -1;
-
- return 0;
-}
-
-int modem_stop(struct ipc_client *client)
-{
- ipc_client_power_off(client);
- ipc_client_close(client);
-
- return 0;
-}
-
-void print_help(void)
-{
- printf("usage: ipc-modem <command>\n");
- printf("commands:\n");
- printf("\tstart boot modem and start read loop\n");
- printf("\tboot boot modem only\n");
- printf("\tpower-on power on the modem\n");
- printf("\tpower-off power off the modem\n");
- printf("arguments:\n");
- printf("\t--debug enable debug messages\n");
- printf("\t--pin=[PIN] provide SIM card PIN\n");
-}
-
-int main(int argc, char *argv[])
-{
- struct ipc_client *client_fmt;
- int c = 0;
- int opt_i = 0;
- int rc = -1;
- int debug = 0;
-
- struct option opt_l[] = {
- {"help", no_argument, 0, 0 },
- {"debug", no_argument, 0, 0 },
- {"pin", required_argument, 0, 0 },
- {0, 0, 0, 0 }
- };
-
- if (argc < 2) {
- print_help();
- exit(1);
- }
-
- while (c >= 0) {
- c = getopt_long(argc, argv, "", opt_l, &opt_i);
- if (c < 0)
- break;
-
- switch (c) {
- case 0:
- if (strncmp(opt_l[opt_i].name, "help", 4) == 0) {
- print_help();
- exit(1);
- } else if (strcmp(opt_l[opt_i].name, "debug") == 0) {
- debug = 1;
- printf("[I] Debug enabled\n");
- } else if (strcmp(opt_l[opt_i].name, "pin") == 0) {
- if (optarg) {
- if (strlen(optarg) < 8) {
- printf("[I] Got SIM PIN!\n");
- memcpy(sim_pin, optarg, 8);
- } else {
- printf("[E] "
- "SIM PIN is too long!"
- "\n");
- return 1;
- }
- }
- }
- break;
- }
- }
-
- client_fmt = ipc_client_create(IPC_CLIENT_TYPE_FMT);
-
- if (client_fmt == 0) {
- printf("[E] Could not create IPC client; aborting ...\n");
- goto modem_quit;
- }
-
- if (debug == 0) {
- ipc_client_log_callback_register(client_fmt,
- modem_log_handler_quiet, NULL);
- } else {
- ipc_client_log_callback_register(client_fmt, modem_log_handler,
- NULL);
- }
-
- while (optind < argc) {
- if (strncmp(argv[optind], "power-on", 8) == 0) {
- if (ipc_client_power_on(client_fmt) < 0)
- printf("[E] Something went wrong "
- "while powering modem on\n");
- goto modem_quit;
- } else if (strncmp(argv[optind], "power-off", 9) == 0) {
- if (ipc_client_power_off(client_fmt) < 0)
- printf("[E] Something went wrong "
- "while powering modem off\n");
- goto modem_quit;
- } else if (strncmp(argv[optind], "boot", 9) == 0) {
- rc = ipc_client_boot(client_fmt);
- if (rc < 0)
- printf("[E] Something went wrong "
- "while bootstrapping modem\n");
- } else if (strncmp(argv[optind], "start", 5) == 0) {
- printf("[0] Starting modem on FMT client\n");
- rc = modem_start(client_fmt);
- if (rc < 0) {
- printf("[E] Something went wrong\n");
- modem_stop(client_fmt);
- return 1;
- }
-
- printf("[1] Starting modem_read_loop on FMT client\n");
- modem_read_loop(client_fmt);
-
- modem_stop(client_fmt);
- } else {
- printf("[E] Unknown argument: '%s'\n", argv[optind]);
- print_help();
- return 1;
- }
-
- optind++;
- }
-
-modem_quit:
- if (client_fmt != 0)
- ipc_client_destroy(client_fmt);
-
- return 0;
-}
diff --git a/tools/ipc-modem/Makefile.am b/tools/ipc-modem/Makefile.am
new file mode 100644
index 0000000..64cde49
--- /dev/null
+++ b/tools/ipc-modem/Makefile.am
@@ -0,0 +1,28 @@
+NULL =
+EXTRA_DIST = $(NULL)
+
+AM_CFLAGS = \
+ -I$(top_srcdir)/include \
+ $(NULL)
+
+if WANT_STRICT_CFLAGS
+AM_CFLAGS += $(STRICT_CFLAGS)
+endif
+
+bin_PROGRAMS = ipc-modem
+
+# TODO: Find a way to make test more modular and represent each run of the
+# ipc-modem in TEST while having it implemented in a single python file
+PY_LOG_COMPILER = $(PYTHON3)
+TEST_EXTENSIONS = .py
+TESTS = tests/ipc-modem.py
+EXTRA_DIST += $(TESTS)
+
+ipc_modem_SOURCES = \
+ipc-modem.c \
+ipc-modem.h \
+ipc-modem-log.c \
+ipc-modem-log.h
+
+ipc_modem_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la
+ipc_modem_LDFLAGS = -lpthread $(ALL_STATIC_LDFLAGS)
diff --git a/tools/ipc-modem/ipc-modem-log.c b/tools/ipc-modem/ipc-modem-log.c
new file mode 100644
index 0000000..7e6b48d
--- /dev/null
+++ b/tools/ipc-modem/ipc-modem-log.c
@@ -0,0 +1,84 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
+ * Copyright (C) 2011 Paul Kocialkowsk <contact@paulk.fr>
+ * Copyright (C) 2022 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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "ipc-modem-log.h"
+
+static enum log_target log_target;
+
+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 (log_target == LOG_TO_STDOUT && user_data)
+ printf("[%s] %s\n", (char *)user_data, message);
+ else if (log_target == LOG_TO_STDOUT)
+ printf("[%s] %s\n", MODEM_LOG_DEBUG, message);
+ else if (log_target == LOG_TO_SYSLOG && user_data)
+ syslog(LOG_INFO,
+ "[%s] %s\n", (char *)user_data, message);
+ else if (log_target == LOG_TO_SYSLOG)
+ syslog(LOG_INFO, "[%s] %s\n", MODEM_LOG_DEBUG, message);
+ }
+
+ free(message);
+}
+
+void modem_log_handler_quiet(__attribute__((unused)) void *user_data,
+ __attribute__((unused)) const char *msg)
+{
+}
+
+void ipc_modem_log(__attribute__((unused)) struct ipc_client *client,
+ char *prefix, const char *message, ...)
+{
+ va_list args;
+ char buffer[4096];
+
+ va_start(args, message);
+ vsnprintf((char *) &buffer, sizeof(buffer), message, args);
+ va_end(args);
+
+ modem_log_handler(prefix, buffer);
+}
+
+void ipc_modem_set_log_target(enum log_target target)
+{
+ log_target = target;
+}
+
diff --git a/tools/ipc-modem/ipc-modem-log.h b/tools/ipc-modem/ipc-modem-log.h
new file mode 100644
index 0000000..1786295
--- /dev/null
+++ b/tools/ipc-modem/ipc-modem-log.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2022 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 IPC_MODEM_LOG_H
+#define IPC_MODEM_LOG_H
+
+#include <stdarg.h>
+
+#include <samsung-ipc.h>
+
+#define MODEM_LOG_ERROR "E"
+#define MODEM_LOG_INFO "I"
+#define MODEM_LOG_DEBUG "D"
+
+enum log_target {
+ LOG_TO_STDOUT,
+ LOG_TO_SYSLOG,
+};
+
+void ipc_modem_log(struct ipc_client *client,
+ char *prefix, const char *message, ...);
+void modem_log_handler(void *user_data, const char *msg);
+void modem_log_handler_quiet(void *user_data, const char *msg);
+void ipc_modem_set_log_target(enum log_target target);
+
+#endif /* IPC_MODEM_LOG_H */
diff --git a/tools/ipc-modem/ipc-modem.c b/tools/ipc-modem/ipc-modem.c
new file mode 100644
index 0000000..c70bcc1
--- /dev/null
+++ b/tools/ipc-modem/ipc-modem.c
@@ -0,0 +1,781 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
+ * Copyright (C) 2011 Paul Kocialkowsk <contact@paulk.fr>
+ *
+ * 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 <assert.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sysexits.h>
+#include <termios.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <samsung-ipc.h>
+
+#include "ipc-modem.h"
+#include "ipc-modem-log.h"
+
+int seq_get(struct ipc_modem_data *data)
+{
+ if (data->seq == 0xff)
+ data->seq = 0x00;
+
+ data->seq++;
+
+ return data->seq;
+}
+
+void modem_snd_no_mic_mute(struct ipc_modem_data *data)
+{
+ uint8_t mic_mute_data = 0;
+
+ ipc_client_send(data->client,
+ seq_get(data), IPC_SND_MIC_MUTE_CTRL, IPC_TYPE_SET,
+ (void *) &mic_mute_data, 1);
+}
+
+void modem_snd_clock_ctrl(struct ipc_modem_data *data)
+{
+ uint8_t clock_ctrl_data = 0x01;
+
+ ipc_client_send(data->client,
+ seq_get(data), IPC_SND_CLOCK_CTRL, IPC_TYPE_EXEC,
+ (void *) &clock_ctrl_data, 1);
+}
+
+void modem_snd_spkr_volume_ctrl(struct ipc_modem_data *data)
+{
+ uint16_t spkr_volume_data = 0x0411;
+
+ ipc_client_send(data->client, seq_get(data), IPC_SND_SPKR_VOLUME_CTRL,
+ IPC_TYPE_SET, (void *) &spkr_volume_data, 2);
+}
+
+void modem_snd_audio_path_ctrl(struct ipc_modem_data *data)
+{
+ uint8_t audio_path_ctrl_data = 0x01;
+
+ ipc_client_send(data->client, seq_get(data), IPC_SND_AUDIO_PATH_CTRL,
+ IPC_TYPE_SET, (void *) &audio_path_ctrl_data, 1);
+}
+
+
+
+void modem_exec_call_out(struct ipc_modem_data *data, char *num)
+{
+ struct ipc_call_outgoing_data call_out;
+
+ modem_snd_no_mic_mute(data);
+
+ memset(&call_out, 0, sizeof(struct ipc_call_outgoing_data));
+
+ call_out.type = IPC_CALL_TYPE_VOICE;
+ call_out.identity = IPC_CALL_IDENTITY_DEFAULT;
+ call_out.number_length = strlen(num);
+ /* TODO: Add support for prefixes */
+ /* 0x21 = +33 */
+ call_out.prefix = IPC_CALL_PREFIX_NONE; //0x21;//IPC_CALL_PREFIX_NONE;
+ memcpy(call_out.number, num, call_out.number_length);
+
+ ipc_client_send(data->client,
+ seq_get(data), IPC_CALL_OUTGOING, IPC_TYPE_EXEC,
+ (void *) &call_out,
+ sizeof(struct ipc_call_outgoing_data));
+
+ data->out_call = 1;
+
+ modem_snd_no_mic_mute(data);
+ modem_snd_spkr_volume_ctrl(data);
+ modem_snd_audio_path_ctrl(data);
+}
+
+void modem_exec_call_answer(struct ipc_modem_data *data)
+{
+ modem_snd_clock_ctrl(data);
+
+ ipc_client_send(data->client,
+ seq_get(data), IPC_CALL_ANSWER, IPC_TYPE_EXEC, NULL, 0);
+
+ modem_snd_no_mic_mute(data);
+}
+
+void modem_get_call_list(struct ipc_modem_data *data)
+{
+ ipc_client_send(data->client,
+ seq_get(data), IPC_CALL_LIST, IPC_TYPE_GET, NULL, 0);
+
+ modem_snd_no_mic_mute(data);
+}
+
+void modem_exec_power_normal(struct ipc_modem_data *data)
+{
+ uint16_t exec_data = IPC_PWR_PHONE_STATE_REQUEST_NORMAL;
+
+ ipc_client_send(data->client,
+ seq_get(data), IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC,
+ (void *) &exec_data, sizeof(data));
+}
+
+void modem_set_sms_device_ready(struct ipc_modem_data *data)
+{
+ ipc_client_send(data->client,
+ seq_get(data), IPC_SMS_DEVICE_READY, IPC_TYPE_SET,
+ NULL, 0);
+}
+
+void modem_set_sec_pin_status(struct ipc_modem_data *data,
+ char *pin1, char *pin2)
+{
+ struct ipc_sec_pin_status_request_data pin_status;
+
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO, "Sending PIN1 unlock request\n");
+
+ ipc_sec_pin_status_setup(&pin_status, IPC_SEC_PIN_TYPE_PIN1, pin1,
+ pin2);
+
+ ipc_client_send(data->client,
+ seq_get(data), IPC_SEC_PIN_STATUS, IPC_TYPE_SET,
+ (void *) &pin_status, sizeof(pin_status));
+}
+
+void modem_response_sec(struct ipc_modem_data *data, struct ipc_message *resp)
+{
+ struct ipc_sec_pin_status_response_data *sim_status;
+ unsigned char type;
+
+ 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:
+ ipc_modem_log(data->client, MODEM_LOG_INFO,
+ "SIM card is definitely absent\n");
+ break;
+ case IPC_SEC_PIN_STATUS_LOCK_SC:
+ switch (sim_status->facility_lock) {
+ case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ:
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_INFO,
+ "We need the PIN1 to unlock the card!"
+ "\n");
+ if (strlen(data->sim_pin) > 0) {
+ modem_set_sec_pin_status(data,
+ data->sim_pin,
+ NULL);
+ } else {
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_ERROR,
+ "No SIM Pin, use --pin\n");
+ }
+ break;
+ case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ:
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_INFO,
+ "Please provide the SIM card PUK!"
+ "\n");
+ break;
+ case IPC_SEC_FACILITY_LOCK_TYPE_SC_CARD_BLOCKED:
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_INFO,
+ "Ouch, the SIM Card is blocked.\n");
+ break;
+ }
+ break;
+ case IPC_SEC_PIN_STATUS_INIT_COMPLETE:
+ ipc_modem_log(data->client, "3", "SIM init complete\n");
+ if (data->state == MODEM_STATE_NORMAL)
+ data->state = MODEM_STATE_SIM_OK;
+ break;
+ case IPC_SEC_PIN_STATUS_PB_INIT_COMPLETE:
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO,
+ "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:
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_INFO,
+ "No SIM card type: unknown (absent?)\n");
+ break;
+ case IPC_SEC_SIM_CARD_TYPE_SIM:
+ case IPC_SEC_SIM_CARD_TYPE_USIM:
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO, "SIM card found\n");
+ break;
+ }
+ break;
+ }
+}
+
+void modem_response_sms(struct ipc_modem_data *data, struct ipc_message *resp)
+{
+ switch (resp->command) {
+ case IPC_SMS_DEVICE_READY:
+ if (data->state == MODEM_STATE_LPM) {
+ ipc_modem_log(
+ data->client,
+ "4",
+ "Modem is ready, requesting normal power mode"
+ "\n");
+ modem_exec_power_normal(data);
+ } else if (data->state == MODEM_STATE_SIM_OK) {
+ ipc_modem_log(data->client,
+ "5", "Modem is fully ready\n");
+ modem_set_sms_device_ready(data);
+ }
+ break;
+ }
+}
+
+void modem_response_call(struct ipc_modem_data *data, struct ipc_message *resp)
+{
+ struct ipc_call_status_data *stat;
+
+ switch (resp->command) {
+ case IPC_CALL_LIST:
+ /*
+ * if (data->in_call)
+ * modem_exec_call_answer(data->client);
+ * if (data->out_call)
+ * modem_snd_no_mic_mute(data);
+ */
+ break;
+ case IPC_CALL_INCOMING:
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO, "Got an incoming call!\n");
+ data->in_call = 1;
+ modem_get_call_list(data);
+ break;
+ case IPC_CALL_STATUS:
+ stat = (struct ipc_call_status_data *)resp->data;
+
+ if (stat->status == IPC_CALL_STATUS_DIALING) {
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_INFO,
+ "Sending clock ctrl and restore alsa\n");
+ modem_snd_clock_ctrl(data);
+ /*
+ * system("alsa_ctl -f /data/alsa_state_modem restore");
+ */
+
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO,
+ "CALL STATUS DIALING!!!\n");
+
+ modem_snd_spkr_volume_ctrl(data);
+ modem_snd_audio_path_ctrl(data);
+
+ modem_get_call_list(data);
+ }
+
+ if (stat->status == IPC_CALL_STATUS_CONNECTED) {
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO,
+ "CALL STATUS CONNECTED!!!\n");
+ modem_snd_no_mic_mute(data);
+ }
+
+ if (stat->status == IPC_CALL_STATUS_RELEASED) {
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO,
+ "CALL STATUS RELEASED!!!\n");
+ modem_snd_no_mic_mute(data);
+ }
+ break;
+ }
+}
+
+void modem_response_pwr(struct ipc_modem_data *data, struct ipc_message *resp)
+{
+ int state_n;
+
+ switch (resp->command) {
+ case IPC_PWR_PHONE_PWR_UP:
+ ipc_modem_log(data->client,
+ "2", "Phone is powered up (LPM)!\n");
+ data->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:
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO,
+ "Power state is now: NORMAL\n");
+ break;
+ case IPC_PWR_PHONE_STATE_LPM:
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_INFO,
+ "Power state is now: LPM (Low Power Mode)?\n");
+ break;
+ }
+#endif
+ data->state = state_n;
+ break;
+
+ }
+}
+
+void modem_response_net(struct ipc_modem_data *data,
+ struct ipc_message *resp)
+{
+ struct ipc_net_regist_response_data *regi;
+ char mnc[6];
+
+ switch (resp->command) {
+ case IPC_NET_REGIST:
+ regi = (struct ipc_net_regist_response_data *) resp->data;
+ if (regi->status == IPC_NET_REGISTRATION_STATUS_HOME)
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_INFO,
+ "Registered with network successfully!\n");
+ break;
+ case IPC_NET_SERVING_NETWORK:
+ memcpy(mnc, (char *)((char *) resp->data + 3), 5);
+ mnc[5] = 0;
+ ipc_modem_log(data->client,
+ "6",
+ "Registered with network! "
+ "Got PLMN (Mobile Network Code): '%s'\n",
+ mnc);
+ if (data->call_done == 0) {
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO,
+ "Requesting outgoing call to %s!\n",
+ data->call_number);
+ modem_exec_call_out(data, data->call_number);
+ }
+ data->call_done = 1;
+ break;
+ }
+}
+
+void modem_response_handle(struct ipc_modem_data *data,
+ struct ipc_message *resp)
+{
+ switch (IPC_GROUP(resp->command)) {
+ case IPC_GROUP_NET:
+ modem_response_net(data, resp);
+ break;
+ case IPC_GROUP_PWR:
+ modem_response_pwr(data, resp);
+ break;
+ case IPC_GROUP_SEC:
+ modem_response_sec(data, resp);
+ break;
+ case IPC_GROUP_SMS:
+ modem_response_sms(data, resp);
+ break;
+ case IPC_GROUP_CALL:
+ modem_response_call(data, resp);
+ break;
+ case IPC_GROUP_DISP:
+ if (data->in_call)
+ modem_snd_no_mic_mute(data);
+ break;
+ }
+}
+
+
+int modem_read_loop(struct ipc_modem_data *data)
+{
+ struct ipc_message resp;
+ int rc;
+
+ memset(&resp, 0, sizeof(resp));
+
+ while (1) {
+ usleep(3000);
+
+ rc = ipc_client_poll(data->client, NULL, NULL);
+ if (rc < 0)
+ continue;
+
+ rc = ipc_client_recv(data->client, &resp);
+ if (rc < 0) {
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_ERROR,
+ "Can't RECV from modem: please run this again"
+ "\n");
+ break;
+ }
+
+ modem_response_handle(data, &resp);
+
+ if (resp.data != NULL)
+ free(resp.data);
+ }
+
+ return 0;
+}
+
+int modem_dummy_read_loop(__attribute__((unused)) struct ipc_client *client)
+{
+ while (true) {
+ ipc_modem_log(client,
+ MODEM_LOG_INFO, "%s: looping\n", __func__);
+ sleep(1);
+ }
+
+ return 0;
+}
+
+int modem_start(struct ipc_client *client)
+{
+ int rc = -1;
+
+ ipc_client_data_create(client);
+ rc = ipc_client_boot(client);
+ if (rc < 0)
+ return -1;
+
+ usleep(300);
+
+ rc = ipc_client_open(client);
+ if (rc < 0)
+ return -1;
+
+ rc = ipc_client_power_on(client);
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int modem_stop(struct ipc_client *client)
+{
+ ipc_client_power_off(client);
+ ipc_client_close(client);
+
+ return 0;
+}
+
+void print_help(void)
+{
+ printf("usage: ipc-modem <command>\n"
+ "commands:\n"
+ "\tboot boot modem only\n"
+ "\tpower-on power on the modem only\n"
+ "\tpower-off power off the modem only\n"
+ "\tstart "
+ "boot modem and start read loop\n"
+ "arguments:\n"
+ "\t--call=<NUMBER> call NUMBER\n"
+ "\t--debug enable debug messages\n"
+ "\t--dry-run "
+ "Test the ipc-modem program without talking to the modem.\n"
+ "\t--help print this help message\n"
+ "\t--log-target=[stdout|syslog] "
+ "direct logs to stdout or syslog\n"
+ "\t--pin=<PIN> provide SIM card PIN\n");
+}
+
+int handle_command(struct ipc_modem_data *data)
+{
+ int rc = 0;
+
+ switch (data->command) {
+ case CMD_POWER_ON:
+ if (data->dry_run)
+ break;
+
+ rc = ipc_client_power_on(data->client);
+ if (rc < 0)
+ ipc_modem_log(data->client, "[E]",
+ "[E] Something went wrong "
+ "while powering modem on\n");
+ goto modem_quit;
+ case CMD_POWER_OFF:
+ if (data->dry_run)
+ break;
+
+ rc = ipc_client_power_off(data->client);
+ if (rc < 0)
+ ipc_modem_log(data->client,
+ MODEM_LOG_ERROR,
+ "Something went wrong "
+ "while powering modem off\n");
+ goto modem_quit;
+ case CMD_BOOT:
+ if (data->dry_run)
+ break;
+
+ rc = ipc_client_boot(data->client);
+ if (rc < 0)
+ ipc_modem_log(data->client,
+ MODEM_LOG_ERROR,
+ "Something went wrong "
+ "while bootstrapping modem\n");
+ break;
+ case CMD_START:
+ if (data->dry_run) {
+ ipc_modem_log(
+ data->client,
+ "1",
+ "Starting dummy modem_read_loop on %s client\n",
+ "FMT");
+ modem_dummy_read_loop(data->client);
+ break;
+ }
+
+ ipc_modem_log(data->client,
+ "0", "Starting modem on FMT client\n");
+
+ rc = modem_start(data->client);
+ if (rc < 0) {
+ ipc_modem_log(data->client,
+ MODEM_LOG_ERROR,
+ "Something went wrong\n");
+ modem_stop(data->client);
+ return EX_UNAVAILABLE;
+ }
+ ipc_modem_log(data->client,
+ "1",
+ "Starting modem_read_loop on FMT client\n");
+ modem_read_loop(data);
+
+ modem_stop(data->client);
+ break;
+ default:
+ /* We should handle all commands */
+ ipc_modem_log(data->client,
+ MODEM_LOG_ERROR,
+ "%s: Unknown command %d\n", __func__,
+ data->command);
+
+ assert(false);
+ }
+
+modem_quit:
+ if (data->client != 0)
+ ipc_client_destroy(data->client);
+
+ return rc;
+}
+
+void print_cmdline_opts(struct ipc_modem_data *data)
+
+{
+ if (data->debug)
+ ipc_modem_log(data->client, MODEM_LOG_INFO, "Debug enabled\n");
+ if (data->debug && data->dry_run)
+ ipc_modem_log(data->client, MODEM_LOG_INFO, "dry-run mode\n");
+}
+
+int parse_cmdline_opts(struct ipc_modem_data *data, int argc, char *argv[])
+{
+ int c = 0;
+ int opt_i = 0;
+
+ struct option opt_l[] = {
+ {"call", required_argument, 0, 0 },
+ {"debug", no_argument, 0, 0 },
+ {"dry-run", no_argument, 0, 0 },
+ {"help", no_argument, 0, 0 },
+ {"log-target", required_argument, 0, 0 },
+ {"pin", required_argument, 0, 0 },
+ {0, 0, 0, 0 }
+ };
+
+ if (argc < 2) {
+ print_help();
+ exit(EX_USAGE);
+ }
+
+ /* Handle options arguments */
+ while (true) {
+ c = getopt_long(argc, argv, "", opt_l, &opt_i);
+ if (c != 0)
+ break;
+
+ if (strcmp(opt_l[opt_i].name, "call") == 0) {
+ if (optarg) {
+ if (strlen(optarg) == 0) {
+ ipc_modem_log(data->client,
+ MODEM_LOG_ERROR,
+ "Missing call number\n");
+ return EX_USAGE;
+ } else if (strlen(optarg) < 14) {
+ assert(strlen(optarg) <
+ sizeof(data->call_number));
+ ipc_modem_log(data->client,
+ MODEM_LOG_INFO,
+ "Got call number!\n");
+ strcpy(data->call_number, optarg);
+ } else {
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_ERROR,
+ "Call number is too long!\n");
+ return EX_USAGE;
+ }
+ }
+ } else if ((strcmp(opt_l[opt_i].name, "log-target") == 0)) {
+ if (optarg) {
+ if (!strcmp(optarg, "syslog")) {
+ ipc_modem_set_log_target(LOG_TO_SYSLOG);
+ } else if (strcmp(optarg, "stdout")) {
+ ipc_modem_log(
+ data->client, MODEM_LOG_ERROR,
+ "Invalid log target '%s'\n",
+ optarg);
+ return EX_USAGE;
+ }
+ }
+ } else if (strcmp(opt_l[opt_i].name, "debug") == 0) {
+ data->debug = true;
+ } else if (strcmp(opt_l[opt_i].name, "dry-run") == 0) {
+ data->dry_run = true;
+ } else if (strncmp(opt_l[opt_i].name, "help", 4) == 0) {
+ print_help();
+ exit(0);
+ } else if ((strcmp(opt_l[opt_i].name, "pin") == 0) &&
+ (optarg)) {
+ if (strlen(optarg) < 8) {
+ assert(strlen(optarg) <
+ sizeof(data->sim_pin));
+
+ ipc_modem_log(
+ data->client,
+ MODEM_LOG_INFO, "Got SIM PIN!\n");
+ strcpy(data->sim_pin, optarg);
+ } else {
+ ipc_modem_log(data->client,
+ MODEM_LOG_ERROR,
+ "SIM PIN is too long!\n");
+ return EX_USAGE;
+ }
+ }
+ }
+
+ /* Handle non options arguments */
+ while (optind < argc) {
+ if (strncmp(argv[optind], "boot", 9) == 0) {
+ data->command = CMD_BOOT;
+ break;
+ } else if (strncmp(argv[optind], "power-on", 8) == 0) {
+ data->command = CMD_POWER_ON;
+ break;
+ } else if (strncmp(argv[optind], "power-off", 9) == 0) {
+ data->command = CMD_POWER_OFF;
+ break;
+ } else if (strncmp(argv[optind], "start", 5) == 0) {
+ data->command = CMD_START;
+ break;
+ } else {
+ ipc_modem_log(data->client,
+ MODEM_LOG_ERROR,
+ "Unknown argument: '%s'\n",
+ argv[optind]);
+ print_help();
+ return EX_USAGE;
+ }
+
+ optind++;
+ }
+
+ if (data->command == CMD_NONE) {
+ ipc_modem_log(
+ data->client, MODEM_LOG_ERROR,
+ "\n"
+ "Error: No command given. You need to use a command.\n"
+ " See the help below for more details.\n"
+ "\n");
+ print_help();
+ return EX_USAGE;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct ipc_modem_data data;
+ int ret;
+
+ bzero((void *)&data, sizeof(data));
+
+ data.client = ipc_client_create(IPC_CLIENT_TYPE_DUMMY);
+
+ ret = parse_cmdline_opts(&data, argc, argv);
+ if (ret)
+ return ret;
+
+ if (!data.dry_run) {
+ ipc_client_destroy(data.client);
+ data.client = ipc_client_create(IPC_CLIENT_TYPE_FMT);
+
+ if (data.client == 0) {
+ data.client = ipc_client_create(IPC_CLIENT_TYPE_DUMMY);
+ if (data.client)
+ ipc_modem_log(
+ data.client,
+ MODEM_LOG_ERROR,
+ "Could not create IPC client; "
+ "aborting ...\n");
+ else
+ printf("Could not create IPC client; "
+ "aborting ...\n");
+
+ return EX_UNAVAILABLE;
+ }
+ }
+
+ if (data.debug == 0)
+ ipc_client_log_callback_register(data.client,
+ modem_log_handler_quiet,
+ NULL);
+ else
+ ipc_client_log_callback_register(data.client,
+ modem_log_handler,
+ NULL);
+
+ print_cmdline_opts(&data);
+
+ return handle_command(&data);
+}
diff --git a/tools/ipc-modem/ipc-modem.h b/tools/ipc-modem/ipc-modem.h
new file mode 100644
index 0000000..0ba2f8e
--- /dev/null
+++ b/tools/ipc-modem/ipc-modem.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
+ * Copyright (C) 2011 Paul Kocialkowsk <contact@paulk.fr>
+ * Copyright (C) 2022 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 IPC_MODEM_H
+#define IPC_MODEM_H
+
+#define MODEM_STATE_LPM 0
+#define MODEM_STATE_NORMAL 2
+#define MODEM_STATE_SIM_OK 4
+
+enum command {
+ CMD_NONE,
+ CMD_START,
+ CMD_BOOT,
+ CMD_POWER_ON,
+ CMD_POWER_OFF,
+};
+
+struct ipc_modem_data {
+ struct ipc_client *client;
+ char call_number[14];
+ char sim_pin[8];
+ enum command command;
+ bool debug;
+ bool dry_run;
+ /* State */
+ bool call_done;
+ bool in_call;
+ bool out_call;
+ int state;
+ int seq;
+};
+
+#endif /* IPC_MODEM */
diff --git a/tools/ipc-modem/tests/ipc-modem.py b/tools/ipc-modem/tests/ipc-modem.py
new file mode 100755
index 0000000..d04f40d
--- /dev/null
+++ b/tools/ipc-modem/tests/ipc-modem.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python3
+#
+# This file is part of libsamsung-ipc.
+#
+# Copyright (C) 2020 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/>.
+
+import os
+import re
+import sys
+import sh
+
+# sysexits.h
+class SysExit(object):
+ #define EX_USAGE 64 /* command line usage error */
+ EX_USAGE = sh.ErrorReturnCode_64
+
+def usage(progname):
+ print('{} [test]'.format(progname))
+ sys.exit(1)
+
+def get_output(data):
+ return str(data).replace(os.linesep, '')
+
+class IpcModem(object):
+ def __init__(self):
+ srcdir = os.environ.get('srcdir', None)
+
+ command_path = ''
+ if srcdir:
+ command_path = '.' + os.sep + 'ipc-modem'
+ # Enable to run tests without automake
+ else:
+ command_path = os.path.dirname(sys.argv[0]) \
+ + os.sep \
+ + '..' \
+ + os.sep \
+ + 'ipc-modem'
+
+ if 'VALGRIND' in os.environ:
+ self.timeout = 60
+ ipc_modem = sh.Command(os.environ['VALGRIND'])
+ self.ipc_modem = ipc_modem.bake('-v',
+ '--log-file=valgrind.%p.log',
+ '--leak-check=full',
+ command_path,
+ '--dry-run')
+ else:
+ self.timeout = 3
+ ipc_modem = sh.Command(command_path)
+ self.ipc_modem = ipc_modem.bake('--dry-run')
+
+ def test_help(self):
+ try:
+ self.ipc_modem()
+ except SysExit.EX_USAGE:
+ pass
+ else:
+ raise Exception()
+
+ def test_boot(self, timeout=None):
+ if timeout==None:
+ timeout = self.timeout
+
+ self.ipc_modem('boot', _timeout=timeout)
+
+ def test_power_on(self, timeout=None):
+ if timeout==None:
+ timeout = self.timeout
+
+ self.ipc_modem('power-on', _timeout=timeout)
+
+ def test_power_off(self, timeout=None):
+ if timeout==None:
+ timeout = self.timeout
+
+ self.ipc_modem('power-off', _timeout=timeout)
+
+ def test_start(self, timeout=None):
+ if timeout==None:
+ timeout = self.timeout
+
+ try:
+ self.ipc_modem('start', _timeout=timeout)
+ except sh.TimeoutException:
+ pass
+ else:
+ raise Exception()
+
+ def test_call_with_number(self, timeout=None):
+ if timeout==None:
+ timeout = self.timeout
+
+ expected_output = "[I] Got call number!"
+ output = ""
+ try:
+ output = get_output(self.ipc_modem('power-on',
+ '--call=0102030405',
+ _timeout=timeout))
+ except:
+ raise Exception()
+
+ if output != expected_output:
+ raise Exception()
+
+ def test_call_without_number(self, timeout=None):
+ if timeout==None:
+ timeout = self.timeout
+
+ expected_output = "[E] Missing call number"
+ output = get_output(self.ipc_modem('power-on',
+ '--call=',
+ _timeout=timeout,
+ _ok_code=SysExit.EX_USAGE.exit_code))
+ if output != expected_output:
+ raise Exception()
+
+ def test_commands(self):
+ self.test_boot()
+ self.test_power_on()
+ self.test_power_off()
+ self.test_start()
+ self.test_call_with_number()
+ self.test_call_without_number()
+
+def main():
+ ipc_modem = IpcModem()
+ ipc_modem.test_help()
+ ipc_modem.test_commands()
+
+if __name__ == '__main__':
+ rc = main()
+ sys.exit(rc)
diff --git a/tools/nv_data-imei.c b/tools/nv_data-imei.c
new file mode 100644
index 0000000..aa62e0c
--- /dev/null
+++ b/tools/nv_data-imei.c
@@ -0,0 +1,1073 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2014 Paul Kocialkowsk <contact@paulk.fr>
+ * Copyright (C) 2020 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/>.
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <samsung-ipc.h>
+
+#include "../samsung-ipc/modems/xmm616/xmm616.h"
+
+#include "nv_data-imei.h"
+
+#define DEBUG 0
+
+#if DEBUG
+static int print_offset(struct offset *offset)
+{
+ printf("offset @ %p: {\n", offset);
+ printf("\tsize_t offset: 0x%x\n", offset->offset);
+ printf("\tbool option_set: %s\n",
+ offset->option_set ? "True" : "False");
+ printf("\tint error: %d\n", offset->error);
+ printf("\tchar *optarg: %s\n", offset->optarg);
+ printf("}\n");
+
+ return 0;
+}
+
+static int print_imei(struct imei *imei)
+{
+ printf("imei @ %p: {\n", imei);
+ printf("\tchar imei[%d + 1]: %s\n", IMEI_LENGTH, imei->imei);
+ printf("\tbool option_set: %s\n", imei->option_set ? "True" : "False");
+ printf("\tchar *optarg: %s\n", imei->optarg);
+ printf("}\n");
+
+ return 0;
+}
+#endif /* DEBUG */
+
+static int list_supported(void)
+{
+ /* TODO:
+ * - Print the result in a parsable format (json?)
+ * - Print the result in and a human format (a table for instance)
+ * - Add IMEI location (under the battery, unknown, etc)
+ * - Add IMEI known offsets
+ */
+ printf("Supported devices:\n");
+
+ /* Offset: 0xE80, other?
+ * Location: Under the battery
+ */
+ printf("\tNexus S (GT-I902x)\n");
+
+ return 0;
+}
+
+static int get_offset(const struct command *command, void *arg)
+{
+ struct offset *offset = arg;
+ size_t i;
+ int rc;
+ bool cmd_has_offset = !!(command->options & OPTION_OFFSET);
+ bool cmd_requires_offset = !!(command->required_options &
+ OPTION_OFFSET);
+
+ if (!cmd_has_offset && !offset->option_set)
+ return 0;
+
+ if (!cmd_has_offset && offset->option_set) {
+ printf("The %s command doesn't have an -o or --offset option\n",
+ command->name);
+ printf("See 'nv_data-imei %s -h' for more details\n",
+ command->name);
+ return -EINVAL;
+ }
+
+ if (cmd_requires_offset && !offset->option_set) {
+ printf("OFFSET option required\n");
+ printf("See nv_data-imei %s -h for more details.\n",
+ command->name);
+ return -EINVAL;
+ } else if (offset->option_set) {
+ for (i = 0; i < strlen(offset->optarg); i++) {
+ if (isspace(offset->optarg[i])) {
+ continue;
+ } else {
+ if (offset->optarg[i] == '-')
+ offset->error |= OFFSET_NEGATIVE;
+ break;
+ }
+ }
+
+ offset->offset = strtoul(offset->optarg, NULL, 0);
+ rc = errno;
+
+ if (offset->offset == ULONG_MAX && rc == ERANGE)
+ offset->error |= OFFSET_OVERFLOW;
+
+ if ((offset->error & OFFSET_NEGATIVE) &&
+ (offset->error & OFFSET_OVERFLOW))
+ printf("Error: The '%s' offset is negative "
+ "and too big as well.\n",
+ offset->optarg);
+ else if (offset->error & OFFSET_NEGATIVE)
+ printf("Error: The '%s' offset is negative"
+ " but offsets cannot be negative.\n",
+ offset->optarg);
+ else if (offset->error & OFFSET_OVERFLOW)
+ printf("Error: The '%s' offset is too big.\n",
+ offset->optarg);
+
+ if (offset->error)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_imei(const struct command *command, void *arg)
+{
+ struct imei *imei = arg;
+
+ if (command->options & OPTION_IMEI) {
+ if ((command->required_options & OPTION_IMEI) &&
+ !(imei->option_set)) {
+ printf("IMEI option required\n");
+ printf("See nv_data-imei %s -h for more details.\n",
+ command->name);
+ return -EINVAL;
+ } else if (imei->option_set) {
+ bool str_is_digit = true;
+ bool str_len_valid;
+ size_t len;
+ size_t i;
+
+ len = strlen(imei->optarg);
+ str_len_valid = !!(len == IMEI_LENGTH);
+
+ for (i = 0; i < len; i++) {
+ if (!isdigit(imei->optarg[i])) {
+ str_is_digit = false;
+ break;
+ }
+ }
+
+ if (!str_is_digit && !str_len_valid) {
+ printf("The '%s' "
+ "IMEI is invalid"
+ " as it does not only contains digits\n",
+ imei->optarg);
+ printf("In addition it is also invalid"
+ " as it is composed of "
+ "%zd digits instead of %d.\n",
+ len, IMEI_LENGTH);
+ return -EINVAL;
+ } else if (!str_is_digit) {
+ printf("The '%s' "
+ "IMEI is invalid"
+ " as it does not only contains digits\n",
+ imei->optarg);
+ return -EINVAL;
+ } else if (!str_len_valid) {
+ printf("The '%s' "
+ "IMEI is invalid as it is composed of "
+ "%zd digits instead of %d.\n",
+ imei->optarg, len, IMEI_LENGTH);
+ return -EINVAL;
+ }
+
+ /* imei.imei is IMEI_LENGTH + 1 */
+ strncpy(imei->imei, imei->optarg, IMEI_LENGTH);
+
+ return 0;
+ }
+ } else if (imei->option_set) {
+ printf("The %s command doesn't have an -i or --imei option\n",
+ command->name);
+ printf("See 'nv_data-imei %s -h' for more details\n",
+ command->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct command_option commands_options[] = {
+ {
+ OPTION_FILE,
+ "",
+ "",
+ "",
+ NULL
+ },
+ {
+ OPTION_HELP,
+ "-h|--help",
+ "Display the command specific help message",
+ "-h",
+ NULL,
+ },
+ {
+ OPTION_OFFSET,
+ "-o OFFSET|--offset=OFFSET",
+ "Use the given OFFSET",
+ "--offset=0xEC80",
+ get_offset,
+ },
+ {
+ OPTION_IMEI,
+ "-i IMEI|--imei=IMEI",
+ "Use the given IMEI",
+ "--imei=355921041234567",
+ get_imei,
+ },
+ { 0 },
+};
+
+static const struct command commands[] = {
+ {
+ "list-supported",
+ "Display supported devices and EFS",
+ NO_OPTIONS,
+ NO_OPTIONS,
+ list_supported,
+ },
+ {
+ "read-imei",
+ "Show the current IMEI from nv_data",
+ OPTION_FILE|OPTION_OFFSET,
+ OPTION_FILE,
+ read_imei,
+ },
+ {
+ "write-imei",
+ "Store the given IMEI to nv_data (may or may not work)",
+ OPTION_FILE|OPTION_IMEI|OPTION_OFFSET,
+ OPTION_FILE|OPTION_IMEI|OPTION_OFFSET,
+ write_imei,
+ },
+ {
+ "bruteforce-imei",
+ "Find the IMEI offset in the nv_data with the given IMEI",
+ OPTION_FILE|OPTION_IMEI,
+ OPTION_FILE|OPTION_IMEI,
+ bruteforce_imei_offset,
+ },
+ { 0 },
+};
+
+#if DEBUG
+static int print_args(int argc, char *argv[], int optind_index)
+{
+ int i;
+
+ printf("argc: %d optind: %d ", argc, optind_index);
+ for (i = 0; i < argc; i++) {
+ printf("[%d]%s", i, argv[i]);
+ if (i != (argc - 1))
+ printf(" ");
+ }
+ printf("\n");
+
+ return 0;
+}
+#endif /* DEBUG */
+
+static const char warning_msg[] =
+ "\n"
+ "+------------------------------------------------------+\n"
+ "| /!\\ This tool is experimental, use at your own risk |\n"
+ "+------------------------------------------------------+\n"
+ "\n"
+ "It is also dangerous if used improperly: This tool can overwrite any\n"
+ "part of the nv_data.bin file, without any checks or warnings: If you\n"
+ "give it any location/offset inside that file, it will proceed\n"
+ "blindly. This raises several concerns:\n"
+ "- As we don't know how to recreate valid nv_data.bin files from\n"
+ " scratch, so you will need to make a backup of it before. We can\n"
+ " recreate a dummy one, however the result is that it ends up with a\n"
+ " generic IMEI. This means that most networks will refuse to let you\n"
+ " register and use their services, which will prevent you from doing\n"
+ " regular calls / SMS. Changing the IMEI in this generic file has\n"
+ " not been tested. It's unknown if some other parameters also need\n"
+ " to be changed to make it work.\n"
+ "- As we don't know much about the content of the nv_data.bin file,\n"
+ " it could potentially be dangerous to modify data in the wrong\n"
+ " location as we don't know the effects. Effects like disrupting the\n"
+ " telephony network which could in turn prevent people from calling\n"
+ " medial emergency services cannot be excluded as this file contains\n"
+ " modem data / parameters and we don't know what they do.\n"
+ "\n"
+ "How to use this program.\n"
+ "- First you need to obtain your current IMEI. This can be done\n"
+ " through various ways, from looking at the sticker that is written\n"
+ " under the back cover of your phone, to software means like looking\n"
+ " in Settings->About Phone->Status->IMEI information in Replicant 6.\n"
+ "- Then once you have the IMEI you can either use the show-imei\n"
+ " command and verify that the text you get matches the IMEI you're\n"
+ " supposed to have, or you can also try to bruteforce the IMEI\n"
+ " location with the known IMEI.\n"
+ "- Once this is done you can change the IMEI, and confirm it has been\n"
+ " changed by looking at\n"
+ " Settings->About Phone->Status->IMEI information in Replicant 6 or\n"
+ " through other software means.\n"
+ "\n"
+ "In the case where you don't have a valid IMEI, and you are still\n"
+ "trying to change it (knowing the risks), you will need not to forget\n"
+ "to verify if it has been changed by looking at\n"
+ "Settings->About Phone->Status->IMEI information in Replicant 6 or\n"
+ "through other software means. This will make sure that you only\n"
+ "modified the offset where the IMEI is really stored and not some\n"
+ "random offset with potentially crucial modem data.\n"
+;
+
+static void print_warnings(void)
+{
+ printf("%s", warning_msg);
+}
+
+/* TODO: Enforce type to only allow valid OPTION_* */
+static const struct command_option *get_option(uint8_t given_option)
+{
+ int i = 0;
+
+ while (true) {
+ const struct command_option *command_option =
+ &(commands_options[i++]);
+
+ /* TODO: Get C to do something like if (!option) */
+ if (!command_option->option)
+ break;
+
+ if (command_option->option == given_option)
+ return command_option;
+ }
+
+ return NULL;
+}
+
+static int print_all_options(void)
+{
+ int i = 0;
+
+ while (true) {
+ const struct command_option *option = &(commands_options[i++]);
+
+ /* TODO: Get C to do something like if (!option) */
+ if (!option->option)
+ break;
+
+ /* Skip options without help like OPTION_FILE */
+ if (strlen(option->option_string))
+ printf("\t%s # %s\n", option->option_string,
+ option->help);
+ }
+
+ return 0;
+}
+
+static int nv_data_imei_help(void)
+{
+ int i = 0;
+
+ print_warnings();
+ printf("\n");
+
+ printf("Usage:\n");
+ printf("\tnv_data-imei FILE COMMAND [OPTIONS]\n");
+ printf("\tnv_data-imei COMMAND -h|--help "
+ "# Display the command specific help message\n");
+
+ printf("Commands:\n");
+
+ while (true) {
+ const struct command *cmd = &(commands[i++]);
+
+ /* TODO: Get C to do something like if (!cmd) */
+ if (!cmd->name)
+ break;
+
+ assert(cmd->name);
+ assert(cmd->help);
+ printf("\t%s # %s\n", cmd->name, cmd->help);
+ }
+
+ printf("Options:\n");
+ print_all_options();
+
+ return 0;
+}
+
+static const struct command *get_command(const char *name)
+{
+ int i = 0;
+
+ while (true) {
+ const struct command *cmd = &(commands[i++]);
+
+ /* TODO: Get C to do something like if (!cmd) */
+ if (!cmd->name)
+ break;
+
+ if (strlen(cmd->name) != strlen(name))
+ continue;
+
+ if (!strncmp(cmd->name, name, strlen(cmd->name)))
+ return cmd;
+ }
+
+ return NULL;
+
+}
+
+static int command_help(const char *command_name)
+{
+
+ const struct command *command;
+ size_t i;
+
+ command = get_command(command_name);
+ if (!command)
+ return EX_USAGE;
+
+ printf("Usage:\n");
+
+ printf("\tnv_data-imei %s%s",
+ (command->options & OPTION_FILE) ? "FILE " : "",
+ command->name);
+
+ if (command->options) {
+ for (i = 0; i < (8 * sizeof(command->options)); i++) {
+ if (command->options & BIT(i)) {
+ bool required = !!(command->required_options &
+ BIT(i));
+ const struct command_option *option =
+ get_option(command->options & BIT(i));
+
+ /* Check if option and commands are in sync */
+ assert(option != NULL);
+
+ if (strlen(option->option_string)) {
+ if (required)
+ printf(" <%s>",
+ option->option_string);
+ else
+ printf(" [%s]",
+ option->option_string);
+ }
+ }
+ }
+ }
+
+ printf("\n");
+
+ if (command->options) {
+ printf("Options:\n");
+ for (i = 0; i < (8 * sizeof(command->options)); i++) {
+ if (command->options & BIT(i)) {
+ const struct command_option *option =
+ get_option(command->options & BIT(i));
+
+ /* Check if option and commands are in sync */
+ assert(option != NULL);
+
+ if (strlen(option->option_string))
+ printf("\t%s #%s\n",
+ option->option_string,
+ option->help);
+ }
+ }
+ }
+
+ printf("Example:\n");
+
+ printf("\tnv_data-imei %s%s",
+ (command->options & OPTION_FILE) ?
+ "./efs_backup_copy/nv_data.bin" : "",
+ command->name);
+
+ if (command->options) {
+ for (i = 0; i < (8 * sizeof(command->options)); i++) {
+ if (command->required_options & BIT(i)) {
+ const struct command_option *option =
+ get_option(command->options & BIT(i));
+
+ /* Check if option and commands are in sync */
+ assert(option != NULL);
+
+ printf(" %s", option->example);
+ }
+ }
+ }
+
+ printf("\n");
+
+ return 0;
+}
+
+static void modem_log_handler(__attribute__((unused)) 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;
+ }
+ printf("%s\n", message);
+ }
+
+ free(message);
+}
+
+static int ipc_setup(struct ipc_client **client)
+{
+ *client = ipc_client_create(IPC_CLIENT_TYPE_DUMMY);
+ if (*client == NULL) {
+ printf("Creating client failed\n");
+ return -EBADE;
+ }
+
+ ipc_client_log_callback_register(*client, modem_log_handler,
+ NULL);
+
+ return 0;
+}
+
+static int decode_imei(unsigned char *buf, struct imei *imei)
+{
+ int i = 0;
+
+ i += snprintf(imei->imei + i, IMEI_LENGTH + 1 - i, "%01x",
+ (*buf & 0xf0) >> 4);
+
+ buf += sizeof(unsigned char);
+
+ while (i < IMEI_LENGTH) {
+ i += snprintf(imei->imei + i, IMEI_LENGTH + 1 - i,
+ "%02x",
+ (*buf >> 4) | ((*buf & 0x0f) << 4));
+ buf += sizeof(unsigned char);
+ }
+
+ return 0;
+}
+
+static int encode_imei(unsigned char *buf, struct imei *imei)
+{
+ int i = 0;
+ unsigned int v;
+ int count = 0;
+
+ count = sscanf(imei->imei, "%01x", &v);
+ if (count != 1) {
+ printf("%s: first sscanf failed with result: %d\n",
+ __func__, count);
+ assert(false);
+ }
+
+ *buf++ = (v << 4) | 0xA;
+
+ i++;
+ while (i < IMEI_LENGTH) {
+ count = sscanf(imei->imei + i, "%02x", &v);
+ if (count != 1) {
+ printf("%s: second sscanf failed with result: %d\n",
+ __func__, count);
+ assert(false);
+ }
+
+ *buf++ = v << 4 | ((v & 0xf0) >> 4);
+ i += 2;
+ }
+
+ return 0;
+}
+
+int bruteforce_imei_offset(char *nv_data_path, struct imei *given_imei)
+{
+ struct ipc_client *client = NULL;
+ size_t file_size;
+ size_t search_size;
+ size_t nv_data_chunk_size;
+ char *buffer = NULL;
+ char *ptr = NULL;
+ unsigned char given_imei_buffer[(IMEI_LENGTH + 1) / 2] = { 0 };
+ bool found_imei = false;
+ int rc;
+
+ rc = ipc_setup(&client);
+ if (rc)
+ return rc;
+
+ ipc_client_log(client,
+ "Starting bruteforce\nnv_data_path: %s",
+ nv_data_path);
+
+ /* The sizes are device dependent, so ipc_client_nv_data_size and
+ * ipc_client_nv_data_chunk_size were used before.
+ * However we want the tool to also be able to run on any computer,
+ * instead of just being able to run on a device.
+ */
+ file_size = file_data_size(client, nv_data_path);
+ if (file_size == (size_t)-1) {
+ rc = errno;
+ goto error;
+ }
+
+ ipc_client_log(client, "nv_data size: %d\n", file_size);
+
+ /* We only support one device so far */
+ nv_data_chunk_size = XMM616_NV_DATA_CHUNK_SIZE;
+
+ buffer = file_data_read(client, nv_data_path, file_size,
+ nv_data_chunk_size, 0);
+
+ if (buffer == NULL) {
+ ipc_client_log(client, "Reading nv_data failed");
+ rc = -1;
+ goto error;
+ }
+
+ rc = encode_imei((unsigned char *)&given_imei_buffer, given_imei);
+ if (rc < 0)
+ return rc;
+
+ ptr = buffer;
+ search_size = file_size;
+
+ do {
+ ptr = memchr(ptr, given_imei_buffer[0], search_size);
+ if (ptr) {
+ if (!strncmp((void*)given_imei_buffer, ptr,
+ sizeof(given_imei_buffer))) {
+ ipc_client_log(client,
+ "=> Found IMEI at 0x%x (%d)",
+ (ptr - buffer),
+ (ptr - buffer));
+ found_imei = true;
+ }
+
+ /* Continue searching even if we already found
+ * it just in case we find the IMEI at a second
+ * location too.
+ */
+ search_size = file_size - (ptr - buffer);
+ ptr ++;
+ }
+ } while (ptr);
+
+ if (!found_imei) {
+ rc = 0;
+ ipc_client_log(client, "=> IMEI not found");
+ }
+
+error:
+ if (buffer)
+ free(buffer);
+
+ ipc_client_destroy(client);
+
+ return rc;
+}
+
+int read_imei(char *nv_data_path, struct offset *offset)
+{
+ struct ipc_client *client = NULL;
+ struct imei imei;
+ size_t file_size;
+ size_t nv_data_chunk_size;
+ unsigned char *buffer = NULL;
+ int rc;
+
+ memset(&imei, 0, sizeof(imei));
+
+ rc = ipc_setup(&client);
+ if (rc)
+ return rc;
+
+ /* We only support one device so far */
+ file_size = XMM616_NV_DATA_SIZE;
+ nv_data_chunk_size = XMM616_NV_DATA_CHUNK_SIZE;
+
+ buffer = file_data_read(client, nv_data_path, file_size,
+ nv_data_chunk_size, 0);
+ if (buffer == NULL) {
+ ipc_client_log(client, "Reading nv_data failed\n");
+ rc = -1;
+ goto error;
+ }
+
+ rc = decode_imei(buffer + offset->offset, &imei);
+ if (rc)
+ goto error;
+
+ ipc_client_log(client, "IMEI: %s\n", imei.imei);
+
+ rc = 0;
+ goto complete;
+
+error:
+complete:
+ if (buffer)
+ free(buffer);
+
+ ipc_client_destroy(client);
+
+ return rc;
+}
+
+int write_imei(char *nv_data_path, struct offset *offset,
+ struct imei *imei)
+{
+ struct ipc_client *client = NULL;
+ char *md5_path = NULL;
+ char *nv_data_secret;
+ size_t nv_data_chunk_size;
+ size_t file_size;
+ char *md5_string = NULL;
+ unsigned char buffer[(IMEI_LENGTH + 1) / 2] = { 0 };
+ size_t length;
+ int rc;
+
+ rc = ipc_setup(&client);
+ if (rc)
+ return rc;
+
+ assert(imei->imei);
+ assert(strlen(imei->imei) == IMEI_LENGTH);
+
+ rc = asprintf(&md5_path, "%s.md5", nv_data_path);
+ if (rc == -1) {
+ ipc_client_log(client, "%s: asprintf failed", __func__);
+ return -1;
+ }
+
+ /* We only support one device so far */
+ nv_data_secret = XMM616_NV_DATA_SECRET;
+ file_size = XMM616_NV_DATA_SIZE;
+ nv_data_chunk_size = XMM616_NV_DATA_CHUNK_SIZE;
+
+ rc = encode_imei((unsigned char *)&buffer, imei);
+ if (rc < 0)
+ return rc;
+
+ rc = file_data_write(client, nv_data_path, buffer, sizeof(buffer),
+ sizeof(buffer), offset->offset);
+ if (rc == -1) {
+ rc = errno;
+ ipc_client_log(client, "Writing nv_data failed\n");
+ goto complete;
+ }
+
+ md5_string = ipc_nv_data_md5_calculate(client, nv_data_path,
+ nv_data_secret, file_size,
+ nv_data_chunk_size);
+ if (md5_string == NULL) {
+ ipc_client_log(client, "Calculating nv_data md5 failed\n");
+ goto error;
+ }
+
+ length = strlen(md5_string);
+
+ unlink(md5_path);
+
+ rc = file_data_write(client, md5_path, md5_string, length, length, 0);
+ if (rc == -1) {
+ rc = errno;
+ ipc_client_log(client, "Writing nv_data md5 failed\n");
+ goto complete;
+ }
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (md5_path)
+ free(md5_path);
+
+ ipc_client_destroy(client);
+
+ return rc;
+}
+
+static int errno_to_sysexit(int err)
+{
+ switch (err) {
+ case 0:
+ return EX_OK;
+ case EACCES:
+ return EX_NOINPUT;
+ case -EINVAL:
+ return EX_USAGE;
+ default:
+ printf("%s: error: unknown error code %d.\n", __func__, err);
+ printf("%s: error code %d needs to be implemented\n", __func__,
+ err);
+ assert(false);
+ }
+
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ opterr = 0;
+ struct imei imei;
+ struct offset offset;
+ const struct command *command = NULL;
+ const struct command_option *option = NULL;
+ char *nv_data_path = NULL;
+ int c, rc;
+
+ memset(&imei, 0, sizeof(imei));
+ memset(&offset, 0, sizeof(offset));
+
+ if (argc == 1) {
+ printf("Not enough options.\n");
+ printf("Try -h to print the help.\n");
+ return EX_USAGE;
+ }
+
+ while (1) {
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h' },
+ {"imei", required_argument, 0, 'i' },
+ {"offset", required_argument, 0, 'o' },
+ {0, 0, 0, 0 }
+ };
+
+ c = getopt_long(argc, argv, "-hi:o:", long_options, NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 1:
+ /* from "man 3 getopt": If the first character of
+ * optstring is '-', then each nonoption argv-element is
+ * handled as if it were the argument of an option with
+ * character code 1. (This is used by programs that were
+ * written to expect options and other argv-elements in
+ * any order and that care about the ordering of the
+ * two.)
+ */
+
+ /* nv_data-imei <argument> */
+ if (optind == 2 && argc == 2) {
+ command = get_command(argv[optind - 1]);
+ /* Example: nv_data-imei list-supported */
+ if (command && command->options == NO_OPTIONS) {
+ rc = command->func();
+ return errno_to_sysexit(rc);
+ } else if (command) {
+ /* The other commands than
+ * list-supported need at least a file
+ * argument so we don't need to handle
+ * all missing options
+ */
+ if (command->options & OPTION_FILE) {
+ printf("Error: the '%s' command "
+ "needs a FILE argument.\n",
+ argv[optind - 1]);
+ printf("See 'nv_data-imei %s -h'"
+ " for more details.\n",
+ argv[optind - 1]);
+ }
+ return EX_USAGE;
+ } else {
+ printf("There is no '%s' command\n",
+ argv[optind - 1]);
+ printf("Try nv_data-imei -h"
+ " to print the help.\n");
+ return EX_USAGE;
+ }
+ /* nv_data-imei FILE COMMAND [...] */
+ } else if (optind == 3 && argc >= 3) {
+ nv_data_path = argv[optind - 2];
+ command = get_command(argv[optind - 1]);
+ if (!command) {
+ printf("There is no '%s' command\n",
+ argv[optind - 1]);
+ printf("Try nv_data-imei -h"
+ " to print the help.\n");
+ return EX_USAGE;
+ }
+ /* Some commands don't take arguments nor files.
+ * The help command is already handled but some
+ * other command like list-supported need to be
+ * handled here.
+ * nv_data-imei FILE list-supported
+ */
+ if (!command->options) {
+ printf("The '%s' command"
+ " accepts no options\n",
+ argv[2]);
+ printf("Try nv_data-imei %s --help to"
+ " print the %s command help.\n",
+ argv[optind - 1],
+ argv[optind - 1]);
+ return EX_USAGE;
+ }
+ }
+ break;
+ case 'h':
+ /* nv_data-imei -h|--help */
+ if (argc == 2) {
+ return nv_data_imei_help();
+
+ /* nv_data-imei COMMAND -h|--help */
+ } else if (argc == 3) {
+ rc = command_help(argv[1]);
+ if (rc) {
+ printf("There is no '%s' command\n",
+ argv[1]);
+ printf("Try nv_data-imei -h"
+ " to print the help.\n");
+ return rc;
+ }
+
+ /* nv_data-imei FILE COMMAND -h|--help|help is
+ * not supported because I didn't find an easy
+ * and robust way to differentiate between
+ * argv[1] being a file or a command. In other
+ * words If it was, supported, and that we are
+ * here, what would be the command? argv[2] or
+ * argv[3]? How to know for sure that argv[2] is
+ * really a command and not a file of the same
+ * name than the command?
+ */
+
+ return 0;
+ } else if (argc > 3) {
+ printf("Wrong number of arguments."
+ " Try 'nv_data-imei COMMAND -h' instead"
+ "\n");
+ printf("Example:\n");
+ printf("\tnv_data-imei %s -h\n",
+ commands[0].name);
+ return EX_USAGE;
+ }
+ break;
+ case 'i':
+ imei.optarg = optarg;
+ if (imei.option_set) {
+ printf("The %s command doesn't have an -i"
+ " or --imei option\n",
+ command->name);
+ printf("See 'nv_data-imei %s -h'"
+ " for more details\n",
+ commands->name);
+ return EX_USAGE;
+ }
+
+ imei.option_set = true;
+
+ break;
+ case 'o':
+ offset.optarg = optarg;
+ if (offset.option_set) {
+ printf("The %s command"
+ " doesn't have an -o or --offset option"
+ "\n", command->name);
+ printf("See 'nv_data-imei %s -h'"
+ " for more details\n",
+ commands->name);
+ return EX_USAGE;
+ }
+
+ offset.option_set = true;
+
+ break;
+ case '?':
+ printf("Unknown option '%s'.\n", argv[optind - 1]);
+ printf("Try nv_data-imei -h to print the help.\n");
+ return EX_USAGE;
+ default:
+ printf("case '%c':\n", c);
+ printf("Unknown option '%s'.\n", argv[optind - 1]);
+ printf("Try nv_data-imei -h to print the help.\n");
+ return EX_USAGE;
+ }
+ }
+
+ /* We use the - in optstring so all arguments go in the 'case 1:' */
+ assert(optind == argc);
+
+ if (argc == 2 || command == NULL) {
+ /* If none of the commands or options were reached, we are in
+ * the case where users ran 'nv_data-imei FILE' or used some
+ * options like -i <argument> without any command.
+ */
+ printf("Missing options, command or invalid command '%s'\n",
+ argv[1]);
+ printf("Try -h to print the help.\n");
+ return EX_USAGE;
+ }
+
+ assert(command->options & OPTION_FILE);
+ assert(command->func);
+
+
+ option = get_option(OPTION_IMEI);
+ rc = option->get_data(command, &imei);
+ if (rc)
+ return errno_to_sysexit(rc);
+
+ option = get_option(OPTION_OFFSET);
+
+ rc = option->get_data(command, &offset);
+ if (rc)
+ return errno_to_sysexit(rc);
+
+ if (command->options & OPTION_IMEI &&
+ command->options & OPTION_OFFSET) {
+ rc = command->func(nv_data_path, &offset, &imei);
+ return errno_to_sysexit(rc);
+ }
+
+ if (command->options & OPTION_IMEI) {
+ rc = command->func(nv_data_path, &imei);
+ return errno_to_sysexit(rc);
+ }
+
+ if (command->options & OPTION_OFFSET) {
+ rc = command->func(nv_data_path, &offset);
+ return errno_to_sysexit(rc);
+ }
+
+ assert(false);
+
+ return 0;
+}
diff --git a/tools/nv_data-imei.h b/tools/nv_data-imei.h
new file mode 100644
index 0000000..7a153c2
--- /dev/null
+++ b/tools/nv_data-imei.h
@@ -0,0 +1,82 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2014 Paul Kocialkowsk <contact@paulk.fr>
+ * Copyright (C) 2020 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 NV_DATA_IMEI_H
+#define NV_DATA_IMEI_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#define BIT(n) (1<<n)
+
+#define IMEI_LENGTH 15
+
+extern int opterr;
+
+/* This enables to enforce the size limit */
+struct imei {
+ char imei[IMEI_LENGTH + 1];
+ bool option_set;
+ char *optarg;
+};
+
+#define OFFSET_NEGATIVE BIT(0)
+#define OFFSET_OVERFLOW BIT(1)
+
+struct offset {
+ size_t offset;
+ bool option_set;
+ int error;
+ char *optarg;
+};
+
+/* So far we support only one device and IMEI offset, but more offsets do exist
+ * as the original code from Paul Kocialkowski used the 0xE880 offset instead.
+ * We don't know yet if multiple offsets can work for one device.
+ */
+#define DEFAULT_IMEI_OFFSET 0xEC80
+
+struct command {
+ const char *name;
+ const char *help;
+ uint8_t options;
+ uint8_t required_options;
+ int (*func)(); /* TODO: enfroce argument types */
+};
+
+struct command_option {
+ uint8_t option;
+ const char *option_string;
+ const char *help;
+ const char *example;
+ int (*get_data)(const struct command *command, void *arg);
+};
+
+#define NO_OPTIONS 0
+#define OPTION_FILE BIT(0)
+#define OPTION_HELP BIT(1)
+#define OPTION_IMEI BIT(2)
+#define OPTION_OFFSET BIT(3)
+
+int bruteforce_imei_offset(char *nv_data_path, struct imei *given_imei);
+int read_imei(char *nv_data_path, struct offset *offset);
+int write_imei(char *nv_data_path, struct offset *offset, struct imei *imei);
+
+#endif /* NV_DATA_IMEI_H */
diff --git a/tools/nv_data-md5.c b/tools/nv_data-md5.c
index e8c9fc8..5edb257 100644
--- a/tools/nv_data-md5.c
+++ b/tools/nv_data-md5.c
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <sys/types.h>
@@ -100,4 +101,6 @@ int main(int argc, char *argv[])
error:
if (client != NULL)
ipc_client_destroy(client);
+
+ return EX_SOFTWARE;
}
diff --git a/tools/tests/nv_data-imei.py b/tools/tests/nv_data-imei.py
new file mode 100755
index 0000000..3447690
--- /dev/null
+++ b/tools/tests/nv_data-imei.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python3
+#
+# This file is part of libsamsung-ipc.
+#
+# Copyright (C) 2020 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/>.
+
+import os
+import re
+import sys
+import sh
+
+# sysexits.h
+class SysExit(object):
+ #define EX_USAGE 64 /* command line usage error */
+ EX_USAGE = sh.ErrorReturnCode_64
+ #define EX_NOINPUT 66 /* cannot open input */
+ EX_NOINPUT = sh.ErrorReturnCode_66
+
+def usage(progname):
+ print('{} [test]'.format(progname))
+ sys.exit(1)
+
+commands = [
+ 'list-supported',
+ 'read-imei',
+ 'write-imei',
+ 'bruteforce-imei',
+]
+
+def get_output(data):
+ return str(data).replace(os.linesep, '')
+
+class NvDataImei(object):
+ def __init__(self):
+ srcdir = os.environ.get('srcdir', None)
+
+ command_path = ''
+ if srcdir:
+ command_path = '.' + os.sep + 'nv_data-imei'
+ # Enable to run tests without automake
+ else:
+ command_path = os.path.dirname(sys.argv[0]) \
+ + os.sep \
+ + '..' \
+ + os.sep \
+ + 'nv_data-imei'
+
+ if 'VALGRIND' in os.environ:
+ self.nv_data_imei = sh.Command(os.environ['VALGRIND'])
+ self.nv_data_imei = self.nv_data_imei.bake(
+ '-v',
+ '--log-file=valgrind.%p.log',
+ '--leak-check=full',
+ command_path)
+ else:
+ self.nv_data_imei = sh.Command(command_path)
+
+ def test_help(self):
+ try:
+ self.nv_data_imei('')
+ except SysExit.EX_USAGE:
+ pass
+ else:
+ raise Exception()
+
+ for help_arg in ['-h', '--help']:
+ self.nv_data_imei(help_arg)
+ for command in commands:
+ self.nv_data_imei(command, help_arg)
+ try:
+ self.nv_data_imei('file', command, help_arg)
+ except SysExit.EX_USAGE:
+ pass
+ else:
+ raise Exception()
+
+ self.nv_data_imei('list-supported')
+
+ def test_commands(self):
+ # Create nv_data.bin
+ valid_imei = '123456789012345'
+ offset = 0x100
+ XMM616_NV_DATA_SIZE = 0x200000
+ nv_data_bin = get_output(sh.mktemp())
+ sh.ddrescue('/dev/zero', nv_data_bin, '-s', str(XMM616_NV_DATA_SIZE))
+
+ self.nv_data_imei(nv_data_bin, 'write-imei', '-o', str(hex(offset)),
+ '-i', valid_imei)
+ output = get_output(self.nv_data_imei(nv_data_bin, 'read-imei', '-o',
+ str(hex(offset))))
+ print(output)
+ expect = 'IMEI: ' + valid_imei
+ if output != expect:
+ raise Exception()
+
+ output = get_output(self.nv_data_imei(nv_data_bin, 'bruteforce-imei',
+ '-i', valid_imei))
+ print(output)
+ expect = re.escape('Found IMEI at {} ({})'.format(str(hex(offset)),
+ offset))
+ if not re.search(expect, output):
+ raise Exception()
+
+ inaccessible_nv_data_bin = str(sh.mktemp('-u')).replace(os.linesep,'')
+ sh.ddrescue('/dev/zero', inaccessible_nv_data_bin, '-s',
+ str(XMM616_NV_DATA_SIZE))
+ sh.chmod('000', inaccessible_nv_data_bin);
+ try:
+ self.nv_data_imei(inaccessible_nv_data_bin, 'write-imei',
+ '-o', '0x0', '-i', valid_imei)
+ self.nv_data_imei(inaccessible_nv_data_bin, 'read-imei',
+ '-o', '0x0')
+ self.nv_data_imei(inaccessible_nv_data_bin, 'bruteforce-imei',
+ '-i', valid_imei)
+ except SysExit.EX_NOINPUT:
+ pass
+ else:
+ raise Exception()
+
+ os.unlink(inaccessible_nv_data_bin)
+ os.unlink(nv_data_bin)
+ os.unlink(nv_data_bin + '.md5')
+
+def main():
+ nv_data_imei = NvDataImei()
+ nv_data_imei.test_help()
+ nv_data_imei.test_commands()
+
+if __name__ == '__main__':
+ rc = main()
+ sys.exit(rc)
diff --git a/tools/tests/nv_data-md5.py b/tools/tests/nv_data-md5.py
new file mode 100755
index 0000000..374ded2
--- /dev/null
+++ b/tools/tests/nv_data-md5.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+#
+# This file is part of libsamsung-ipc.
+#
+# Copyright (C) 2020 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/>.
+
+import os
+import re
+import sys
+import sh
+
+def usage(progname):
+ print('{} [test]'.format(progname))
+ sys.exit(1)
+
+def get_output(data):
+ return str(data).replace(os.linesep, '')
+
+class NvDataMD5(object):
+ def __init__(self):
+ srcdir = os.environ.get('srcdir', None)
+
+ command_path = ''
+ if srcdir:
+ command_path = '.' + os.sep + 'nv_data-md5'
+ # Enable to run tests without automake
+ else:
+ command_path = os.path.dirname(sys.argv[0]) \
+ + os.sep \
+ + '..' \
+ + os.sep \
+ + 'nv_data-md5'
+
+ if 'VALGRIND' in os.environ:
+ self.nv_data_md5 = sh.Command(os.environ['VALGRIND'])
+ self.nv_data_md5 = self.nv_data_md5.bake(
+ '-v',
+ '--log-file=valgrind.%p.log',
+ '--leak-check=full',
+ command_path)
+ else:
+ self.nv_data_md5 = sh.Command(command_path)
+ def test_help(self):
+ try:
+ self.nv_data_md5()
+ except sh.ErrorReturnCode_1:
+ pass
+ else:
+ raise Exception()
+
+ def test_commands(self):
+ expected_md5 = '5293814414abb3831e3fc1a1b35e69bc'
+ NV_DATA_SIZE = 0x200000
+ nv_data_bin = get_output(sh.mktemp())
+
+ # Create nv_data.bin
+ sh.ddrescue('/dev/zero', nv_data_bin, '-s', str(NV_DATA_SIZE))
+
+ output = get_output(self.nv_data_md5(nv_data_bin))
+
+ print(output)
+
+ if output != expected_md5:
+ raise Exception()
+
+ os.unlink(nv_data_bin)
+
+def main():
+ nv_data_md5 = NvDataMD5()
+ nv_data_md5.test_help()
+ nv_data_md5.test_commands()
+
+if __name__ == '__main__':
+ rc = main()
+ sys.exit(rc)