1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdlib.h>
8 #include <zephyr/shell/shell.h>
9 #include <zephyr/bluetooth/mesh.h>
10 #include <zephyr/bluetooth/mesh/shell.h>
11 
12 #include "mesh/foundation.h"
13 #include "utils.h"
14 
cmd_subnet_bridge_get(const struct shell * sh,size_t argc,char * argv[])15 static int cmd_subnet_bridge_get(const struct shell *sh, size_t argc, char *argv[])
16 {
17 	enum bt_mesh_brg_cfg_state rsp;
18 	int err;
19 
20 	err = bt_mesh_brg_cfg_cli_get(bt_mesh_shell_target_ctx.net_idx,
21 				      bt_mesh_shell_target_ctx.dst, &rsp);
22 	if (err) {
23 		shell_error(sh, "Failed to send Subnet Bridge Get (err %d)", err);
24 		return -ENOEXEC;
25 	}
26 
27 	shell_print(sh, "Subnet Bridge State: %s",
28 		    (rsp == BT_MESH_BRG_CFG_ENABLED) ? "Enabled" : "Disabled");
29 	return 0;
30 }
31 
cmd_subnet_bridge_set(const struct shell * sh,size_t argc,char * argv[])32 static int cmd_subnet_bridge_set(const struct shell *sh, size_t argc, char *argv[])
33 {
34 	enum bt_mesh_brg_cfg_state set, rsp;
35 	int err = 0;
36 
37 	set = shell_strtobool(argv[1], 0, &err) ? BT_MESH_BRG_CFG_ENABLED
38 						: BT_MESH_BRG_CFG_DISABLED;
39 
40 	if (err) {
41 		shell_warn(sh, "Unable to parse input string argument");
42 		return err;
43 	}
44 
45 	err = bt_mesh_brg_cfg_cli_set(bt_mesh_shell_target_ctx.net_idx,
46 				      bt_mesh_shell_target_ctx.dst, set, &rsp);
47 	if (err) {
48 		shell_error(sh, "Failed to send Subnet Bridge Set (err %d)", err);
49 		return -ENOEXEC;
50 	}
51 
52 	shell_print(sh, "Subnet Bridge State: %s",
53 		    (rsp == BT_MESH_BRG_CFG_ENABLED) ? "Enabled" : "Disabled");
54 	return 0;
55 }
56 
cmd_bridging_table_size_get(const struct shell * sh,size_t argc,char * argv[])57 static int cmd_bridging_table_size_get(const struct shell *sh, size_t argc, char *argv[])
58 {
59 	uint16_t rsp;
60 	int err;
61 
62 	err = bt_mesh_brg_cfg_cli_table_size_get(bt_mesh_shell_target_ctx.net_idx,
63 						 bt_mesh_shell_target_ctx.dst, &rsp);
64 	if (err) {
65 		shell_error(sh, "Failed to send Bridging Table Size Get (err %d)", err);
66 		return -ENOEXEC;
67 	}
68 
69 	shell_print(sh, "Bridging Table Size: %u", rsp);
70 	return 0;
71 }
72 
cmd_bridging_table_add(const struct shell * sh,size_t argc,char * argv[])73 static int cmd_bridging_table_add(const struct shell *sh, size_t argc, char *argv[])
74 {
75 	struct bt_mesh_brg_cfg_table_entry entry;
76 	struct bt_mesh_brg_cfg_table_status rsp;
77 	int err = 0;
78 
79 	entry.directions = shell_strtoul(argv[1], 0, &err);
80 	entry.net_idx1 = shell_strtoul(argv[2], 0, &err);
81 	entry.net_idx2 = shell_strtoul(argv[3], 0, &err);
82 	entry.addr1 = shell_strtoul(argv[4], 0, &err);
83 	entry.addr2 = shell_strtoul(argv[5], 0, &err);
84 	if (err) {
85 		shell_warn(sh, "Unable to parse input string argument");
86 		return err;
87 	}
88 
89 	err = bt_mesh_brg_cfg_cli_table_add(bt_mesh_shell_target_ctx.net_idx,
90 					    bt_mesh_shell_target_ctx.dst, &entry, &rsp);
91 	if (err) {
92 		shell_error(sh, "Failed to send Bridging Table Add (err %d)", err);
93 		return -ENOEXEC;
94 	}
95 
96 	if (rsp.status) {
97 		shell_print(sh, "Bridging Table Add failed with status 0x%02x", rsp.status);
98 	} else {
99 		shell_print(sh, "Bridging Table Add was successful.");
100 	}
101 	return 0;
102 }
103 
cmd_bridging_table_remove(const struct shell * sh,size_t argc,char * argv[])104 static int cmd_bridging_table_remove(const struct shell *sh, size_t argc, char *argv[])
105 {
106 	uint16_t net_idx1, net_idx2, addr1, addr2;
107 	struct bt_mesh_brg_cfg_table_status rsp;
108 	int err = 0;
109 
110 	net_idx1 = shell_strtoul(argv[1], 0, &err);
111 	net_idx2 = shell_strtoul(argv[2], 0, &err);
112 	addr1 = shell_strtoul(argv[3], 0, &err);
113 	addr2 = shell_strtoul(argv[4], 0, &err);
114 	if (err) {
115 		shell_warn(sh, "Unable to parse input string argument");
116 		return err;
117 	}
118 
119 	err = bt_mesh_brg_cfg_cli_table_remove(bt_mesh_shell_target_ctx.net_idx,
120 					       bt_mesh_shell_target_ctx.dst, net_idx1, net_idx2,
121 					       addr1, addr2, &rsp);
122 	if (err) {
123 		shell_error(sh, "Failed to send Bridging Table Remove (err %d)", err);
124 		return -ENOEXEC;
125 	}
126 
127 	if (rsp.status) {
128 		shell_print(sh, "Bridging Table Remove failed with status 0x%02x", rsp.status);
129 	} else {
130 		shell_print(sh, "Bridging Table Remove was successful.");
131 	}
132 	return 0;
133 }
134 
cmd_bridged_subnets_get(const struct shell * sh,size_t argc,char * argv[])135 static int cmd_bridged_subnets_get(const struct shell *sh, size_t argc, char *argv[])
136 {
137 	struct bt_mesh_brg_cfg_filter_netkey filter_net_idx;
138 	uint8_t start_idx;
139 	struct bt_mesh_brg_cfg_subnets_list rsp = {
140 		.list = NET_BUF_SIMPLE(CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX * 3),
141 	};
142 	int err = 0;
143 
144 	net_buf_simple_init(rsp.list, 0);
145 
146 	filter_net_idx.filter = shell_strtoul(argv[1], 0, &err);
147 	filter_net_idx.net_idx = shell_strtoul(argv[2], 0, &err);
148 	start_idx = shell_strtoul(argv[3], 0, &err);
149 	if (err) {
150 		shell_warn(sh, "Unable to parse input string argument");
151 		return err;
152 	}
153 
154 	err = bt_mesh_brg_cfg_cli_subnets_get(bt_mesh_shell_target_ctx.net_idx,
155 					      bt_mesh_shell_target_ctx.dst, filter_net_idx,
156 					      start_idx, &rsp);
157 	if (err) {
158 		shell_error(sh, "Failed to send Bridged Subnets Get (err %d)", err);
159 		return -ENOEXEC;
160 	}
161 
162 	shell_print(sh, "Bridged Subnets List:");
163 	shell_print(sh, "\tfilter: %02x", rsp.net_idx_filter.filter);
164 	shell_print(sh, "\tnet_idx: %04x", rsp.net_idx_filter.net_idx);
165 	shell_print(sh, "\tstart_idx: %u", rsp.start_idx);
166 	if (rsp.list) {
167 		uint16_t net_idx1, net_idx2;
168 		int i = 0;
169 
170 		while (rsp.list->len) {
171 			key_idx_unpack_pair(rsp.list, &net_idx1, &net_idx2);
172 			shell_print(sh, "\tEntry %d:", i++);
173 			shell_print(sh, "\t\tnet_idx1: 0x%04x, net_idx2: 0x%04x", net_idx1,
174 				    net_idx2);
175 		}
176 	}
177 	return 0;
178 }
179 
cmd_bridging_table_get(const struct shell * sh,size_t argc,char * argv[])180 static int cmd_bridging_table_get(const struct shell *sh, size_t argc, char *argv[])
181 {
182 	uint16_t net_idx1, net_idx2, start_idx;
183 	struct bt_mesh_brg_cfg_table_list rsp = {
184 		.list = NET_BUF_SIMPLE(CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX * 5),
185 	};
186 	int err = 0;
187 
188 	net_buf_simple_init(rsp.list, 0);
189 
190 	net_idx1 = shell_strtoul(argv[1], 0, &err);
191 	net_idx2 = shell_strtoul(argv[2], 0, &err);
192 	start_idx = shell_strtoul(argv[3], 0, &err);
193 	if (err) {
194 		shell_warn(sh, "Unable to parse input string argument");
195 		return err;
196 	}
197 
198 	err = bt_mesh_brg_cfg_cli_table_get(bt_mesh_shell_target_ctx.net_idx,
199 					    bt_mesh_shell_target_ctx.dst, net_idx1, net_idx2,
200 					    start_idx, &rsp);
201 	if (err) {
202 		shell_error(sh, "Failed to send Bridging Table Get (err %d)", err);
203 		return -ENOEXEC;
204 	}
205 
206 	if (rsp.status) {
207 		shell_print(sh, "Bridging Table Get failed with status 0x%02x", rsp.status);
208 	} else {
209 		shell_print(sh, "Bridging Table List:");
210 		shell_print(sh, "\tstatus: %02x", rsp.status);
211 		shell_print(sh, "\tnet_idx1: %04x", rsp.net_idx1);
212 		shell_print(sh, "\tnet_idx2: %04x", rsp.net_idx2);
213 		shell_print(sh, "\tstart_idx: %u", rsp.start_idx);
214 		if (rsp.list) {
215 			uint16_t addr1, addr2;
216 			uint8_t directions;
217 			int i = 0;
218 
219 			while (rsp.list->len) {
220 				addr1 = net_buf_simple_pull_le16(rsp.list);
221 				addr2 = net_buf_simple_pull_le16(rsp.list);
222 				directions = net_buf_simple_pull_u8(rsp.list);
223 				shell_print(sh, "\tEntry %d:", i++);
224 				shell_print(sh,
225 					    "\t\taddr1: 0x%04x, addr2: 0x%04x, directions: 0x%02x",
226 					    addr1, addr2, directions);
227 			}
228 		}
229 	}
230 	return 0;
231 }
232 
233 SHELL_STATIC_SUBCMD_SET_CREATE(
234 	brg_cfg_cmds, SHELL_CMD_ARG(get, NULL, NULL, cmd_subnet_bridge_get, 1, 0),
235 	SHELL_CMD_ARG(set, NULL, "<State(disable, enable)>", cmd_subnet_bridge_set, 2, 0),
236 	SHELL_CMD_ARG(table-size-get, NULL, NULL, cmd_bridging_table_size_get, 1, 0),
237 	SHELL_CMD_ARG(table-add, NULL, "<Directions> <NetIdx1> <NetIdx2> <Addr1> <Addr2>",
238 		      cmd_bridging_table_add, 6, 0),
239 	SHELL_CMD_ARG(table-remove, NULL, "<NetIdx1> <NetIdx2> <Addr1> <Addr2>",
240 		      cmd_bridging_table_remove, 5, 0),
241 	SHELL_CMD_ARG(subnets-get, NULL, "<Filter> <NetIdx> <StartIdx>", cmd_bridged_subnets_get,
242 		      4, 0),
243 	SHELL_CMD_ARG(table-get, NULL, "<NetIdx1> <NetIdx2> <StartIdx>", cmd_bridging_table_get,
244 		      4, 0),
245 	SHELL_SUBCMD_SET_END);
246 
247 SHELL_SUBCMD_ADD((mesh, models), brg, &brg_cfg_cmds, "Bridge Configuration Cli commands",
248 		 bt_mesh_shell_mdl_cmds_help, 1, 1);
249