| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <stdio.h>
- #include <errno.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <inttypes.h>
- #include <string.h>
- #include <fcntl.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <glib.h>
- #include "src/shared/util.h"
- #include "src/log.h"
- #include "android/ipc-common.h"
- #include "android/ipc.h"
- static const char HAL_SK_PATH[] = "\0test_hal_socket";
- #define SERVICE_ID_MAX 10
- struct test_data {
- bool disconnect;
- const void *cmd;
- uint16_t cmd_size;
- uint8_t service;
- const struct ipc_handler *handlers;
- uint8_t handlers_size;
- };
- struct context {
- GMainLoop *main_loop;
- int sk;
- guint source;
- guint cmd_source;
- guint notif_source;
- GIOChannel *cmd_io;
- GIOChannel *notif_io;
- const struct test_data *data;
- };
- static struct ipc *ipc = NULL;
- static void context_quit(struct context *context)
- {
- g_main_loop_quit(context->main_loop);
- }
- static gboolean cmd_watch(GIOChannel *io, GIOCondition cond,
- gpointer user_data)
- {
- struct context *context = user_data;
- const struct test_data *test_data = context->data;
- const struct ipc_hdr *sent_msg = test_data->cmd;
- uint8_t buf[128];
- int sk;
- struct ipc_hdr success_resp = {
- .service_id = sent_msg->service_id,
- .opcode = sent_msg->opcode,
- .len = 0,
- };
- if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
- g_assert(test_data->disconnect);
- return FALSE;
- }
- g_assert(!test_data->disconnect);
- sk = g_io_channel_unix_get_fd(io);
- g_assert(read(sk, buf, sizeof(buf)) == sizeof(struct ipc_hdr));
- g_assert(!memcmp(&success_resp, buf, sizeof(struct ipc_hdr)));
- context_quit(context);
- return TRUE;
- }
- static gboolean notif_watch(GIOChannel *io, GIOCondition cond,
- gpointer user_data)
- {
- struct context *context = user_data;
- const struct test_data *test_data = context->data;
- if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
- g_assert(test_data->disconnect);
- return FALSE;
- }
- g_assert(!test_data->disconnect);
- return TRUE;
- }
- static gboolean connect_handler(GIOChannel *io, GIOCondition cond,
- gpointer user_data)
- {
- struct context *context = user_data;
- const struct test_data *test_data = context->data;
- GIOChannel *new_io;
- GIOCondition watch_cond;
- int sk;
- if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
- g_assert(FALSE);
- return FALSE;
- }
- g_assert(!context->cmd_source || !context->notif_source);
- sk = accept(context->sk, NULL, NULL);
- g_assert(sk >= 0);
- new_io = g_io_channel_unix_new(sk);
- watch_cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
- if (context->cmd_source && !context->notif_source) {
- context->notif_source = g_io_add_watch(new_io, watch_cond,
- notif_watch, context);
- g_assert(context->notif_source > 0);
- context->notif_io = new_io;
- }
- if (!context->cmd_source) {
- context->cmd_source = g_io_add_watch(new_io, watch_cond,
- cmd_watch, context);
- context->cmd_io = new_io;
- }
- if (context->cmd_source && context->notif_source && !test_data->cmd)
- context_quit(context);
- return TRUE;
- }
- static struct context *create_context(gconstpointer data)
- {
- struct context *context = g_new0(struct context, 1);
- struct sockaddr_un addr;
- GIOChannel *io;
- int ret, sk;
- context->main_loop = g_main_loop_new(NULL, FALSE);
- g_assert(context->main_loop);
- sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
- g_assert(sk >= 0);
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- memcpy(addr.sun_path, HAL_SK_PATH, sizeof(HAL_SK_PATH));
- ret = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
- g_assert(ret == 0);
- ret = listen(sk, 5);
- g_assert(ret == 0);
- io = g_io_channel_unix_new(sk);
- g_io_channel_set_close_on_unref(io, TRUE);
- context->source = g_io_add_watch(io,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- connect_handler, context);
- g_assert(context->source > 0);
- g_io_channel_unref(io);
- context->sk = sk;
- context->data = data;
- return context;
- }
- static void execute_context(struct context *context)
- {
- g_main_loop_run(context->main_loop);
- g_io_channel_shutdown(context->notif_io, TRUE, NULL);
- g_io_channel_shutdown(context->cmd_io, TRUE, NULL);
- g_io_channel_unref(context->cmd_io);
- g_io_channel_unref(context->notif_io);
- g_source_remove(context->notif_source);
- g_source_remove(context->cmd_source);
- g_source_remove(context->source);
- g_main_loop_unref(context->main_loop);
- g_free(context);
- }
- static void disconnected(void *data)
- {
- struct context *context = data;
- g_assert(context->data->disconnect);
- context_quit(context);
- }
- static void test_init(gconstpointer data)
- {
- struct context *context = create_context(data);
- ipc = ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH), SERVICE_ID_MAX,
- true, NULL, NULL);
- g_assert(ipc);
- execute_context(context);
- ipc_cleanup(ipc);
- ipc = NULL;
- }
- static gboolean send_cmd(gpointer user_data)
- {
- struct context *context = user_data;
- const struct test_data *test_data = context->data;
- int sk;
- sk = g_io_channel_unix_get_fd(context->cmd_io);
- g_assert(sk >= 0);
- g_assert(write(sk, test_data->cmd, test_data->cmd_size) ==
- test_data->cmd_size);
- return FALSE;
- }
- static gboolean register_service(gpointer user_data)
- {
- struct context *context = user_data;
- const struct test_data *test_data = context->data;
- ipc_register(ipc, test_data->service, test_data->handlers,
- test_data->handlers_size);
- return FALSE;
- }
- static gboolean unregister_service(gpointer user_data)
- {
- struct context *context = user_data;
- const struct test_data *test_data = context->data;
- ipc_unregister(ipc, test_data->service);
- return FALSE;
- }
- static void test_cmd(gconstpointer data)
- {
- struct context *context = create_context(data);
- ipc = ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH), SERVICE_ID_MAX,
- true, disconnected, context);
- g_assert(ipc);
- g_idle_add(send_cmd, context);
- execute_context(context);
- ipc_cleanup(ipc);
- ipc = NULL;
- }
- static void test_cmd_reg(gconstpointer data)
- {
- struct context *context = create_context(data);
- const struct test_data *test_data = context->data;
- ipc = ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH), SERVICE_ID_MAX,
- true, disconnected, context);
- g_assert(ipc);
- g_idle_add(register_service, context);
- g_idle_add(send_cmd, context);
- execute_context(context);
- ipc_unregister(ipc, test_data->service);
- ipc_cleanup(ipc);
- ipc = NULL;
- }
- static void test_cmd_reg_1(gconstpointer data)
- {
- struct context *context = create_context(data);
- ipc = ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH), SERVICE_ID_MAX,
- true, disconnected, context);
- g_assert(ipc);
- g_idle_add(register_service, context);
- g_idle_add(unregister_service, context);
- g_idle_add(send_cmd, context);
- execute_context(context);
- ipc_cleanup(ipc);
- ipc = NULL;
- }
- static void test_cmd_handler_1(const void *buf, uint16_t len)
- {
- ipc_send_rsp(ipc, 0, 1, 0);
- }
- static void test_cmd_handler_2(const void *buf, uint16_t len)
- {
- ipc_send_rsp(ipc, 0, 2, 0);
- }
- static void test_cmd_handler_invalid(const void *buf, uint16_t len)
- {
- g_assert(false);
- }
- static const struct test_data test_init_1 = {};
- static const struct ipc_hdr test_cmd_1_hdr = {
- .service_id = 0,
- .opcode = 1,
- .len = 0
- };
- static const struct ipc_hdr test_cmd_2_hdr = {
- .service_id = 0,
- .opcode = 2,
- .len = 0
- };
- static const struct test_data test_cmd_service_invalid_1 = {
- .cmd = &test_cmd_1_hdr,
- .cmd_size = sizeof(test_cmd_1_hdr),
- .disconnect = true,
- };
- static const struct ipc_handler cmd_handlers[] = {
- { test_cmd_handler_1, false, 0 }
- };
- static const struct test_data test_cmd_service_valid_1 = {
- .cmd = &test_cmd_1_hdr,
- .cmd_size = sizeof(test_cmd_1_hdr),
- .service = 0,
- .handlers = cmd_handlers,
- .handlers_size = 1
- };
- static const struct test_data test_cmd_service_invalid_2 = {
- .cmd = &test_cmd_1_hdr,
- .cmd_size = sizeof(test_cmd_1_hdr),
- .service = 0,
- .handlers = cmd_handlers,
- .handlers_size = 1,
- .disconnect = true,
- };
- static const struct ipc_handler cmd_handlers_invalid_2[] = {
- { test_cmd_handler_1, false, 0 },
- { test_cmd_handler_invalid, false, 0 }
- };
- static const struct ipc_handler cmd_handlers_invalid_1[] = {
- { test_cmd_handler_invalid, false, 0 },
- { test_cmd_handler_2, false, 0 },
- };
- static const struct test_data test_cmd_opcode_valid_1 = {
- .cmd = &test_cmd_1_hdr,
- .cmd_size = sizeof(test_cmd_1_hdr),
- .service = 0,
- .handlers = cmd_handlers_invalid_2,
- .handlers_size = 2,
- };
- static const struct test_data test_cmd_opcode_valid_2 = {
- .cmd = &test_cmd_2_hdr,
- .cmd_size = sizeof(test_cmd_2_hdr),
- .service = 0,
- .handlers = cmd_handlers_invalid_1,
- .handlers_size = 2,
- };
- static const struct test_data test_cmd_opcode_invalid_1 = {
- .cmd = &test_cmd_2_hdr,
- .cmd_size = sizeof(test_cmd_2_hdr),
- .service = 0,
- .handlers = cmd_handlers,
- .handlers_size = 1,
- .disconnect = true,
- };
- static const struct test_data test_cmd_hdr_invalid = {
- .cmd = &test_cmd_1_hdr,
- .cmd_size = sizeof(test_cmd_1_hdr) - 1,
- .service = 0,
- .handlers = cmd_handlers,
- .handlers_size = 1,
- .disconnect = true,
- };
- #define VARDATA_EX1 "some data example"
- struct vardata {
- struct ipc_hdr hdr;
- uint8_t data[IPC_MTU - sizeof(struct ipc_hdr)];
- } __attribute__((packed));
- static const struct vardata test_cmd_vardata = {
- .hdr.service_id = 0,
- .hdr.opcode = 1,
- .hdr.len = sizeof(VARDATA_EX1),
- .data = VARDATA_EX1,
- };
- static const struct ipc_handler cmd_vardata_handlers[] = {
- { test_cmd_handler_1, true, sizeof(VARDATA_EX1) }
- };
- static const struct test_data test_cmd_vardata_valid = {
- .cmd = &test_cmd_vardata,
- .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1),
- .service = 0,
- .handlers = cmd_vardata_handlers,
- .handlers_size = 1,
- };
- static const struct ipc_handler cmd_vardata_handlers_valid2[] = {
- { test_cmd_handler_1, true, sizeof(VARDATA_EX1) - 1 }
- };
- static const struct test_data test_cmd_vardata_valid_2 = {
- .cmd = &test_cmd_vardata,
- .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1),
- .service = 0,
- .handlers = cmd_vardata_handlers_valid2,
- .handlers_size = 1,
- };
- static const struct test_data test_cmd_vardata_invalid_1 = {
- .cmd = &test_cmd_vardata,
- .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1) - 1,
- .service = 0,
- .handlers = cmd_vardata_handlers,
- .handlers_size = 1,
- .disconnect = true,
- };
- static const struct ipc_hdr test_cmd_service_offrange_hdr = {
- .service_id = SERVICE_ID_MAX + 1,
- .opcode = 1,
- .len = 0
- };
- static const struct test_data test_cmd_service_offrange = {
- .cmd = &test_cmd_service_offrange_hdr,
- .cmd_size = sizeof(struct ipc_hdr),
- .service = 0,
- .handlers = cmd_handlers,
- .handlers_size = 1,
- .disconnect = true,
- };
- static const struct vardata test_cmd_invalid_data_1 = {
- .hdr.service_id = 0,
- .hdr.opcode = 1,
- .hdr.len = sizeof(VARDATA_EX1),
- .data = VARDATA_EX1,
- };
- static const struct test_data test_cmd_msg_invalid_1 = {
- .cmd = &test_cmd_invalid_data_1,
- .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1) - 1,
- .service = 0,
- .handlers = cmd_handlers,
- .handlers_size = 1,
- .disconnect = true,
- };
- static const struct vardata test_cmd_invalid_data_2 = {
- .hdr.service_id = 0,
- .hdr.opcode = 1,
- .hdr.len = sizeof(VARDATA_EX1) - 1,
- .data = VARDATA_EX1,
- };
- static const struct test_data test_cmd_msg_invalid_2 = {
- .cmd = &test_cmd_invalid_data_2,
- .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1),
- .service = 0,
- .handlers = cmd_handlers,
- .handlers_size = 1,
- .disconnect = true,
- };
- int main(int argc, char *argv[])
- {
- g_test_init(&argc, &argv, NULL);
- if (g_test_verbose())
- __btd_log_init("*", 0);
- g_test_add_data_func("/android_ipc/init", &test_init_1, test_init);
- g_test_add_data_func("/android_ipc/service_invalid_1",
- &test_cmd_service_invalid_1, test_cmd);
- g_test_add_data_func("/android_ipc/service_valid_1",
- &test_cmd_service_valid_1, test_cmd_reg);
- g_test_add_data_func("/android_ipc/service_invalid_2",
- &test_cmd_service_invalid_2, test_cmd_reg_1);
- g_test_add_data_func("/android_ipc/opcode_valid_1",
- &test_cmd_opcode_valid_1, test_cmd_reg);
- g_test_add_data_func("/android_ipc/opcode_valid_2",
- &test_cmd_opcode_valid_2, test_cmd_reg);
- g_test_add_data_func("/android_ipc/opcode_invalid_1",
- &test_cmd_opcode_invalid_1, test_cmd_reg);
- g_test_add_data_func("/android_ipc/vardata_valid",
- &test_cmd_vardata_valid, test_cmd_reg);
- g_test_add_data_func("/android_ipc/vardata_valid_2",
- &test_cmd_vardata_valid_2, test_cmd_reg);
- g_test_add_data_func("/android_ipc/vardata_invalid_1",
- &test_cmd_vardata_invalid_1, test_cmd_reg);
- g_test_add_data_func("/android_ipc/service_offrange",
- &test_cmd_service_offrange, test_cmd_reg);
- g_test_add_data_func("/android_ipc/hdr_invalid",
- &test_cmd_hdr_invalid, test_cmd_reg);
- g_test_add_data_func("/android_ipc/msg_invalid_1",
- &test_cmd_msg_invalid_1, test_cmd_reg);
- g_test_add_data_func("/android_ipc/msg_invalid_2",
- &test_cmd_msg_invalid_2, test_cmd_reg);
- return g_test_run();
- }
|