| /* |
| * |
| * BlueZ - Bluetooth protocol stack for Linux |
| * |
| * Copyright (C) 2017 Intel Corporation. All rights reserved. |
| * |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library 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 |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #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 <stdbool.h> |
| #include <sys/uio.h> |
| #include <wordexp.h> |
| |
| #include <glib.h> |
| |
| #include "src/shared/shell.h" |
| #include "src/shared/util.h" |
| #include "mesh/mesh-net.h" |
| #include "mesh/keys.h" |
| #include "mesh/net.h" |
| #include "mesh/node.h" |
| #include "mesh/prov-db.h" |
| #include "mesh/util.h" |
| #include "mesh/config-model.h" |
| |
| #define MIN_COMPOSITION_LEN 16 |
| |
| static uint32_t print_mod_id(uint8_t *data, bool vid) |
| { |
| uint32_t mod_id; |
| |
| if (!vid) { |
| mod_id = get_le16(data); |
| bt_shell_printf("Model Id\t%4.4x\n", mod_id); |
| mod_id = 0xffff0000 | mod_id; |
| } else { |
| mod_id = get_le16(data + 2); |
| bt_shell_printf("Model Id\t%4.4x %4.4x\n", |
| get_le16(data), mod_id); |
| mod_id = get_le16(data) << 16 | mod_id; |
| } |
| return mod_id; |
| } |
| |
| static bool client_msg_recvd(uint16_t src, uint8_t *data, |
| uint16_t len, void *user_data) |
| { |
| uint32_t opcode; |
| struct mesh_node *node; |
| uint16_t app_idx, net_idx, addr; |
| uint32_t mod_id; |
| uint16_t primary; |
| uint16_t ele_addr; |
| uint8_t ele_idx; |
| struct mesh_publication pub; |
| int n; |
| uint16_t i; |
| |
| if (mesh_opcode_get(data, len, &opcode, &n)) { |
| len -= n; |
| data += n; |
| } else |
| return false; |
| |
| if (IS_UNICAST(src)) { |
| node = node_find_by_addr(src); |
| } else |
| node = NULL; |
| |
| if (!node) |
| return false; |
| |
| primary = node_get_primary(node); |
| if (primary != src) |
| return false; |
| |
| switch (opcode & ~OP_UNRELIABLE) { |
| default: |
| return false; |
| |
| case OP_DEV_COMP_STATUS: |
| if (len < MIN_COMPOSITION_LEN || !node) |
| break; |
| if (node_parse_composition(node, data, len)) { |
| if (!prov_db_add_node_composition(node, data, len)) |
| break; |
| } |
| |
| if (node_get_composition(node)) |
| prov_db_print_node_composition(node); |
| break; |
| |
| case OP_APPKEY_STATUS: |
| if (len != 4) |
| break; |
| |
| bt_shell_printf("Node %4.4x AppKey status %s\n", src, |
| mesh_status_str(data[0])); |
| net_idx = get_le16(data + 1) & 0xfff; |
| app_idx = get_le16(data + 2) >> 4; |
| |
| bt_shell_printf("NetKey\t%3.3x\n", net_idx); |
| bt_shell_printf("AppKey\t%3.3x\n", app_idx); |
| |
| if (data[0] != MESH_STATUS_SUCCESS && |
| data[0] != MESH_STATUS_IDX_ALREADY_STORED && |
| node_app_key_delete(node, net_idx, app_idx)) |
| prov_db_node_keys(node, node_get_app_keys(node), |
| "appKeys"); |
| break; |
| |
| case OP_NETKEY_STATUS: |
| if (len != 3) |
| break; |
| |
| bt_shell_printf("Node %4.4x NetKey status %s\n", src, |
| mesh_status_str(data[0])); |
| net_idx = get_le16(data + 1) & 0xfff; |
| |
| bt_shell_printf("\tNetKey %3.3x\n", net_idx); |
| |
| if (data[0] != MESH_STATUS_SUCCESS && |
| data[0] != MESH_STATUS_IDX_ALREADY_STORED && |
| node_net_key_delete(node, net_idx)) |
| prov_db_node_keys(node, node_get_net_keys(node), |
| "netKeys"); |
| break; |
| |
| case OP_MODEL_APP_STATUS: |
| if (len != 7 && len != 9) |
| break; |
| |
| bt_shell_printf("Node %4.4x Model App status %s\n", src, |
| mesh_status_str(data[0])); |
| addr = get_le16(data + 1); |
| app_idx = get_le16(data + 3); |
| |
| bt_shell_printf("Element Addr\t%4.4x\n", addr); |
| |
| mod_id = print_mod_id(data + 5, (len == 9) ? true : false); |
| |
| bt_shell_printf("AppIdx\t\t%3.3x\n ", app_idx); |
| |
| if (data[0] == MESH_STATUS_SUCCESS && |
| node_add_binding(node, addr - src, mod_id, app_idx)) |
| prov_db_add_binding(node, addr - src, mod_id, app_idx); |
| break; |
| |
| case OP_NODE_IDENTITY_STATUS: |
| if (len != 4) |
| return true; |
| bt_shell_printf("Network index 0x%04x " |
| "Node Identity state 0x%02x status %s\n", |
| get_le16(data + 1), data[3], |
| mesh_status_str(data[0])); |
| break; |
| |
| case OP_CONFIG_RELAY_STATUS: |
| if (len != 2) |
| return true; |
| bt_shell_printf("Node %4.4x Relay state 0x%02x" |
| " count %d steps %d\n", |
| src, data[0], data[1]>>5, data[1] & 0x1f); |
| break; |
| |
| case OP_CONFIG_PROXY_STATUS: |
| if (len != 1) |
| return true; |
| bt_shell_printf("Node %4.4x Proxy state 0x%02x\n", |
| src, data[0]); |
| break; |
| |
| case OP_CONFIG_DEFAULT_TTL_STATUS: |
| if (len != 1) |
| return true; |
| bt_shell_printf("Node %4.4x Default TTL %d\n", src, data[0]); |
| if (node_set_default_ttl (node, data[0])) |
| prov_db_node_set_ttl(node, data[0]); |
| break; |
| |
| case OP_CONFIG_MODEL_PUB_STATUS: |
| if (len != 12 && len != 14) |
| return true; |
| |
| bt_shell_printf("\nNode %4.4x Publication status %s\n", |
| src, mesh_status_str(data[0])); |
| |
| if (data[0] != MESH_STATUS_SUCCESS) |
| return true; |
| |
| ele_addr = get_le16(data + 1); |
| |
| bt_shell_printf("Element Addr\t%04x\n", ele_addr); |
| |
| mod_id = print_mod_id(data + 10, (len == 14) ? true : false); |
| |
| pub.u.addr16 = get_le16(data + 3); |
| pub.app_idx = get_le16(data + 5); |
| pub.ttl = data[7]; |
| pub.period = data[8]; |
| n = (data[8] & 0x3f); |
| bt_shell_printf("Pub Addr\t%04x\n", pub.u.addr16); |
| switch (data[8] >> 6) { |
| case 0: |
| bt_shell_printf("Period\t\t%d ms\n", n * 100); |
| break; |
| case 2: |
| n *= 10; |
| /* fall through */ |
| case 1: |
| bt_shell_printf("Period\t\t%d sec\n", n); |
| break; |
| case 3: |
| bt_shell_printf("Period\t\t%d min\n", n * 10); |
| break; |
| } |
| |
| pub.retransmit = data[9]; |
| bt_shell_printf("Rexmit count\t%d\n", data[9] >> 5); |
| bt_shell_printf("Rexmit steps\t%d\n", data[9] & 0x1f); |
| |
| ele_idx = ele_addr - node_get_primary(node); |
| |
| /* Local configuration is saved by server */ |
| if (node == node_get_local_node()) |
| break; |
| |
| if (node_model_pub_set(node, ele_idx, mod_id, &pub)) |
| prov_db_node_set_model_pub(node, ele_idx, mod_id, |
| node_model_pub_get(node, ele_idx, mod_id)); |
| break; |
| |
| /* Per Mesh Profile 4.3.2.19 */ |
| case OP_CONFIG_MODEL_SUB_STATUS: |
| bt_shell_printf("\nNode %4.4x Subscription status %s\n", |
| src, mesh_status_str(data[0])); |
| |
| if (data[0] != MESH_STATUS_SUCCESS) |
| return true; |
| |
| ele_addr = get_le16(data + 1); |
| addr = get_le16(data + 3); |
| ele_idx = ele_addr - node_get_primary(node); |
| |
| bt_shell_printf("Element Addr\t%4.4x\n", ele_addr); |
| |
| mod_id = print_mod_id(data + 5, (len == 9) ? true : false); |
| |
| bt_shell_printf("Subscr Addr\t%4.4x\n", addr); |
| |
| /* Save subscriptions in node and database */ |
| if (node_add_subscription(node, ele_idx, mod_id, addr)) |
| prov_db_add_subscription(node, ele_idx, mod_id, addr); |
| break; |
| |
| /* Per Mesh Profile 4.3.2.27 */ |
| case OP_CONFIG_MODEL_SUB_LIST: |
| |
| bt_shell_printf("\nNode %4.4x Subscription List status %s\n", |
| src, mesh_status_str(data[0])); |
| |
| if (data[0] != MESH_STATUS_SUCCESS) |
| return true; |
| |
| bt_shell_printf("Element Addr\t%4.4x\n", get_le16(data + 1)); |
| bt_shell_printf("Model ID\t%4.4x\n", get_le16(data + 3)); |
| |
| for (i = 5; i < len; i += 2) |
| bt_shell_printf("Subscr Addr\t%4.4x\n", |
| get_le16(data + i)); |
| break; |
| |
| /* Per Mesh Profile 4.3.2.50 */ |
| case OP_MODEL_APP_LIST: |
| bt_shell_printf("\nNode %4.4x Model AppIdx " |
| "status %s\n", src, |
| mesh_status_str(data[0])); |
| |
| if (data[0] != MESH_STATUS_SUCCESS) |
| return true; |
| |
| bt_shell_printf("Element Addr\t%4.4x\n", get_le16(data + 1)); |
| bt_shell_printf("Model ID\t%4.4x\n", get_le16(data + 3)); |
| |
| for (i = 5; i < len; i += 2) |
| bt_shell_printf("Model AppIdx\t%4.4x\n", |
| get_le16(data + i)); |
| break; |
| |
| /* Per Mesh Profile 4.3.2.63 */ |
| case OP_CONFIG_HEARTBEAT_PUB_STATUS: |
| bt_shell_printf("\nNode %4.4x Heartbeat publish status %s\n", |
| src, mesh_status_str(data[0])); |
| |
| if (data[0] != MESH_STATUS_SUCCESS) |
| return true; |
| |
| bt_shell_printf("Destination\t%4.4x\n", get_le16(data + 1)); |
| bt_shell_printf("Count\t\t%2.2x\n", data[3]); |
| bt_shell_printf("Period\t\t%2.2x\n", data[4]); |
| bt_shell_printf("TTL\t\t%2.2x\n", data[5]); |
| bt_shell_printf("Features\t%4.4x\n", get_le16(data + 6)); |
| bt_shell_printf("Net_Idx\t%4.4x\n", get_le16(data + 8)); |
| break; |
| |
| /* Per Mesh Profile 4.3.2.66 */ |
| case OP_CONFIG_HEARTBEAT_SUB_STATUS: |
| bt_shell_printf("\nNode %4.4x Heartbeat subscribe status %s\n", |
| src, mesh_status_str(data[0])); |
| |
| if (data[0] != MESH_STATUS_SUCCESS) |
| return true; |
| |
| bt_shell_printf("Source\t\t%4.4x\n", get_le16(data + 1)); |
| bt_shell_printf("Destination\t%4.4x\n", get_le16(data + 3)); |
| bt_shell_printf("Period\t\t%2.2x\n", data[5]); |
| bt_shell_printf("Count\t\t%2.2x\n", data[6]); |
| bt_shell_printf("Min Hops\t%2.2x\n", data[7]); |
| bt_shell_printf("Max Hops\t%2.2x\n", data[8]); |
| break; |
| } |
| |
| return true; |
| } |
| |
| static uint32_t target; |
| static uint32_t parms[8]; |
| |
| static uint32_t read_input_parameters(int argc, char *argv[]) |
| { |
| uint32_t i; |
| |
| if (!argc) |
| return 0; |
| |
| --argc; |
| ++argv; |
| |
| if (!argc || argv[0][0] == '\0') |
| return 0; |
| |
| memset(parms, 0xff, sizeof(parms)); |
| |
| for (i = 0; i < sizeof(parms)/sizeof(parms[0]) && i < (unsigned) argc; |
| i++) { |
| sscanf(argv[i], "%x", &parms[i]); |
| if (parms[i] == 0xffffffff) |
| break; |
| } |
| |
| return i; |
| } |
| |
| static void cmd_node_set(int argc, char *argv[]) |
| { |
| uint32_t dst; |
| char *end; |
| |
| dst = strtol(argv[1], &end, 16); |
| if (end != (argv[1] + 4)) { |
| bt_shell_printf("Bad unicast address %s: " |
| "expected format 4 digit hex\n", argv[1]); |
| target = UNASSIGNED_ADDRESS; |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } else { |
| bt_shell_printf("Configuring node %4.4x\n", dst); |
| target = dst; |
| set_menu_prompt("config", argv[1]); |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| } |
| |
| static bool config_send(uint8_t *buf, uint16_t len) |
| { |
| struct mesh_node *node = node_get_local_node(); |
| uint16_t primary; |
| |
| if(!node) |
| return false; |
| |
| primary = node_get_primary(node); |
| if (target != primary) |
| return net_access_layer_send(DEFAULT_TTL, primary, |
| target, APP_IDX_DEV, buf, len); |
| |
| node_local_data_handler(primary, target, node_get_iv_index(node), |
| node_get_sequence_number(node), APP_IDX_DEV, |
| buf, len); |
| return true; |
| |
| } |
| |
| static void cmd_default(uint32_t opcode) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(opcode, msg); |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send command (opcode 0x%x)\n", |
| opcode); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_composition_get(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| struct mesh_node *node; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| node = node_find_by_addr(target); |
| |
| if (!node) |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| |
| n = mesh_opcode_set(OP_DEV_COMP_GET, msg); |
| |
| /* By default, use page 0 */ |
| msg[n++] = (read_input_parameters(argc, argv) == 1) ? parms[0] : 0; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"GET NODE COMPOSITION\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_net_key(int argc, char *argv[], uint32_t opcode) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| uint16_t net_idx; |
| uint8_t *key; |
| struct mesh_node *node; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(opcode, msg); |
| |
| if (read_input_parameters(argc, argv) != 1) { |
| bt_shell_printf("Bad arguments %s\n", argv[1]); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| node = node_find_by_addr(target); |
| if (!node) { |
| bt_shell_printf("Node %4.4x\n not found", target); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| net_idx = parms[0]; |
| |
| if (opcode != OP_NETKEY_DELETE) { |
| |
| key = keys_net_key_get(net_idx, true); |
| if (!key) { |
| bt_shell_printf("NetKey with index %4.4x not found\n", |
| net_idx); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| put_le16(net_idx, &msg[n]); |
| n += 2; |
| |
| memcpy(msg + n, key, 16); |
| n += 16; |
| } |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"%s NET KEY\"\n", |
| opcode == OP_NETKEY_ADD ? "ADD" : "DEL"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| if (opcode != OP_NETKEY_DELETE) { |
| if (node_net_key_add(node, net_idx)) |
| prov_db_node_keys(node, node_get_net_keys(node), |
| "netKeys"); |
| } else { |
| if (node_net_key_delete(node, net_idx)) |
| prov_db_node_keys(node, node_get_net_keys(node), |
| "netKeys"); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_netkey_add(int argc, char *argv[]) |
| { |
| cmd_net_key(argc, argv, OP_NETKEY_ADD); |
| } |
| |
| static void cmd_netkey_del(int argc, char *argv[]) |
| { |
| cmd_net_key(argc, argv, OP_NETKEY_DELETE); |
| } |
| |
| static void cmd_app_key(int argc, char *argv[], uint32_t opcode) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| uint16_t net_idx; |
| uint16_t app_idx; |
| uint8_t *key; |
| struct mesh_node *node; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| if (read_input_parameters(argc, argv) != 1) { |
| bt_shell_printf("Bad arguments %s\n", argv[1]); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| node = node_find_by_addr(target); |
| if (!node) { |
| bt_shell_printf("Node %4.4x\n not found", target); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(opcode, msg); |
| |
| app_idx = parms[0]; |
| net_idx = keys_app_key_get_bound(app_idx); |
| if (net_idx == NET_IDX_INVALID) { |
| bt_shell_printf("AppKey with index %4.4x not found\n", app_idx); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| msg[n++] = net_idx & 0xf; |
| msg[n++] = ((net_idx >> 8) & 0xf) | |
| ((app_idx << 4) & 0xf0); |
| msg[n++] = app_idx >> 4; |
| |
| if (opcode != OP_APPKEY_DELETE) { |
| key = keys_app_key_get(app_idx, true); |
| if (!key) { |
| bt_shell_printf("AppKey %4.4x not found\n", net_idx); |
| return; |
| } |
| |
| memcpy(msg + n, key, 16); |
| n += 16; |
| } |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"ADD %s KEY\"\n", |
| opcode == OP_APPKEY_ADD ? "ADD" : "DEL"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| if (opcode != OP_APPKEY_DELETE) { |
| if (node_app_key_add(node, app_idx)) |
| prov_db_node_keys(node, node_get_app_keys(node), |
| "appKeys"); |
| } else { |
| if (node_app_key_delete(node, net_idx, app_idx)) |
| prov_db_node_keys(node, node_get_app_keys(node), |
| "appKeys"); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_appkey_add(int argc, char *argv[]) |
| { |
| cmd_app_key(argc, argv, OP_APPKEY_ADD); |
| } |
| |
| static void cmd_appkey_del(int argc, char *argv[]) |
| { |
| cmd_app_key(argc, argv, OP_APPKEY_DELETE); |
| } |
| |
| static bool verify_config_target(uint32_t dst) |
| { |
| struct mesh_node *node; |
| |
| if (IS_UNASSIGNED(dst)) { |
| bt_shell_printf("Destination not set\n"); |
| return false; |
| } |
| |
| node = node_find_by_addr(dst); |
| if (!node) { |
| bt_shell_printf("Node with unicast address %4.4x unknown\n", |
| dst); |
| return false; |
| } |
| |
| if (!node_get_composition(node)) { |
| bt_shell_printf("Node composition for %4.4x unknown\n", dst); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static void cmd_bind(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| int parm_cnt; |
| |
| if (!verify_config_target(target)) |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 3 && parm_cnt != 4) { |
| bt_shell_printf("Bad arguments\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(OP_MODEL_APP_BIND, msg); |
| |
| put_le16(target + parms[0], msg + n); |
| n += 2; |
| put_le16(parms[1], msg + n); |
| n += 2; |
| if (parm_cnt == 4) { |
| put_le16(parms[3], msg + n); |
| put_le16(parms[2], msg + n + 2); |
| n += 4; |
| } else { |
| put_le16(parms[2], msg + n); |
| n += 2; |
| } |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"MODEL APP BIND\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_ident_set(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[2 + 3 + 4]; |
| int parm_cnt; |
| |
| if (!verify_config_target(target)) |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| |
| n = mesh_opcode_set(OP_NODE_IDENTITY_SET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 2) { |
| bt_shell_printf("bad arguments\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| put_le16(parms[0], msg + n); |
| n += 2; |
| msg[n++] = parms[1]; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"SET IDENTITY\"\n"); |
| return; |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_ident_get(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[2 + 2 + 4]; |
| int parm_cnt; |
| |
| if (!verify_config_target(target)) |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| |
| n = mesh_opcode_set(OP_NODE_IDENTITY_GET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 1) { |
| bt_shell_printf("bad arguments\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| put_le16(parms[0], msg + n); |
| n += 2; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"GET IDENTITY\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_proxy_set(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[2 + 1 + 4]; |
| int parm_cnt; |
| |
| if (!verify_config_target(target)) |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| |
| n = mesh_opcode_set(OP_CONFIG_PROXY_SET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 1) { |
| bt_shell_printf("bad arguments"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| msg[n++] = parms[0]; |
| msg[n++] = parms[1]; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"SET PROXY\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_proxy_get(int argc, char *argv[]) |
| { |
| cmd_default(OP_CONFIG_PROXY_GET); |
| } |
| |
| static void cmd_relay_set(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[2 + 2 + 4]; |
| int parm_cnt; |
| |
| if (!verify_config_target(target)) |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| |
| n = mesh_opcode_set(OP_CONFIG_RELAY_SET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 3) { |
| bt_shell_printf("bad arguments\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| msg[n++] = parms[0]; |
| msg[n++] = (parms[1] << 5) | parms[2]; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"SET RELAY\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_relay_get(int argc, char *argv[]) |
| { |
| cmd_default(OP_CONFIG_RELAY_GET); |
| } |
| |
| static void cmd_ttl_set(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| int parm_cnt; |
| uint8_t ttl; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(OP_CONFIG_DEFAULT_TTL_SET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt) { |
| ttl = parms[0] & TTL_MASK; |
| } else |
| ttl = node_get_default_ttl(node_get_local_node()); |
| |
| msg[n++] = ttl; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"SET_DEFAULT TTL\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_pub_set(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| int parm_cnt; |
| |
| if (!verify_config_target(target)) |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| |
| n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_SET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 6 && parm_cnt != 7) { |
| bt_shell_printf("Bad arguments\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| put_le16(parms[0], msg + n); |
| n += 2; |
| /* Publish address */ |
| put_le16(parms[1], msg + n); |
| n += 2; |
| /* AppKey index + credential (set to 0) */ |
| put_le16(parms[2], msg + n); |
| n += 2; |
| /* TTL */ |
| msg[n++] = DEFAULT_TTL; |
| /* Publish period step count and step resolution */ |
| msg[n++] = parms[3]; |
| /* Publish retransmit count & interval steps */ |
| msg[n++] = parms[4]; |
| /* Model Id */ |
| if (parm_cnt == 7) { |
| put_le16(parms[6], msg + n); |
| put_le16(parms[5], msg + n + 2); |
| n += 4; |
| } else { |
| put_le16(parms[5], msg + n); |
| n += 2; |
| } |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"SET MODEL PUBLICATION\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_pub_get(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| int parm_cnt; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_GET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 2 && parm_cnt != 3) { |
| bt_shell_printf("Bad arguments: %s\n", argv[1]); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| /* Element Address */ |
| put_le16(parms[0], msg + n); |
| n += 2; |
| /* Model Id */ |
| if (parm_cnt == 3) { |
| put_le16(parms[2], msg + n); |
| put_le16(parms[1], msg + n + 2); |
| n += 4; |
| } else { |
| put_le16(parms[1], msg + n); |
| n += 2; |
| } |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"GET MODEL PUBLICATION\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_sub_add(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| int parm_cnt; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(OP_CONFIG_MODEL_SUB_ADD, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 3) { |
| bt_shell_printf("Bad arguments: %s\n", argv[1]); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| /* Per Mesh Profile 4.3.2.19 */ |
| /* Element Address */ |
| put_le16(parms[0], msg + n); |
| n += 2; |
| /* Subscription Address */ |
| put_le16(parms[1], msg + n); |
| n += 2; |
| /* SIG Model ID */ |
| put_le16(parms[2], msg + n); |
| n += 2; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"ADD SUBSCRIPTION\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_sub_get(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| int parm_cnt; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(OP_CONFIG_MODEL_SUB_GET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 2) { |
| bt_shell_printf("Bad arguments: %s\n", argv[1]); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| /* Per Mesh Profile 4.3.2.27 */ |
| /* Element Address */ |
| put_le16(parms[0], msg + n); |
| n += 2; |
| /* Model ID */ |
| put_le16(parms[1], msg + n); |
| n += 2; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"GET SUB GET\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_mod_appidx_get(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| int parm_cnt; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(OP_MODEL_APP_GET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 2) { |
| bt_shell_printf("Bad arguments: %s\n", argv[1]); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| /* Per Mesh Profile 4.3.2.49 */ |
| /* Element Address */ |
| put_le16(parms[0], msg + n); |
| n += 2; |
| /* Model ID */ |
| put_le16(parms[1], msg + n); |
| n += 2; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"GET APP GET\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_hb_pub_set(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| int parm_cnt; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(OP_CONFIG_HEARTBEAT_PUB_SET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 5) { |
| bt_shell_printf("Bad arguments: %s\n", argv[1]); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| /* Per Mesh Profile 4.3.2.62 */ |
| /* Publish address */ |
| put_le16(parms[0], msg + n); |
| n += 2; |
| /* Count Log */ |
| msg[n++] = parms[1]; |
| /* Period Log */ |
| msg[n++] = parms[2]; |
| /* Heartbeat TTL */ |
| msg[n++] = DEFAULT_TTL; |
| /* Features */ |
| put_le16(parms[3], msg + n); |
| n += 2; |
| /* NetKey Index */ |
| put_le16(parms[4], msg + n); |
| n += 2; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"SET HEARTBEAT PUBLISH\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_hb_pub_get(int argc, char *argv[]) |
| { |
| cmd_default(OP_CONFIG_HEARTBEAT_PUB_GET); |
| } |
| |
| static void cmd_hb_sub_set(int argc, char *argv[]) |
| { |
| uint16_t n; |
| uint8_t msg[32]; |
| int parm_cnt; |
| |
| if (IS_UNASSIGNED(target)) { |
| bt_shell_printf("Destination not set\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| n = mesh_opcode_set(OP_CONFIG_HEARTBEAT_SUB_SET, msg); |
| |
| parm_cnt = read_input_parameters(argc, argv); |
| if (parm_cnt != 3) { |
| bt_shell_printf("Bad arguments: %s\n", argv[1]); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| /* Per Mesh Profile 4.3.2.65 */ |
| /* Source address */ |
| put_le16(parms[0], msg + n); |
| n += 2; |
| /* Destination address */ |
| put_le16(parms[1], msg + n); |
| n += 2; |
| /* Period log */ |
| msg[n++] = parms[2]; |
| |
| if (!config_send(msg, n)) { |
| bt_shell_printf("Failed to send \"SET HEARTBEAT SUBSCRIBE\"\n"); |
| return bt_shell_noninteractive_quit(EXIT_FAILURE); |
| } |
| |
| return bt_shell_noninteractive_quit(EXIT_SUCCESS); |
| } |
| |
| static void cmd_hb_sub_get(int argc, char *argv[]) |
| { |
| cmd_default(OP_CONFIG_HEARTBEAT_SUB_GET); |
| } |
| |
| static void cmd_ttl_get(int argc, char *argv[]) |
| { |
| cmd_default(OP_CONFIG_DEFAULT_TTL_GET); |
| } |
| |
| static const struct bt_shell_menu cfg_menu = { |
| .name = "config", |
| .desc = "Configuration Model Submenu", |
| .entries = { |
| {"target", "<unicast>", cmd_node_set, |
| "Set target node to configure"}, |
| {"composition-get", "[page_num]", cmd_composition_get, |
| "Get composition data"}, |
| {"netkey-add", "<net_idx>", cmd_netkey_add, |
| "Add network key"}, |
| {"netkey-del", "<net_idx>", cmd_netkey_del, |
| "Delete network key"}, |
| {"appkey-add", "<app_idx>", cmd_appkey_add, |
| "Add application key"}, |
| {"appkey-del", "<app_idx>", cmd_appkey_del, |
| "Delete application key"}, |
| {"bind", "<ele_idx> <app_idx> <mod_id> [cid]", |
| cmd_bind, "Bind app key to a model"}, |
| {"mod-appidx-get", "<ele_addr> <model id>", |
| cmd_mod_appidx_get, "Get model app_idx"}, |
| {"ttl-set", "<ttl>", cmd_ttl_set, |
| "Set default TTL"}, |
| {"ttl-get", NULL, cmd_ttl_get, |
| "Get default TTL"}, |
| {"pub-set", "<ele_addr> <pub_addr> <app_idx> " |
| "<per (step|res)> <re-xmt (cnt|per)> <mod id> " |
| "[cid]", |
| cmd_pub_set, "\n\t\t\t\t\t\t Set publication"}, |
| {"pub-get", "<ele_addr> <model>", cmd_pub_get, |
| "Get publication"}, |
| {"proxy-set", "<proxy>", cmd_proxy_set, |
| "Set proxy state"}, |
| {"proxy-get", NULL, cmd_proxy_get, |
| "Get proxy state"}, |
| {"ident-set", "<net_idx> <state>", cmd_ident_set, |
| "Set node identity state"}, |
| {"ident-get", "<net_idx>", cmd_ident_get, |
| "Get node identity state"}, |
| {"relay-set", "<relay> <rexmt count> <rexmt steps>", |
| cmd_relay_set, |
| "Set relay"}, |
| {"relay-get", NULL, cmd_relay_get, |
| "Get relay"}, |
| {"hb-pub-set", "<pub_addr> <count> <period> <features> <net_idx>", |
| cmd_hb_pub_set, "Set heartbeat publish"}, |
| {"hb-pub-get", NULL, cmd_hb_pub_get, |
| "Get heartbeat publish"}, |
| {"hb-sub-set", "<src_addr> <dst_addr> <period>", |
| cmd_hb_sub_set, "Set heartbeat subscribe"}, |
| {"hb-sub-get", NULL, cmd_hb_sub_get, |
| "Get heartbeat subscribe"}, |
| {"sub-add", "<ele_addr> <sub_addr> <model id>", |
| cmd_sub_add, "Add subscription"}, |
| {"sub-get", "<ele_addr> <model id>", |
| cmd_sub_get, "Get subscription"}, |
| {} }, |
| }; |
| |
| void config_client_get_composition(uint32_t dst) |
| { |
| uint32_t tmp = target; |
| |
| target = dst; |
| cmd_composition_get(0, NULL); |
| target = tmp; |
| } |
| |
| static struct mesh_model_ops client_cbs = { |
| client_msg_recvd, |
| NULL, |
| NULL, |
| NULL |
| }; |
| |
| bool config_client_init(void) |
| { |
| if (!node_local_model_register(PRIMARY_ELEMENT_IDX, |
| CONFIG_CLIENT_MODEL_ID, |
| &client_cbs, NULL)) |
| return false; |
| |
| bt_shell_add_submenu(&cfg_menu); |
| |
| return true; |
| } |