config-client.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  1. // SPDX-License-Identifier: LGPL-2.1-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2017 Intel Corporation. All rights reserved.
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #include <stdio.h>
  14. #include <errno.h>
  15. #include <unistd.h>
  16. #include <stdlib.h>
  17. #include <stdbool.h>
  18. #include <inttypes.h>
  19. #include <stdbool.h>
  20. #include <sys/uio.h>
  21. #include <wordexp.h>
  22. #include <glib.h>
  23. #include "src/shared/shell.h"
  24. #include "src/shared/util.h"
  25. #include "tools/mesh/config-model.h"
  26. #include "tools/mesh-gatt/mesh-net.h"
  27. #include "tools/mesh-gatt/keys.h"
  28. #include "tools/mesh-gatt/net.h"
  29. #include "tools/mesh-gatt/node.h"
  30. #include "tools/mesh-gatt/prov-db.h"
  31. #include "tools/mesh-gatt/util.h"
  32. #define MIN_COMPOSITION_LEN 16
  33. static uint32_t print_mod_id(uint8_t *data, bool vid)
  34. {
  35. uint32_t mod_id;
  36. if (!vid) {
  37. mod_id = get_le16(data);
  38. bt_shell_printf("Model Id\t%4.4x\n", mod_id);
  39. mod_id = 0xffff0000 | mod_id;
  40. } else {
  41. mod_id = get_le16(data + 2);
  42. bt_shell_printf("Model Id\t%4.4x %4.4x\n",
  43. get_le16(data), mod_id);
  44. mod_id = get_le16(data) << 16 | mod_id;
  45. }
  46. return mod_id;
  47. }
  48. static bool client_msg_recvd(uint16_t src, uint8_t *data,
  49. uint16_t len, void *user_data)
  50. {
  51. uint32_t opcode;
  52. struct mesh_node *node;
  53. uint16_t app_idx, net_idx, addr;
  54. uint32_t mod_id;
  55. uint16_t primary;
  56. uint16_t ele_addr;
  57. uint8_t ele_idx;
  58. struct mesh_publication pub;
  59. int n;
  60. uint16_t i;
  61. if (mesh_opcode_get(data, len, &opcode, &n)) {
  62. len -= n;
  63. data += n;
  64. } else
  65. return false;
  66. if (IS_UNICAST(src)) {
  67. node = node_find_by_addr(src);
  68. } else
  69. node = NULL;
  70. if (!node)
  71. return false;
  72. primary = node_get_primary(node);
  73. if (primary != src)
  74. return false;
  75. switch (opcode) {
  76. default:
  77. return false;
  78. case OP_DEV_COMP_STATUS:
  79. if (len < MIN_COMPOSITION_LEN || !node)
  80. break;
  81. if (node_parse_composition(node, data, len)) {
  82. if (!prov_db_add_node_composition(node, data, len))
  83. break;
  84. }
  85. if (node_get_composition(node))
  86. prov_db_print_node_composition(node);
  87. break;
  88. case OP_APPKEY_STATUS:
  89. if (len != 4)
  90. break;
  91. bt_shell_printf("Node %4.4x AppKey status %s\n", src,
  92. mesh_status_str(data[0]));
  93. net_idx = get_le16(data + 1) & 0xfff;
  94. app_idx = get_le16(data + 2) >> 4;
  95. bt_shell_printf("NetKey\t%3.3x\n", net_idx);
  96. bt_shell_printf("AppKey\t%3.3x\n", app_idx);
  97. if (data[0] != MESH_STATUS_SUCCESS &&
  98. data[0] != MESH_STATUS_IDX_ALREADY_STORED &&
  99. node_app_key_delete(node, net_idx, app_idx))
  100. prov_db_node_keys(node, node_get_app_keys(node),
  101. "appKeys");
  102. break;
  103. case OP_NETKEY_STATUS:
  104. if (len != 3)
  105. break;
  106. bt_shell_printf("Node %4.4x NetKey status %s\n", src,
  107. mesh_status_str(data[0]));
  108. net_idx = get_le16(data + 1) & 0xfff;
  109. bt_shell_printf("\tNetKey %3.3x\n", net_idx);
  110. if (data[0] != MESH_STATUS_SUCCESS &&
  111. data[0] != MESH_STATUS_IDX_ALREADY_STORED &&
  112. node_net_key_delete(node, net_idx))
  113. prov_db_node_keys(node, node_get_net_keys(node),
  114. "netKeys");
  115. break;
  116. case OP_MODEL_APP_STATUS:
  117. if (len != 7 && len != 9)
  118. break;
  119. bt_shell_printf("Node %4.4x Model App status %s\n", src,
  120. mesh_status_str(data[0]));
  121. addr = get_le16(data + 1);
  122. app_idx = get_le16(data + 3);
  123. bt_shell_printf("Element Addr\t%4.4x\n", addr);
  124. mod_id = print_mod_id(data + 5, (len == 9) ? true : false);
  125. bt_shell_printf("AppIdx\t\t%3.3x\n ", app_idx);
  126. if (data[0] == MESH_STATUS_SUCCESS &&
  127. node_add_binding(node, addr - src, mod_id, app_idx))
  128. prov_db_add_binding(node, addr - src, mod_id, app_idx);
  129. break;
  130. case OP_NODE_IDENTITY_STATUS:
  131. if (len != 4)
  132. return true;
  133. bt_shell_printf("Network index 0x%04x "
  134. "Node Identity state 0x%02x status %s\n",
  135. get_le16(data + 1), data[3],
  136. mesh_status_str(data[0]));
  137. break;
  138. case OP_CONFIG_BEACON_STATUS:
  139. if (len != 1)
  140. return true;
  141. bt_shell_printf("Node %4.4x Config Beacon Status 0x%02x\n",
  142. src, data[0]);
  143. break;
  144. case OP_CONFIG_RELAY_STATUS:
  145. if (len != 2)
  146. return true;
  147. bt_shell_printf("Node %4.4x Relay state 0x%02x"
  148. " count %d steps %d\n",
  149. src, data[0], data[1]>>5, data[1] & 0x1f);
  150. break;
  151. case OP_CONFIG_PROXY_STATUS:
  152. if (len != 1)
  153. return true;
  154. bt_shell_printf("Node %4.4x Proxy state 0x%02x\n",
  155. src, data[0]);
  156. break;
  157. case OP_CONFIG_DEFAULT_TTL_STATUS:
  158. if (len != 1)
  159. return true;
  160. bt_shell_printf("Node %4.4x Default TTL %d\n", src, data[0]);
  161. if (node_set_default_ttl (node, data[0]))
  162. prov_db_node_set_ttl(node, data[0]);
  163. break;
  164. case OP_CONFIG_MODEL_PUB_STATUS:
  165. if (len != 12 && len != 14)
  166. return true;
  167. bt_shell_printf("\nNode %4.4x Publication status %s\n",
  168. src, mesh_status_str(data[0]));
  169. if (data[0] != MESH_STATUS_SUCCESS)
  170. return true;
  171. ele_addr = get_le16(data + 1);
  172. bt_shell_printf("Element Addr\t%04x\n", ele_addr);
  173. mod_id = print_mod_id(data + 10, (len == 14) ? true : false);
  174. pub.u.addr16 = get_le16(data + 3);
  175. pub.app_idx = get_le16(data + 5);
  176. pub.ttl = data[7];
  177. pub.period = data[8];
  178. n = (data[8] & 0x3f);
  179. bt_shell_printf("Pub Addr\t%04x\n", pub.u.addr16);
  180. switch (data[8] >> 6) {
  181. case 0:
  182. bt_shell_printf("Period\t\t%d ms\n", n * 100);
  183. break;
  184. case 2:
  185. n *= 10;
  186. /* fall through */
  187. case 1:
  188. bt_shell_printf("Period\t\t%d sec\n", n);
  189. break;
  190. case 3:
  191. bt_shell_printf("Period\t\t%d min\n", n * 10);
  192. break;
  193. }
  194. pub.retransmit = data[9];
  195. bt_shell_printf("Rexmit count\t%d\n", data[9] >> 5);
  196. bt_shell_printf("Rexmit steps\t%d\n", data[9] & 0x1f);
  197. ele_idx = ele_addr - node_get_primary(node);
  198. /* Local configuration is saved by server */
  199. if (node == node_get_local_node())
  200. break;
  201. if (node_model_pub_set(node, ele_idx, mod_id, &pub))
  202. prov_db_node_set_model_pub(node, ele_idx, mod_id,
  203. node_model_pub_get(node, ele_idx, mod_id));
  204. break;
  205. /* Per Mesh Profile 4.3.2.19 */
  206. case OP_CONFIG_MODEL_SUB_STATUS:
  207. bt_shell_printf("\nNode %4.4x Subscription status %s\n",
  208. src, mesh_status_str(data[0]));
  209. if (data[0] != MESH_STATUS_SUCCESS)
  210. return true;
  211. ele_addr = get_le16(data + 1);
  212. addr = get_le16(data + 3);
  213. ele_idx = ele_addr - node_get_primary(node);
  214. bt_shell_printf("Element Addr\t%4.4x\n", ele_addr);
  215. mod_id = print_mod_id(data + 5, (len == 9) ? true : false);
  216. bt_shell_printf("Subscr Addr\t%4.4x\n", addr);
  217. /* Save subscriptions in node and database */
  218. if (node_add_subscription(node, ele_idx, mod_id, addr))
  219. prov_db_add_subscription(node, ele_idx, mod_id, addr);
  220. break;
  221. /* Per Mesh Profile 4.3.2.27 */
  222. case OP_CONFIG_MODEL_SUB_LIST:
  223. bt_shell_printf("\nNode %4.4x Subscription List status %s\n",
  224. src, mesh_status_str(data[0]));
  225. if (data[0] != MESH_STATUS_SUCCESS)
  226. return true;
  227. bt_shell_printf("Element Addr\t%4.4x\n", get_le16(data + 1));
  228. bt_shell_printf("Model ID\t%4.4x\n", get_le16(data + 3));
  229. for (i = 5; i < len; i += 2)
  230. bt_shell_printf("Subscr Addr\t%4.4x\n",
  231. get_le16(data + i));
  232. break;
  233. /* Per Mesh Profile 4.3.2.50 */
  234. case OP_MODEL_APP_LIST:
  235. bt_shell_printf("\nNode %4.4x Model AppIdx "
  236. "status %s\n", src,
  237. mesh_status_str(data[0]));
  238. if (data[0] != MESH_STATUS_SUCCESS)
  239. return true;
  240. bt_shell_printf("Element Addr\t%4.4x\n", get_le16(data + 1));
  241. bt_shell_printf("Model ID\t%4.4x\n", get_le16(data + 3));
  242. for (i = 5; i < len; i += 2)
  243. bt_shell_printf("Model AppIdx\t%4.4x\n",
  244. get_le16(data + i));
  245. break;
  246. /* Per Mesh Profile 4.3.2.63 */
  247. case OP_CONFIG_HEARTBEAT_PUB_STATUS:
  248. bt_shell_printf("\nNode %4.4x Heartbeat publish status %s\n",
  249. src, mesh_status_str(data[0]));
  250. if (data[0] != MESH_STATUS_SUCCESS)
  251. return true;
  252. bt_shell_printf("Destination\t%4.4x\n", get_le16(data + 1));
  253. bt_shell_printf("Count\t\t%2.2x\n", data[3]);
  254. bt_shell_printf("Period\t\t%2.2x\n", data[4]);
  255. bt_shell_printf("TTL\t\t%2.2x\n", data[5]);
  256. bt_shell_printf("Features\t%4.4x\n", get_le16(data + 6));
  257. bt_shell_printf("Net_Idx\t%4.4x\n", get_le16(data + 8));
  258. break;
  259. /* Per Mesh Profile 4.3.2.66 */
  260. case OP_CONFIG_HEARTBEAT_SUB_STATUS:
  261. bt_shell_printf("\nNode %4.4x Heartbeat subscribe status %s\n",
  262. src, mesh_status_str(data[0]));
  263. if (data[0] != MESH_STATUS_SUCCESS)
  264. return true;
  265. bt_shell_printf("Source\t\t%4.4x\n", get_le16(data + 1));
  266. bt_shell_printf("Destination\t%4.4x\n", get_le16(data + 3));
  267. bt_shell_printf("Period\t\t%2.2x\n", data[5]);
  268. bt_shell_printf("Count\t\t%2.2x\n", data[6]);
  269. bt_shell_printf("Min Hops\t%2.2x\n", data[7]);
  270. bt_shell_printf("Max Hops\t%2.2x\n", data[8]);
  271. break;
  272. /* Per Mesh Profile 4.3.2.54 */
  273. case OP_NODE_RESET_STATUS:
  274. bt_shell_printf("Node %4.4x reset status %s\n",
  275. src, mesh_status_str(data[0]));
  276. net_release_address(node_get_primary(node),
  277. (node_get_num_elements(node)));
  278. /* TODO: Remove node info from database */
  279. node_free(node);
  280. break;
  281. }
  282. return true;
  283. }
  284. static uint32_t target;
  285. static uint32_t parms[8];
  286. static uint32_t read_input_parameters(int argc, char *argv[])
  287. {
  288. uint32_t i;
  289. if (!argc)
  290. return 0;
  291. --argc;
  292. ++argv;
  293. if (!argc || argv[0][0] == '\0')
  294. return 0;
  295. memset(parms, 0xff, sizeof(parms));
  296. for (i = 0; i < sizeof(parms)/sizeof(parms[0]) && i < (unsigned) argc;
  297. i++) {
  298. sscanf(argv[i], "%x", &parms[i]);
  299. if (parms[i] == 0xffffffff)
  300. break;
  301. }
  302. return i;
  303. }
  304. static void cmd_node_set(int argc, char *argv[])
  305. {
  306. uint32_t dst;
  307. char *end;
  308. dst = strtol(argv[1], &end, 16);
  309. if (end != (argv[1] + 4)) {
  310. bt_shell_printf("Bad unicast address %s: "
  311. "expected format 4 digit hex\n", argv[1]);
  312. target = UNASSIGNED_ADDRESS;
  313. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  314. } else {
  315. bt_shell_printf("Configuring node %4.4x\n", dst);
  316. target = dst;
  317. set_menu_prompt("config", argv[1]);
  318. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  319. }
  320. }
  321. static bool config_send(uint8_t *buf, uint16_t len)
  322. {
  323. struct mesh_node *node = node_get_local_node();
  324. uint16_t primary;
  325. if(!node)
  326. return false;
  327. primary = node_get_primary(node);
  328. if (target != primary)
  329. return net_access_layer_send(DEFAULT_TTL, primary,
  330. target, APP_IDX_DEV, buf, len);
  331. node_local_data_handler(primary, target, node_get_iv_index(node),
  332. node_get_sequence_number(node), APP_IDX_DEV,
  333. buf, len);
  334. return true;
  335. }
  336. static void cmd_default(uint32_t opcode)
  337. {
  338. uint16_t n;
  339. uint8_t msg[32];
  340. if (IS_UNASSIGNED(target)) {
  341. bt_shell_printf("Destination not set\n");
  342. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  343. }
  344. n = mesh_opcode_set(opcode, msg);
  345. if (!config_send(msg, n)) {
  346. bt_shell_printf("Failed to send command (opcode 0x%x)\n",
  347. opcode);
  348. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  349. }
  350. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  351. }
  352. static void cmd_composition_get(int argc, char *argv[])
  353. {
  354. uint16_t n;
  355. uint8_t msg[32];
  356. struct mesh_node *node;
  357. if (IS_UNASSIGNED(target)) {
  358. bt_shell_printf("Destination not set\n");
  359. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  360. }
  361. node = node_find_by_addr(target);
  362. if (!node)
  363. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  364. n = mesh_opcode_set(OP_DEV_COMP_GET, msg);
  365. /* By default, use page 0 */
  366. msg[n++] = (read_input_parameters(argc, argv) == 1) ? parms[0] : 0;
  367. if (!config_send(msg, n)) {
  368. bt_shell_printf("Failed to send \"GET NODE COMPOSITION\"\n");
  369. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  370. }
  371. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  372. }
  373. static void cmd_net_key(int argc, char *argv[], uint32_t opcode)
  374. {
  375. uint16_t n;
  376. uint8_t msg[32];
  377. uint16_t net_idx;
  378. uint8_t *key;
  379. struct mesh_node *node;
  380. if (IS_UNASSIGNED(target)) {
  381. bt_shell_printf("Destination not set\n");
  382. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  383. }
  384. n = mesh_opcode_set(opcode, msg);
  385. if (read_input_parameters(argc, argv) != 1) {
  386. bt_shell_printf("Bad arguments %s\n", argv[1]);
  387. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  388. }
  389. node = node_find_by_addr(target);
  390. if (!node) {
  391. bt_shell_printf("Node %4.4x\n not found", target);
  392. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  393. }
  394. net_idx = parms[0];
  395. if (opcode != OP_NETKEY_DELETE) {
  396. key = keys_net_key_get(net_idx, true);
  397. if (!key) {
  398. bt_shell_printf("NetKey with index %4.4x not found\n",
  399. net_idx);
  400. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  401. }
  402. put_le16(net_idx, &msg[n]);
  403. n += 2;
  404. memcpy(msg + n, key, 16);
  405. n += 16;
  406. }
  407. if (!config_send(msg, n)) {
  408. bt_shell_printf("Failed to send \"%s NET KEY\"\n",
  409. opcode == OP_NETKEY_ADD ? "ADD" : "DEL");
  410. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  411. }
  412. if (opcode != OP_NETKEY_DELETE) {
  413. if (node_net_key_add(node, net_idx))
  414. prov_db_node_keys(node, node_get_net_keys(node),
  415. "netKeys");
  416. } else {
  417. if (node_net_key_delete(node, net_idx))
  418. prov_db_node_keys(node, node_get_net_keys(node),
  419. "netKeys");
  420. }
  421. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  422. }
  423. static void cmd_netkey_add(int argc, char *argv[])
  424. {
  425. cmd_net_key(argc, argv, OP_NETKEY_ADD);
  426. }
  427. static void cmd_netkey_del(int argc, char *argv[])
  428. {
  429. cmd_net_key(argc, argv, OP_NETKEY_DELETE);
  430. }
  431. static void cmd_app_key(int argc, char *argv[], uint32_t opcode)
  432. {
  433. uint16_t n;
  434. uint8_t msg[32];
  435. uint16_t net_idx;
  436. uint16_t app_idx;
  437. uint8_t *key;
  438. struct mesh_node *node;
  439. if (IS_UNASSIGNED(target)) {
  440. bt_shell_printf("Destination not set\n");
  441. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  442. }
  443. if (read_input_parameters(argc, argv) != 1) {
  444. bt_shell_printf("Bad arguments %s\n", argv[1]);
  445. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  446. }
  447. node = node_find_by_addr(target);
  448. if (!node) {
  449. bt_shell_printf("Node %4.4x\n not found", target);
  450. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  451. }
  452. n = mesh_opcode_set(opcode, msg);
  453. app_idx = parms[0];
  454. net_idx = keys_app_key_get_bound(app_idx);
  455. if (net_idx == NET_IDX_INVALID) {
  456. bt_shell_printf("AppKey with index %4.4x not found\n", app_idx);
  457. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  458. }
  459. msg[n++] = net_idx & 0xff;
  460. msg[n++] = ((net_idx >> 8) & 0xf) |
  461. ((app_idx << 4) & 0xf0);
  462. msg[n++] = app_idx >> 4;
  463. if (opcode != OP_APPKEY_DELETE) {
  464. key = keys_app_key_get(app_idx, true);
  465. if (!key) {
  466. bt_shell_printf("AppKey %4.4x not found\n", net_idx);
  467. return;
  468. }
  469. memcpy(msg + n, key, 16);
  470. n += 16;
  471. }
  472. if (!config_send(msg, n)) {
  473. bt_shell_printf("Failed to send \"ADD %s KEY\"\n",
  474. opcode == OP_APPKEY_ADD ? "ADD" : "DEL");
  475. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  476. }
  477. if (opcode != OP_APPKEY_DELETE) {
  478. if (node_app_key_add(node, app_idx))
  479. prov_db_node_keys(node, node_get_app_keys(node),
  480. "appKeys");
  481. } else {
  482. if (node_app_key_delete(node, net_idx, app_idx))
  483. prov_db_node_keys(node, node_get_app_keys(node),
  484. "appKeys");
  485. }
  486. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  487. }
  488. static void cmd_appkey_add(int argc, char *argv[])
  489. {
  490. cmd_app_key(argc, argv, OP_APPKEY_ADD);
  491. }
  492. static void cmd_appkey_del(int argc, char *argv[])
  493. {
  494. cmd_app_key(argc, argv, OP_APPKEY_DELETE);
  495. }
  496. static bool verify_config_target(uint32_t dst)
  497. {
  498. struct mesh_node *node;
  499. if (IS_UNASSIGNED(dst)) {
  500. bt_shell_printf("Destination not set\n");
  501. return false;
  502. }
  503. node = node_find_by_addr(dst);
  504. if (!node) {
  505. bt_shell_printf("Node with unicast address %4.4x unknown\n",
  506. dst);
  507. return false;
  508. }
  509. if (!node_get_composition(node)) {
  510. bt_shell_printf("Node composition for %4.4x unknown\n", dst);
  511. return false;
  512. }
  513. return true;
  514. }
  515. static void cmd_bind(int argc, char *argv[])
  516. {
  517. uint16_t n;
  518. uint8_t msg[32];
  519. int parm_cnt;
  520. if (!verify_config_target(target))
  521. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  522. parm_cnt = read_input_parameters(argc, argv);
  523. if (parm_cnt != 3 && parm_cnt != 4) {
  524. bt_shell_printf("Bad arguments\n");
  525. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  526. }
  527. n = mesh_opcode_set(OP_MODEL_APP_BIND, msg);
  528. put_le16(target + parms[0], msg + n);
  529. n += 2;
  530. put_le16(parms[1], msg + n);
  531. n += 2;
  532. if (parm_cnt == 4) {
  533. put_le16(parms[3], msg + n);
  534. put_le16(parms[2], msg + n + 2);
  535. n += 4;
  536. } else {
  537. put_le16(parms[2], msg + n);
  538. n += 2;
  539. }
  540. if (!config_send(msg, n)) {
  541. bt_shell_printf("Failed to send \"MODEL APP BIND\"\n");
  542. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  543. }
  544. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  545. }
  546. static void cmd_beacon_set(int argc, char *argv[])
  547. {
  548. uint16_t n;
  549. uint8_t msg[2 + 1];
  550. int parm_cnt;
  551. if (!verify_config_target(target))
  552. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  553. n = mesh_opcode_set(OP_CONFIG_BEACON_SET, msg);
  554. parm_cnt = read_input_parameters(argc, argv);
  555. if (parm_cnt != 1) {
  556. bt_shell_printf("bad arguments\n");
  557. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  558. }
  559. msg[n++] = parms[0];
  560. if (!config_send(msg, n)) {
  561. bt_shell_printf("Failed to send \"SET BEACON\"\n");
  562. return;
  563. }
  564. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  565. }
  566. static void cmd_beacon_get(int argc, char *argv[])
  567. {
  568. cmd_default(OP_CONFIG_BEACON_GET);
  569. }
  570. static void cmd_ident_set(int argc, char *argv[])
  571. {
  572. uint16_t n;
  573. uint8_t msg[2 + 3 + 4];
  574. int parm_cnt;
  575. if (!verify_config_target(target))
  576. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  577. n = mesh_opcode_set(OP_NODE_IDENTITY_SET, msg);
  578. parm_cnt = read_input_parameters(argc, argv);
  579. if (parm_cnt != 2) {
  580. bt_shell_printf("bad arguments\n");
  581. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  582. }
  583. put_le16(parms[0], msg + n);
  584. n += 2;
  585. msg[n++] = parms[1];
  586. if (!config_send(msg, n)) {
  587. bt_shell_printf("Failed to send \"SET IDENTITY\"\n");
  588. return;
  589. }
  590. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  591. }
  592. static void cmd_ident_get(int argc, char *argv[])
  593. {
  594. uint16_t n;
  595. uint8_t msg[2 + 2 + 4];
  596. int parm_cnt;
  597. if (!verify_config_target(target))
  598. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  599. n = mesh_opcode_set(OP_NODE_IDENTITY_GET, msg);
  600. parm_cnt = read_input_parameters(argc, argv);
  601. if (parm_cnt != 1) {
  602. bt_shell_printf("bad arguments\n");
  603. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  604. }
  605. put_le16(parms[0], msg + n);
  606. n += 2;
  607. if (!config_send(msg, n)) {
  608. bt_shell_printf("Failed to send \"GET IDENTITY\"\n");
  609. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  610. }
  611. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  612. }
  613. static void cmd_proxy_set(int argc, char *argv[])
  614. {
  615. uint16_t n;
  616. uint8_t msg[2 + 1];
  617. int parm_cnt;
  618. if (!verify_config_target(target))
  619. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  620. n = mesh_opcode_set(OP_CONFIG_PROXY_SET, msg);
  621. parm_cnt = read_input_parameters(argc, argv);
  622. if (parm_cnt != 1) {
  623. bt_shell_printf("bad arguments");
  624. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  625. }
  626. msg[n++] = parms[0];
  627. if (!config_send(msg, n)) {
  628. bt_shell_printf("Failed to send \"SET PROXY\"\n");
  629. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  630. }
  631. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  632. }
  633. static void cmd_proxy_get(int argc, char *argv[])
  634. {
  635. cmd_default(OP_CONFIG_PROXY_GET);
  636. }
  637. static void cmd_relay_set(int argc, char *argv[])
  638. {
  639. uint16_t n;
  640. uint8_t msg[2 + 2 + 4];
  641. int parm_cnt;
  642. if (!verify_config_target(target))
  643. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  644. n = mesh_opcode_set(OP_CONFIG_RELAY_SET, msg);
  645. parm_cnt = read_input_parameters(argc, argv);
  646. if (parm_cnt != 3) {
  647. bt_shell_printf("bad arguments\n");
  648. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  649. }
  650. msg[n++] = parms[0];
  651. msg[n++] = (parms[1] << 5) | parms[2];
  652. if (!config_send(msg, n)) {
  653. bt_shell_printf("Failed to send \"SET RELAY\"\n");
  654. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  655. }
  656. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  657. }
  658. static void cmd_relay_get(int argc, char *argv[])
  659. {
  660. cmd_default(OP_CONFIG_RELAY_GET);
  661. }
  662. static void cmd_ttl_set(int argc, char *argv[])
  663. {
  664. uint16_t n;
  665. uint8_t msg[32];
  666. int parm_cnt;
  667. uint8_t ttl;
  668. if (IS_UNASSIGNED(target)) {
  669. bt_shell_printf("Destination not set\n");
  670. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  671. }
  672. n = mesh_opcode_set(OP_CONFIG_DEFAULT_TTL_SET, msg);
  673. parm_cnt = read_input_parameters(argc, argv);
  674. if (parm_cnt) {
  675. ttl = parms[0] & TTL_MASK;
  676. } else
  677. ttl = node_get_default_ttl(node_get_local_node());
  678. msg[n++] = ttl;
  679. if (!config_send(msg, n)) {
  680. bt_shell_printf("Failed to send \"SET_DEFAULT TTL\"\n");
  681. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  682. }
  683. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  684. }
  685. static void cmd_pub_set(int argc, char *argv[])
  686. {
  687. uint16_t n;
  688. uint8_t msg[32];
  689. int parm_cnt;
  690. if (!verify_config_target(target))
  691. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  692. n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_SET, msg);
  693. parm_cnt = read_input_parameters(argc, argv);
  694. if (parm_cnt != 6 && parm_cnt != 7) {
  695. bt_shell_printf("Bad arguments\n");
  696. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  697. }
  698. put_le16(parms[0], msg + n);
  699. n += 2;
  700. /* Publish address */
  701. put_le16(parms[1], msg + n);
  702. n += 2;
  703. /* AppKey index + credential (set to 0) */
  704. put_le16(parms[2], msg + n);
  705. n += 2;
  706. /* TTL */
  707. msg[n++] = DEFAULT_TTL;
  708. /* Publish period step count and step resolution */
  709. msg[n++] = parms[3];
  710. /* Publish retransmit count & interval steps */
  711. msg[n++] = parms[4];
  712. /* Model Id */
  713. if (parm_cnt == 7) {
  714. put_le16(parms[6], msg + n);
  715. put_le16(parms[5], msg + n + 2);
  716. n += 4;
  717. } else {
  718. put_le16(parms[5], msg + n);
  719. n += 2;
  720. }
  721. if (!config_send(msg, n)) {
  722. bt_shell_printf("Failed to send \"SET MODEL PUBLICATION\"\n");
  723. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  724. }
  725. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  726. }
  727. static void cmd_pub_get(int argc, char *argv[])
  728. {
  729. uint16_t n;
  730. uint8_t msg[32];
  731. int parm_cnt;
  732. if (IS_UNASSIGNED(target)) {
  733. bt_shell_printf("Destination not set\n");
  734. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  735. }
  736. n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_GET, msg);
  737. parm_cnt = read_input_parameters(argc, argv);
  738. if (parm_cnt != 2 && parm_cnt != 3) {
  739. bt_shell_printf("Bad arguments: %s\n", argv[1]);
  740. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  741. }
  742. /* Element Address */
  743. put_le16(parms[0], msg + n);
  744. n += 2;
  745. /* Model Id */
  746. if (parm_cnt == 3) {
  747. put_le16(parms[2], msg + n);
  748. put_le16(parms[1], msg + n + 2);
  749. n += 4;
  750. } else {
  751. put_le16(parms[1], msg + n);
  752. n += 2;
  753. }
  754. if (!config_send(msg, n)) {
  755. bt_shell_printf("Failed to send \"GET MODEL PUBLICATION\"\n");
  756. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  757. }
  758. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  759. }
  760. static void cmd_sub_add(int argc, char *argv[])
  761. {
  762. uint16_t n;
  763. uint8_t msg[32];
  764. int parm_cnt;
  765. if (IS_UNASSIGNED(target)) {
  766. bt_shell_printf("Destination not set\n");
  767. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  768. }
  769. n = mesh_opcode_set(OP_CONFIG_MODEL_SUB_ADD, msg);
  770. parm_cnt = read_input_parameters(argc, argv);
  771. if (parm_cnt != 3) {
  772. bt_shell_printf("Bad arguments: %s\n", argv[1]);
  773. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  774. }
  775. /* Per Mesh Profile 4.3.2.19 */
  776. /* Element Address */
  777. put_le16(parms[0], msg + n);
  778. n += 2;
  779. /* Subscription Address */
  780. put_le16(parms[1], msg + n);
  781. n += 2;
  782. /* SIG Model ID */
  783. put_le16(parms[2], msg + n);
  784. n += 2;
  785. if (!config_send(msg, n)) {
  786. bt_shell_printf("Failed to send \"ADD SUBSCRIPTION\"\n");
  787. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  788. }
  789. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  790. }
  791. static void cmd_sub_get(int argc, char *argv[])
  792. {
  793. uint16_t n;
  794. uint8_t msg[32];
  795. int parm_cnt;
  796. if (IS_UNASSIGNED(target)) {
  797. bt_shell_printf("Destination not set\n");
  798. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  799. }
  800. n = mesh_opcode_set(OP_CONFIG_MODEL_SUB_GET, msg);
  801. parm_cnt = read_input_parameters(argc, argv);
  802. if (parm_cnt != 2) {
  803. bt_shell_printf("Bad arguments: %s\n", argv[1]);
  804. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  805. }
  806. /* Per Mesh Profile 4.3.2.27 */
  807. /* Element Address */
  808. put_le16(parms[0], msg + n);
  809. n += 2;
  810. /* Model ID */
  811. put_le16(parms[1], msg + n);
  812. n += 2;
  813. if (!config_send(msg, n)) {
  814. bt_shell_printf("Failed to send \"GET SUB GET\"\n");
  815. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  816. }
  817. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  818. }
  819. static void cmd_mod_appidx_get(int argc, char *argv[])
  820. {
  821. uint16_t n;
  822. uint8_t msg[32];
  823. int parm_cnt;
  824. if (IS_UNASSIGNED(target)) {
  825. bt_shell_printf("Destination not set\n");
  826. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  827. }
  828. n = mesh_opcode_set(OP_MODEL_APP_GET, msg);
  829. parm_cnt = read_input_parameters(argc, argv);
  830. if (parm_cnt != 2) {
  831. bt_shell_printf("Bad arguments: %s\n", argv[1]);
  832. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  833. }
  834. /* Per Mesh Profile 4.3.2.49 */
  835. /* Element Address */
  836. put_le16(parms[0], msg + n);
  837. n += 2;
  838. /* Model ID */
  839. put_le16(parms[1], msg + n);
  840. n += 2;
  841. if (!config_send(msg, n)) {
  842. bt_shell_printf("Failed to send \"GET APP GET\"\n");
  843. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  844. }
  845. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  846. }
  847. static void cmd_hb_pub_set(int argc, char *argv[])
  848. {
  849. uint16_t n;
  850. uint8_t msg[32];
  851. int parm_cnt;
  852. if (IS_UNASSIGNED(target)) {
  853. bt_shell_printf("Destination not set\n");
  854. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  855. }
  856. n = mesh_opcode_set(OP_CONFIG_HEARTBEAT_PUB_SET, msg);
  857. parm_cnt = read_input_parameters(argc, argv);
  858. if (parm_cnt != 6) {
  859. bt_shell_printf("Bad arguments: %s\n", argv[1]);
  860. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  861. }
  862. /* Per Mesh Profile 4.3.2.62 */
  863. /* Publish address */
  864. put_le16(parms[0], msg + n);
  865. n += 2;
  866. /* Count Log */
  867. msg[n++] = parms[1];
  868. /* Period Log */
  869. msg[n++] = parms[2];
  870. /* Heartbeat TTL */
  871. msg[n++] = parms[3];
  872. /* Features */
  873. put_le16(parms[4], msg + n);
  874. n += 2;
  875. /* NetKey Index */
  876. put_le16(parms[5], msg + n);
  877. n += 2;
  878. if (!config_send(msg, n)) {
  879. bt_shell_printf("Failed to send \"SET HEARTBEAT PUBLISH\"\n");
  880. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  881. }
  882. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  883. }
  884. static void cmd_hb_pub_get(int argc, char *argv[])
  885. {
  886. cmd_default(OP_CONFIG_HEARTBEAT_PUB_GET);
  887. }
  888. static void cmd_hb_sub_set(int argc, char *argv[])
  889. {
  890. uint16_t n;
  891. uint8_t msg[32];
  892. int parm_cnt;
  893. if (IS_UNASSIGNED(target)) {
  894. bt_shell_printf("Destination not set\n");
  895. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  896. }
  897. n = mesh_opcode_set(OP_CONFIG_HEARTBEAT_SUB_SET, msg);
  898. parm_cnt = read_input_parameters(argc, argv);
  899. if (parm_cnt != 3) {
  900. bt_shell_printf("Bad arguments: %s\n", argv[1]);
  901. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  902. }
  903. /* Per Mesh Profile 4.3.2.65 */
  904. /* Source address */
  905. put_le16(parms[0], msg + n);
  906. n += 2;
  907. /* Destination address */
  908. put_le16(parms[1], msg + n);
  909. n += 2;
  910. /* Period log */
  911. msg[n++] = parms[2];
  912. if (!config_send(msg, n)) {
  913. bt_shell_printf("Failed to send \"SET HEARTBEAT SUBSCRIBE\"\n");
  914. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  915. }
  916. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  917. }
  918. static void cmd_hb_sub_get(int argc, char *argv[])
  919. {
  920. cmd_default(OP_CONFIG_HEARTBEAT_SUB_GET);
  921. }
  922. static void cmd_ttl_get(int argc, char *argv[])
  923. {
  924. cmd_default(OP_CONFIG_DEFAULT_TTL_GET);
  925. }
  926. static void cmd_node_reset(int argc, char *argv[])
  927. {
  928. cmd_default(OP_NODE_RESET);
  929. }
  930. static const struct bt_shell_menu cfg_menu = {
  931. .name = "config",
  932. .desc = "Configuration Model Submenu",
  933. .entries = {
  934. {"target", "<unicast>", cmd_node_set,
  935. "Set target node to configure"},
  936. {"composition-get", "[page_num]", cmd_composition_get,
  937. "Get composition data"},
  938. {"netkey-add", "<net_idx>", cmd_netkey_add,
  939. "Add network key"},
  940. {"netkey-del", "<net_idx>", cmd_netkey_del,
  941. "Delete network key"},
  942. {"appkey-add", "<app_idx>", cmd_appkey_add,
  943. "Add application key"},
  944. {"appkey-del", "<app_idx>", cmd_appkey_del,
  945. "Delete application key"},
  946. {"bind", "<ele_idx> <app_idx> <mod_id> [cid]",
  947. cmd_bind, "Bind app key to a model"},
  948. {"mod-appidx-get", "<ele_addr> <model id>",
  949. cmd_mod_appidx_get, "Get model app_idx"},
  950. {"ttl-set", "<ttl>", cmd_ttl_set,
  951. "Set default TTL"},
  952. {"ttl-get", NULL, cmd_ttl_get,
  953. "Get default TTL"},
  954. {"pub-set", "<ele_addr> <pub_addr> <app_idx> "
  955. "<per (step|res)> <re-xmt (cnt|per)> <mod id> "
  956. "[cid]",
  957. cmd_pub_set, "\n\t\t\t\t\t\t Set publication"},
  958. {"pub-get", "<ele_addr> <model>", cmd_pub_get,
  959. "Get publication"},
  960. {"proxy-set", "<proxy>", cmd_proxy_set,
  961. "Set proxy state"},
  962. {"proxy-get", NULL, cmd_proxy_get,
  963. "Get proxy state"},
  964. {"ident-set", "<net_idx> <state>", cmd_ident_set,
  965. "Set node identity state"},
  966. {"ident-get", "<net_idx>", cmd_ident_get,
  967. "Get node identity state"},
  968. {"beacon-set", "<state>", cmd_beacon_set,
  969. "Set node identity state"},
  970. {"beacon-get", NULL, cmd_beacon_get,
  971. "Get node beacon state"},
  972. {"relay-set", "<relay> <rexmt count> <rexmt steps>",
  973. cmd_relay_set,
  974. "Set relay"},
  975. {"relay-get", NULL, cmd_relay_get,
  976. "Get relay"},
  977. {"hb-pub-set", "<pub_addr> <count> <period> <ttl> <features> <net_idx>",
  978. cmd_hb_pub_set, "Set heartbeat publish"},
  979. {"hb-pub-get", NULL, cmd_hb_pub_get,
  980. "Get heartbeat publish"},
  981. {"hb-sub-set", "<src_addr> <dst_addr> <period>",
  982. cmd_hb_sub_set, "Set heartbeat subscribe"},
  983. {"hb-sub-get", NULL, cmd_hb_sub_get,
  984. "Get heartbeat subscribe"},
  985. {"sub-add", "<ele_addr> <sub_addr> <model id>",
  986. cmd_sub_add, "Add subscription"},
  987. {"sub-get", "<ele_addr> <model id>",
  988. cmd_sub_get, "Get subscription"},
  989. {"node-reset", NULL, cmd_node_reset,
  990. "Reset a node and remove it from network"},
  991. {} },
  992. };
  993. void config_client_get_composition(uint32_t dst)
  994. {
  995. uint32_t tmp = target;
  996. target = dst;
  997. cmd_composition_get(0, NULL);
  998. target = tmp;
  999. }
  1000. static struct mesh_model_ops client_cbs = {
  1001. client_msg_recvd,
  1002. NULL,
  1003. NULL,
  1004. NULL
  1005. };
  1006. bool config_client_init(void)
  1007. {
  1008. if (!node_local_model_register(PRIMARY_ELEMENT_IDX,
  1009. CONFIG_CLIENT_MODEL_ID,
  1010. &client_cbs, NULL))
  1011. return false;
  1012. bt_shell_add_submenu(&cfg_menu);
  1013. return true;
  1014. }