test-mgmt.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2012 Intel Corporation. All rights reserved.
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #include <stdbool.h>
  14. #include <unistd.h>
  15. #include <sys/socket.h>
  16. #include <glib.h>
  17. #include "lib/bluetooth.h"
  18. #include "lib/mgmt.h"
  19. #include "src/shared/mgmt.h"
  20. struct context {
  21. GMainLoop *main_loop;
  22. int fd;
  23. struct mgmt *mgmt_client;
  24. guint server_source;
  25. GList *handler_list;
  26. };
  27. enum action {
  28. ACTION_PASSED,
  29. ACTION_IGNORE,
  30. ACTION_RESPOND,
  31. };
  32. struct handler {
  33. const void *cmd_data;
  34. uint16_t cmd_size;
  35. const void *rsp_data;
  36. uint16_t rsp_size;
  37. uint8_t rsp_status;
  38. bool match_prefix;
  39. enum action action;
  40. };
  41. static void mgmt_debug(const char *str, void *user_data)
  42. {
  43. const char *prefix = user_data;
  44. g_print("%s%s\n", prefix, str);
  45. }
  46. static void context_quit(struct context *context)
  47. {
  48. g_main_loop_quit(context->main_loop);
  49. }
  50. static void check_actions(struct context *context, int fd,
  51. const void *data, uint16_t size)
  52. {
  53. GList *list;
  54. for (list = g_list_first(context->handler_list); list;
  55. list = g_list_next(list)) {
  56. struct handler *handler = list->data;
  57. int ret;
  58. if (handler->match_prefix) {
  59. if (size < handler->cmd_size)
  60. continue;
  61. } else {
  62. if (size != handler->cmd_size)
  63. continue;
  64. }
  65. if (memcmp(data, handler->cmd_data, handler->cmd_size))
  66. continue;
  67. switch (handler->action) {
  68. case ACTION_PASSED:
  69. context_quit(context);
  70. return;
  71. case ACTION_RESPOND:
  72. ret = write(fd, handler->rsp_data, handler->rsp_size);
  73. g_assert(ret >= 0);
  74. return;
  75. case ACTION_IGNORE:
  76. return;
  77. }
  78. }
  79. g_test_message("Command not handled\n");
  80. g_assert_not_reached();
  81. }
  82. static gboolean server_handler(GIOChannel *channel, GIOCondition cond,
  83. gpointer user_data)
  84. {
  85. struct context *context = user_data;
  86. unsigned char buf[512];
  87. ssize_t result;
  88. int fd;
  89. if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
  90. return FALSE;
  91. fd = g_io_channel_unix_get_fd(channel);
  92. result = read(fd, buf, sizeof(buf));
  93. if (result < 0)
  94. return FALSE;
  95. check_actions(context, fd, buf, result);
  96. return TRUE;
  97. }
  98. static struct context *create_context(void)
  99. {
  100. struct context *context = g_new0(struct context, 1);
  101. GIOChannel *channel;
  102. int err, sv[2];
  103. context->main_loop = g_main_loop_new(NULL, FALSE);
  104. g_assert(context->main_loop);
  105. err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
  106. g_assert(err == 0);
  107. context->fd = sv[0];
  108. channel = g_io_channel_unix_new(sv[0]);
  109. g_io_channel_set_close_on_unref(channel, TRUE);
  110. g_io_channel_set_encoding(channel, NULL, NULL);
  111. g_io_channel_set_buffered(channel, FALSE);
  112. context->server_source = g_io_add_watch(channel,
  113. G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
  114. server_handler, context);
  115. g_assert(context->server_source > 0);
  116. g_io_channel_unref(channel);
  117. context->mgmt_client = mgmt_new(sv[1]);
  118. g_assert(context->mgmt_client);
  119. if (g_test_verbose() == TRUE)
  120. mgmt_set_debug(context->mgmt_client,
  121. mgmt_debug, "mgmt: ", NULL);
  122. mgmt_set_close_on_unref(context->mgmt_client, true);
  123. return context;
  124. }
  125. static void execute_context(struct context *context)
  126. {
  127. g_main_loop_run(context->main_loop);
  128. g_list_free_full(context->handler_list, g_free);
  129. g_source_remove(context->server_source);
  130. mgmt_unref(context->mgmt_client);
  131. g_main_loop_unref(context->main_loop);
  132. g_free(context);
  133. }
  134. static void add_action(struct context *context,
  135. const void *cmd_data, uint16_t cmd_size,
  136. const void *rsp_data, uint16_t rsp_size,
  137. uint8_t rsp_status, bool match_prefix,
  138. enum action action)
  139. {
  140. struct handler *handler = g_new0(struct handler, 1);
  141. handler->cmd_data = cmd_data;
  142. handler->cmd_size = cmd_size;
  143. handler->rsp_data = rsp_data;
  144. handler->rsp_size = rsp_size;
  145. handler->rsp_status = rsp_status;
  146. handler->match_prefix = match_prefix;
  147. handler->action = action;
  148. context->handler_list = g_list_append(context->handler_list, handler);
  149. }
  150. struct command_test_data {
  151. uint16_t opcode;
  152. uint16_t index;
  153. uint16_t length;
  154. const void *param;
  155. const void *cmd_data;
  156. uint16_t cmd_size;
  157. const void *rsp_data;
  158. uint16_t rsp_size;
  159. uint8_t rsp_status;
  160. };
  161. static const unsigned char read_version_command[] =
  162. { 0x01, 0x00, 0xff, 0xff, 0x00, 0x00 };
  163. static const unsigned char read_version_response[] =
  164. { 0x01, 0x00, 0xff, 0xff, 0x06, 0x00,
  165. 0x01, 0x00, 0x00, 0x01, 0x06, 0x00 };
  166. static const struct command_test_data command_test_1 = {
  167. .opcode = MGMT_OP_READ_VERSION,
  168. .index = MGMT_INDEX_NONE,
  169. .cmd_data = read_version_command,
  170. .cmd_size = sizeof(read_version_command),
  171. .rsp_data = read_version_response,
  172. .rsp_size = sizeof(read_version_response),
  173. .rsp_status = MGMT_STATUS_SUCCESS,
  174. };
  175. static const unsigned char read_info_command[] =
  176. { 0x04, 0x00, 0x00, 0x02, 0x00, 0x00 };
  177. static const struct command_test_data command_test_2 = {
  178. .opcode = MGMT_OP_READ_INFO,
  179. .index = 512,
  180. .cmd_data = read_info_command,
  181. .cmd_size = sizeof(read_info_command),
  182. };
  183. static const unsigned char invalid_index_response[] =
  184. { 0x02, 0x00, 0xff, 0xff, 0x03, 0x00,
  185. 0x01, 0x00, 0x11 };
  186. static const struct command_test_data command_test_3 = {
  187. .opcode = MGMT_OP_READ_VERSION,
  188. .index = MGMT_INDEX_NONE,
  189. .cmd_data = read_version_command,
  190. .cmd_size = sizeof(read_version_command),
  191. .rsp_data = invalid_index_response,
  192. .rsp_size = sizeof(invalid_index_response),
  193. .rsp_status = MGMT_STATUS_INVALID_INDEX,
  194. };
  195. static const unsigned char event_index_added[] =
  196. { 0x04, 0x00, 0x01, 0x00, 0x00, 0x00 };
  197. static const struct command_test_data event_test_1 = {
  198. .opcode = MGMT_EV_INDEX_ADDED,
  199. .index = MGMT_INDEX_NONE,
  200. .cmd_data = event_index_added,
  201. .cmd_size = sizeof(event_index_added),
  202. };
  203. static void test_command(gconstpointer data)
  204. {
  205. const struct command_test_data *test = data;
  206. struct context *context = create_context();
  207. add_action(context, test->cmd_data, test->cmd_size,
  208. test->rsp_data, test->rsp_size, test->rsp_status,
  209. false, ACTION_PASSED);
  210. mgmt_send(context->mgmt_client, test->opcode, test->index,
  211. test->length, test->param,
  212. NULL ,NULL, NULL);
  213. execute_context(context);
  214. }
  215. static void response_cb(uint8_t status, uint16_t length, const void *param,
  216. void *user_data)
  217. {
  218. struct context *context = user_data;
  219. struct handler *handler = context->handler_list->data;
  220. g_assert_cmpint(status, ==, handler->rsp_status);
  221. context_quit(context);
  222. }
  223. static void test_response(gconstpointer data)
  224. {
  225. const struct command_test_data *test = data;
  226. struct context *context = create_context();
  227. add_action(context, test->cmd_data, test->cmd_size,
  228. test->rsp_data, test->rsp_size, test->rsp_status,
  229. false, ACTION_RESPOND);
  230. mgmt_send(context->mgmt_client, test->opcode, test->index,
  231. test->length, test->param,
  232. response_cb, context, NULL);
  233. execute_context(context);
  234. }
  235. static void event_cb(uint16_t index, uint16_t length, const void *param,
  236. void *user_data)
  237. {
  238. struct context *context = user_data;
  239. if (g_test_verbose())
  240. printf("Event received\n");
  241. context_quit(context);
  242. }
  243. static void test_event(gconstpointer data)
  244. {
  245. const struct command_test_data *test = data;
  246. struct context *context = create_context();
  247. mgmt_register(context->mgmt_client, test->opcode, test->index,
  248. event_cb, context, NULL);
  249. g_assert_cmpint(write(context->fd, test->cmd_data, test->cmd_size), ==,
  250. test->cmd_size);
  251. execute_context(context);
  252. }
  253. static void test_event2(gconstpointer data)
  254. {
  255. const struct command_test_data *test = data;
  256. struct context *context = create_context();
  257. mgmt_register(context->mgmt_client, test->opcode, test->index,
  258. event_cb, context, NULL);
  259. mgmt_register(context->mgmt_client, test->opcode, test->index,
  260. event_cb, context, NULL);
  261. g_assert_cmpint(write(context->fd, test->cmd_data, test->cmd_size), ==,
  262. test->cmd_size);
  263. execute_context(context);
  264. }
  265. static void unregister_all_cb(uint16_t index, uint16_t length,
  266. const void *param, void *user_data)
  267. {
  268. struct context *context = user_data;
  269. mgmt_unregister_all(context->mgmt_client);
  270. context_quit(context);
  271. }
  272. static void test_unregister_all(gconstpointer data)
  273. {
  274. const struct command_test_data *test = data;
  275. struct context *context = create_context();
  276. mgmt_register(context->mgmt_client, test->opcode, test->index,
  277. unregister_all_cb, context, NULL);
  278. mgmt_register(context->mgmt_client, test->opcode, test->index,
  279. event_cb, context, NULL);
  280. g_assert_cmpint(write(context->fd, test->cmd_data, test->cmd_size), ==,
  281. test->cmd_size);
  282. execute_context(context);
  283. }
  284. static void unregister_index_cb(uint16_t index, uint16_t length,
  285. const void *param, void *user_data)
  286. {
  287. struct context *context = user_data;
  288. mgmt_unregister_index(context->mgmt_client, index);
  289. context_quit(context);
  290. }
  291. static void destroy_cb(uint16_t index, uint16_t length, const void *param,
  292. void *user_data)
  293. {
  294. struct context *context = user_data;
  295. mgmt_unref(context->mgmt_client);
  296. context->mgmt_client = NULL;
  297. context_quit(context);
  298. }
  299. static void test_unregister_index(gconstpointer data)
  300. {
  301. const struct command_test_data *test = data;
  302. struct context *context = create_context();
  303. mgmt_register(context->mgmt_client, test->opcode, test->index,
  304. unregister_index_cb, context, NULL);
  305. mgmt_register(context->mgmt_client, test->opcode, test->index,
  306. event_cb, context, NULL);
  307. g_assert_cmpint(write(context->fd, test->cmd_data, test->cmd_size), ==,
  308. test->cmd_size);
  309. execute_context(context);
  310. }
  311. static void test_destroy(gconstpointer data)
  312. {
  313. const struct command_test_data *test = data;
  314. struct context *context = create_context();
  315. mgmt_register(context->mgmt_client, test->opcode, test->index,
  316. destroy_cb, context, NULL);
  317. mgmt_register(context->mgmt_client, test->opcode, test->index,
  318. event_cb, context, NULL);
  319. g_assert_cmpint(write(context->fd, test->cmd_data, test->cmd_size), ==,
  320. test->cmd_size);
  321. execute_context(context);
  322. }
  323. int main(int argc, char *argv[])
  324. {
  325. g_test_init(&argc, &argv, NULL);
  326. g_test_add_data_func("/mgmt/command/1", &command_test_1, test_command);
  327. g_test_add_data_func("/mgmt/command/2", &command_test_2, test_command);
  328. g_test_add_data_func("/mgmt/response/1", &command_test_1,
  329. test_response);
  330. g_test_add_data_func("/mgmt/response/2", &command_test_3,
  331. test_response);
  332. g_test_add_data_func("/mgmt/event/1", &event_test_1, test_event);
  333. g_test_add_data_func("/mgmt/event/2", &event_test_1, test_event2);
  334. g_test_add_data_func("/mgmt/unregister/1", &event_test_1,
  335. test_unregister_all);
  336. g_test_add_data_func("/mgmt/unregister/2", &event_test_1,
  337. test_unregister_index);
  338. g_test_add_data_func("/mgmt/destroy/1", &event_test_1, test_destroy);
  339. return g_test_run();
  340. }