diff --git a/src/plugins/intel/mm-xmmrpc-xmm7360-protocol.c b/src/plugins/intel/mm-xmmrpc-xmm7360-protocol.c index 336987fe..e4440e0a 100644 --- a/src/plugins/intel/mm-xmmrpc-xmm7360-protocol.c +++ b/src/plugins/intel/mm-xmmrpc-xmm7360-protocol.c @@ -21,6 +21,9 @@ #include #include +#include +#define _LIBMM_INSIDE_MM +#include #include "mm-xmmrpc-xmm7360-protocol.h" #include "mm-intel-enums-types.h" @@ -50,7 +53,7 @@ xmm7360_rpc_response_free (Xmm7360RpcResponse *response) g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, fmt, __VA_ARGS__); \ } -static gint +gint xmm7360_byte_array_read_asn_int (GByteArray *buf, gsize offset, gint *out_val, @@ -64,7 +67,7 @@ xmm7360_byte_array_read_asn_int (GByteArray *buf, if (buf->len <= offset + 2) { PARSE_ERROR ("initial buffer size %u too small (need %zu)", - buf->len, offset + 2); + buf->len, offset + 2 + 1); return -1; } @@ -116,7 +119,7 @@ xmm7360_byte_array_read_asn_int (GByteArray *buf, return offset - orig_offset; } -static gint +gint xmm7360_byte_array_read_string (GByteArray *buf, gsize offset, Xmm7360RpcMsgArg *out_arg, @@ -217,14 +220,14 @@ xmm7360_byte_array_append_asn_int4 (GByteArray *buf, gint32 value) g_byte_array_append (buf, (const guint8 *) &value_be, 4); } -static void +void xmm7360_byte_array_append_uint8 (GByteArray *buf, gulong val) { guint8 _val = (guint8) val; g_byte_array_append (buf, &_val, 1); } -static void +void xmm7360_byte_array_append_string (GByteArray *buf, const guint8 *data, gsize data_len, @@ -413,7 +416,7 @@ xmm7360_command_to_byte_array (Xmm7360RpcCallId callid, return buf; } -static gboolean +gboolean xmm7360_rpc_msg_body_unpack (GByteArray *buf, GPtrArray *args, GError **error) { gsize offset; diff --git a/src/plugins/intel/mm-xmmrpc-xmm7360-protocol.h b/src/plugins/intel/mm-xmmrpc-xmm7360-protocol.h index 8531ba46..e02e2ea3 100644 --- a/src/plugins/intel/mm-xmmrpc-xmm7360-protocol.h +++ b/src/plugins/intel/mm-xmmrpc-xmm7360-protocol.h @@ -526,9 +526,28 @@ typedef struct { /*****************************************************************************/ +gint xmm7360_byte_array_read_asn_int (GByteArray *buf, + gsize offset, + gint *out_val, + Xmm7360RpcMsgArg *out_arg, + GError **error); + +gint xmm7360_byte_array_read_string (GByteArray *buf, + gsize offset, + Xmm7360RpcMsgArg *out_arg, + GError **error); + void xmm7360_byte_array_append_asn_int4 (GByteArray *array, gint32 value); +void xmm7360_byte_array_append_uint8 (GByteArray *buf, + gulong val); + +void xmm7360_byte_array_append_string (GByteArray *buf, + const guint8 *data, + gsize data_len, + guint data_len_padded); + void xmm7360_rpc_response_free (Xmm7360RpcResponse *msg); GByteArray * xmm7360_rpc_args_to_byte_array (const Xmm7360RpcMsgArg *args); @@ -544,6 +563,10 @@ GString * xmm7360_rpc_args_to_string (GPtrArray GString * xmm7360_byte_array_hexlify (GByteArray *buf); +gboolean xmm7360_rpc_msg_body_unpack (GByteArray *buf, + GPtrArray *args, + GError **error); + G_DEFINE_AUTOPTR_CLEANUP_FUNC (Xmm7360RpcResponse, xmm7360_rpc_response_free); #endif /* MM_XMMRPC_XMM7360_PROTOCOL_H */ diff --git a/src/plugins/intel/tests/test-xmmrpc-xmm7360-protocol.c b/src/plugins/intel/tests/test-xmmrpc-xmm7360-protocol.c new file mode 100644 index 00000000..2de796cf --- /dev/null +++ b/src/plugins/intel/tests/test-xmmrpc-xmm7360-protocol.c @@ -0,0 +1,341 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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 2 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 General Public License for more details: + * + * Copyright (C) 2018 Aleksander Morgado + */ + +#include +#include +#include + +#include +#define _LIBMM_INSIDE_MM +#include + +#include "mm-log-test.h" +#include "mm-modem-helpers.h" +#include "mm-xmmrpc-xmm7360-protocol.h" + +#define XMM_BUFFER(...) \ + .buffer = { __VA_ARGS__ }, \ + .buffer_size = sizeof((guint8[]){ __VA_ARGS__ }), + +#define XMM_STRING_BUFFER(str_type, str_len, ...) \ + .buffer = { str_type, \ + str_len, \ + 0x02, /* len_padded: ASN int start marker */ \ + 0x01, /* len_padded: ASN int size 1 */ \ + str_len * (str_type == 0x55 ? 1 : str_type == 0x56 ? 2 : str_type == 0x57 ? 4 : 0), /* len_padded: ASN int val */ \ + 0x02, /* pad_len: ASN int start marker */ \ + 0x01, /* pad_len: ASN int size 1 */ \ + 0x00, /* pad_len: ASN int val 0 */ \ + __VA_ARGS__ /* string data */ \ + }, \ + .buffer_size = sizeof((guint8[]){ __VA_ARGS__ }) + 8, + +#define XMM_EXPECTED_ARG_BUFFER(...) \ + .expected_arg_buf = { __VA_ARGS__ }, \ + .expected_arg_size = sizeof((guint8[]){ __VA_ARGS__ }), + +/*****************************************************************************/ + +typedef struct { + const gchar *detail; + const gsize offset; + const gint expected_consumed; + const gint expected_error; + const gchar *expected_error_string; + const guint8 buffer[255]; + const guint buffer_size; + const guint8 expected_arg_buf[255]; + const gsize expected_arg_size; +} ReadStrTest; + +static const ReadStrTest read_str_tests[] = { + { + .detail = "zero_buffer", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "initial buffer size 0 too small (need 2)", + }, + { + .detail = "1b_buffer", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "initial buffer size 1 too small (need 2)", + XMM_BUFFER( 0x02 ) + }, + { + .detail = "bad_string_type", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "unhandled string type 0x02", + XMM_BUFFER( 0x02, 0x04 ) + }, + { + .detail = "small_buffer_big_message", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "initial buffer size 3 too small (need 5)", + XMM_BUFFER( 0x55, 0x04, 0x02 ) + }, + { + .detail = "1b_string_2chars", + .expected_consumed = 10, + XMM_STRING_BUFFER( 0x55, 0x02, 'H', 'i' ) + XMM_EXPECTED_ARG_BUFFER( 'H', 'i' ) + }, + { + .detail = "1b_string_5chars", + .expected_consumed = 13, + XMM_STRING_BUFFER( 0x55, 0x05, 'H', 'e', 'l', 'l', 'o' ) + XMM_EXPECTED_ARG_BUFFER( 'H', 'e', 'l', 'l', 'o' ) + }, + { + .detail = "2b_string_2chars", + .expected_consumed = 12, + XMM_STRING_BUFFER( 0x56, 0x02, 0x00, 'H', 0x00, 'i' ) + XMM_EXPECTED_ARG_BUFFER( 0x00, 'H', 0x00, 'i' ) + }, + { + .detail = "4b_string_2chars", + .expected_consumed = 16, + XMM_STRING_BUFFER( 0x57, 0x02, 0x00, 0x01, 0x02, 'H', 0x00, 0x01, 0x02, 'i' ) + XMM_EXPECTED_ARG_BUFFER( 0x00, 0x01, 0x02, 'H', 0x00, 0x01, 0x02, 'i' ) + }, + { + .detail = "1b_string_zero_length", + .expected_consumed = 8, + XMM_STRING_BUFFER( 0x55, 0x00 ) + }, + { + .detail = "2b_string_zero_length", + .expected_consumed = 8, + XMM_STRING_BUFFER( 0x56, 0x00 ) + }, + { + .detail = "4b_string_zero_length", + .expected_consumed = 8, + XMM_STRING_BUFFER( 0x57, 0x00 ) + }, +}; + +static void +test_read_str (gconstpointer data) +{ + const ReadStrTest *test = data; + g_autoptr(GError) error = NULL; + gint consumed; + g_autoptr(GByteArray) buffer = NULL; + Xmm7360RpcMsgArg arg = { 0 }; + + buffer = g_byte_array_sized_new (sizeof (test->buffer_size)); + if (sizeof (test->buffer)) + g_byte_array_append (buffer, test->buffer, test->buffer_size); + + consumed = xmm7360_byte_array_read_string (buffer, test->offset, &arg, &error); + if (error) { + g_assert_error (error, MM_CORE_ERROR, test->expected_error); + g_assert_cmpstr (error->message, ==, test->expected_error_string); + g_assert_cmpint (consumed, <, 0); + g_assert_cmpint (test->expected_arg_size, ==, 0); + g_assert_cmpint (arg.size, ==, 0); + } else { + g_assert_no_error (error); + g_assert_cmpint (test->expected_error, ==, 0); + g_assert_false (!!test->expected_error_string); + g_assert_cmpint (consumed, ==, test->expected_consumed); + g_assert_cmpint (arg.type, ==, XMM7360_RPC_MSG_ARG_TYPE_STRING); + g_assert_cmpint (arg.size, ==, test->expected_arg_size); + g_assert_cmpmem (arg.value.string, arg.size, test->expected_arg_buf, test->expected_arg_size); + } +} + +/*****************************************************************************/ + +typedef struct { + const gchar *detail; + const gsize offset; + const gint expected_consumed; + const gint expected_error; + const gchar *expected_error_string; + const gint expected_val; + const guint8 buffer[255]; + const guint buffer_size; + const Xmm7360RpcMsgArg expected_arg; +} ReadAsnIntTest; + +static const ReadAsnIntTest read_asn_int_tests[] = { + { + .detail = "zero_buffer", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "initial buffer size 0 too small (need 3)", + }, + { + .detail = "1b_buffer", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "initial buffer size 1 too small (need 3)", + XMM_BUFFER( 0x02 ) + }, + { + .detail = "2b_buffer", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "initial buffer size 2 too small (need 3)", + XMM_BUFFER( 0x02, 0x01 ) + }, + { + .detail = "small_buffer_big_message", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "buffer size 3 too small (need 6)", + XMM_BUFFER( 0x02, 0x04, 0x02 ) + }, + { + .detail = "bad_start", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "unexpected ASN start byte 0x00 (expected 0x02)", + XMM_BUFFER( 0x00, 0x01, 0x01 ) + }, + { + .detail = "no_data", + .expected_consumed = 2, + .expected_val = 0, + XMM_BUFFER( 0x02, 0x00, 0x00 ) + .expected_arg = { + .type = XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN, + }, + }, + { + .detail = "u8", + .expected_consumed = 3, + .expected_val = 1, + XMM_BUFFER( 0x02, 0x01, 0x01 ) + .expected_arg = { + .type = XMM7360_RPC_MSG_ARG_TYPE_BYTE, + .value.b = 0x01, + }, + }, + { + .detail = "u16", + .expected_consumed = 4, + .expected_val = 0x102, + XMM_BUFFER( 0x02, 0x02, 0x01, 0x02 ) + .expected_arg = { + .type = XMM7360_RPC_MSG_ARG_TYPE_SHORT, + .value.s = 0x102, + }, + }, + { + .detail = "u24_is_bad", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "unhandled int size 3", + XMM_BUFFER( 0x02, 0x03, 0x01, 0x02, 0x03 ) + }, + { + .detail = "u32", + .expected_consumed = 6, + .expected_val = 0x1020304, + XMM_BUFFER( 0x02, 0x04, 0x01, 0x02, 0x03, 0x04 ) + .expected_arg = { + .type = XMM7360_RPC_MSG_ARG_TYPE_LONG, + .value.l = 0x1020304, + }, + }, + { + .detail = "ubad", + .expected_consumed = -1, + .expected_error = MM_CORE_ERROR_FAILED, + .expected_error_string = "unhandled int size 6", + XMM_BUFFER( 0x02, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 ) + }, +}; + +static void +test_read_asn_int (gconstpointer data) +{ + const ReadAsnIntTest *test = data; + g_autoptr(GError) error = NULL; + gint consumed; + g_autoptr(GByteArray) buffer = NULL; + gint val = 0; + Xmm7360RpcMsgArg arg = { 0 }; + + buffer = g_byte_array_sized_new (sizeof (test->buffer_size)); + if (sizeof (test->buffer)) + g_byte_array_append (buffer, test->buffer, test->buffer_size); + + consumed = xmm7360_byte_array_read_asn_int (buffer, test->offset, &val, &arg, &error); + if (error) { + g_assert_error (error, MM_CORE_ERROR, test->expected_error); + g_assert_cmpstr (error->message, ==, test->expected_error_string); + g_assert_cmpint (consumed, <, 0); + g_assert_cmpint (test->expected_arg.type, ==, 0); + } else { + g_assert_no_error (error); + g_assert_cmpint (test->expected_error, ==, 0); + g_assert_false (!!test->expected_error_string); + g_assert_cmpint (consumed, ==, test->expected_consumed); + g_assert_cmpint (val, ==, test->expected_val); + if (test->expected_arg.type != XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN) { + g_assert_cmpint (arg.type, ==, test->expected_arg.type); + switch (arg.type) { + case XMM7360_RPC_MSG_ARG_TYPE_BYTE: + g_assert_cmpint (arg.value.b, ==, test->expected_arg.value.b); + break; + case XMM7360_RPC_MSG_ARG_TYPE_SHORT: + g_assert_cmpint (arg.value.s, ==, test->expected_arg.value.s); + break; + case XMM7360_RPC_MSG_ARG_TYPE_LONG: + g_assert_cmpint (arg.value.l, ==, test->expected_arg.value.l); + break; + case XMM7360_RPC_MSG_ARG_TYPE_STRING: + g_assert_cmpmem (arg.value.string, arg.size, test->expected_arg.value.string, test->expected_arg.size); + break; + case XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN: + default: + g_assert_not_reached (); + } + } + } +} + +/*****************************************************************************/ + +int main (int argc, char **argv) +{ + guint i; + + setlocale (LC_ALL, ""); + + g_test_init (&argc, &argv, NULL); + + for (i = 0; i < G_N_ELEMENTS (read_asn_int_tests); i++) { + g_autofree gchar *path; + + path = g_strdup_printf ("/MM/xmmrpc/read_asn_int/%s", read_asn_int_tests[i].detail); + g_test_add_data_func (path, &read_asn_int_tests[i], test_read_asn_int); + } + + for (i = 0; i < G_N_ELEMENTS (read_str_tests); i++) { + g_autofree gchar *path; + + path = g_strdup_printf ("/MM/xmmrpc/read_str/%s", read_str_tests[i].detail); + g_test_add_data_func (path, &read_str_tests[i], test_read_str); + } + + return g_test_run (); +} diff --git a/src/plugins/meson.build b/src/plugins/meson.build index 8ad7a804..5a79bb16 100644 --- a/src/plugins/meson.build +++ b/src/plugins/meson.build @@ -635,16 +635,22 @@ if plugins_options['intel'] command: [ python, mm_mkenums, - '--fhead', '#include "mm-port-serial-xmmrpc-xmm7360.h"\n#ifndef __MM_XMM7360_ENUMS_TYPES_H__\n#define __MM_XMM7360_ENUMS_TYPES_H__\n', + '--fhead', '#include "mm-xmmrpc-xmm7360-protocol.h"\n#ifndef __MM_XMM7360_ENUMS_TYPES_H__\n#define __MM_XMM7360_ENUMS_TYPES_H__\n', '--template', files(templates_dir / enums_types + '.h.template'), '--ftail', '#endif /* __MM_XMM7360_ENUMS_TYPES_H__ */\n', '@INPUT@'], capture: true, ) + test_sources = files( + 'intel/mm-xmmrpc-xmm7360-protocol.c', + 'intel/tests/test-xmmrpc-xmm7360-protocol.c', + ) + plugins += {'plugin-intel': { 'plugin': true, 'module': {'sources': sources, 'include_directories': plugins_incs + [xmm_inc, intel_inc], 'c_args': common_c_args}, + 'test': {'sources': test_sources, 'include_directories': intel_inc, 'dependencies': libhelpers_dep}, }} endif