1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <assert.h>
21 #include <inttypes.h>
22 #include <errno.h>
23 #include <string.h>
24
25 #include "nimble/ble.h"
26 #include "nimble/nimble_opt.h"
27 #include "nimble/hci_common.h"
28 #include "host/ble_gap.h"
29 #include "host/ble_hs_adv.h"
30 #include "host/ble_sm.h"
31 #include "host/ble_eddystone.h"
32 #include "host/ble_hs_id.h"
33 #include "services/gatt/ble_svc_gatt.h"
34 #include "../src/ble_hs_priv.h"
35
36 #include "cmd.h"
37 #include "btshell.h"
38 #include "cmd_gatt.h"
39 #include "cmd_l2cap.h"
40
41 #include "nimble/npl_shell.h"
42
43 #define BTSHELL_MODULE "btshell"
44
45 int
cmd_parse_conn_start_end(uint16_t * out_conn,uint16_t * out_start,uint16_t * out_end)46 cmd_parse_conn_start_end(uint16_t *out_conn, uint16_t *out_start,
47 uint16_t *out_end)
48 {
49 int rc;
50
51 *out_conn = parse_arg_uint16("conn", &rc);
52 if (rc != 0) {
53 return rc;
54 }
55
56 *out_start = parse_arg_uint16("start", &rc);
57 if (rc != 0) {
58 return rc;
59 }
60
61 *out_end = parse_arg_uint16("end", &rc);
62 if (rc != 0) {
63 return rc;
64 }
65
66 return 0;
67 }
68
69 static const struct kv_pair cmd_own_addr_types[] = {
70 { "public", BLE_OWN_ADDR_PUBLIC },
71 { "random", BLE_OWN_ADDR_RANDOM },
72 { "rpa_pub", BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT },
73 { "rpa_rnd", BLE_OWN_ADDR_RPA_RANDOM_DEFAULT },
74 { NULL }
75 };
76
77 static const struct kv_pair cmd_peer_addr_types[] = {
78 { "public", BLE_ADDR_PUBLIC },
79 { "random", BLE_ADDR_RANDOM },
80 { "public_id", BLE_ADDR_PUBLIC_ID },
81 { "random_id", BLE_ADDR_RANDOM_ID },
82 { NULL }
83 };
84
85 static const struct kv_pair cmd_addr_type[] = {
86 { "public", BLE_ADDR_PUBLIC },
87 { "random", BLE_ADDR_RANDOM },
88 { NULL }
89 };
90
91
92
93 /*****************************************************************************
94 * $advertise *
95 *****************************************************************************/
96 static const struct kv_pair cmd_adv_filt_types[] = {
97 { "none", BLE_HCI_ADV_FILT_NONE },
98 { "scan", BLE_HCI_ADV_FILT_SCAN },
99 { "conn", BLE_HCI_ADV_FILT_CONN },
100 { "both", BLE_HCI_ADV_FILT_BOTH },
101 { NULL }
102 };
103
104 #if MYNEWT_VAL(BLE_EXT_ADV)
105 static struct kv_pair cmd_ext_adv_phy_opts[] = {
106 { "1M", 0x01 },
107 { "2M", 0x02 },
108 { "coded", 0x03 },
109 { NULL }
110 };
111
112 static bool adv_instances[BLE_ADV_INSTANCES];
113
114 static int
cmd_advertise_configure(int argc,char ** argv)115 cmd_advertise_configure(int argc, char **argv)
116 {
117 struct ble_gap_ext_adv_params params = {0};
118 int8_t selected_tx_power;
119 uint8_t instance;
120 int rc;
121
122 rc = parse_arg_all(argc - 1, argv + 1);
123 if (rc != 0) {
124 return rc;
125 }
126
127 instance = parse_arg_uint8_dflt("instance", 0, &rc);
128 if (rc != 0 || instance >= BLE_ADV_INSTANCES) {
129 console_printf("invalid instance\n");
130 return rc;
131 }
132
133 if (adv_instances[instance]) {
134 console_printf("instance already configured\n");
135 return rc;
136 }
137
138 memset(¶ms, 0, sizeof(params));
139
140 params.legacy_pdu = parse_arg_bool_dflt("legacy", 0, &rc);
141 if (rc != 0) {
142 console_printf("invalid 'legacy' parameter\n");
143 return rc;
144 }
145
146 if (params.legacy_pdu) {
147 params.connectable = 1;
148 params.scannable = 1;
149 }
150
151 params.connectable = parse_arg_bool_dflt("connectable", params.connectable, &rc);
152 if (rc != 0) {
153 console_printf("invalid 'connectable' parameter\n");
154 return rc;
155 }
156
157 params.scannable = parse_arg_bool_dflt("scannable", params.scannable, &rc);
158 if (rc != 0) {
159 console_printf("invalid 'scannable' parameter\n");
160 return rc;
161 }
162
163 params.high_duty_directed = parse_arg_bool_dflt("high_duty", 0, &rc);
164 if (rc != 0) {
165 console_printf("invalid 'high_duty' parameter\n");
166 return rc;
167 }
168
169 params.anonymous = parse_arg_bool_dflt("anonymous", 0, &rc);
170 if (rc != 0) {
171 console_printf("invalid 'anonymous' parameter\n");
172 return rc;
173 }
174
175 params.include_tx_power = parse_arg_bool_dflt("include_tx_power", 0, &rc);
176 if (rc != 0) {
177 console_printf("invalid 'include_tx_power' parameter\n");
178 return rc;
179 }
180
181 params.scan_req_notif = parse_arg_bool_dflt("scan_req_notif", 0, &rc);
182 if (rc != 0) {
183 console_printf("invalid 'scan_req_notif' parameter\n");
184 return rc;
185 }
186
187 rc = parse_arg_mac("peer_addr", params.peer.val);
188 if (rc == 0) {
189 params.directed = 1;
190
191 params.peer.type = parse_arg_kv_dflt("peer_addr_type",
192 cmd_peer_addr_types,
193 BLE_ADDR_PUBLIC, &rc);
194 if (rc != 0) {
195 console_printf("invalid 'peer_addr_type' parameter\n");
196 return rc;
197 }
198 }
199 else if (rc == ENOENT) {
200 /* skip, no peer address provided */
201 } else {
202 console_printf("invalid 'peer_addr' parameter\n");
203 return rc;
204 }
205
206
207 params.directed = parse_arg_bool_dflt("directed", params.directed, &rc);
208 if (rc != 0) {
209 console_printf("invalid 'directed' parameter\n");
210 return rc;
211 }
212
213 if (params.directed && params.legacy_pdu) {
214 params.scannable = 0;
215 }
216
217 params.own_addr_type = parse_arg_kv_dflt("own_addr_type",
218 cmd_own_addr_types,
219 BLE_OWN_ADDR_PUBLIC, &rc);
220 if (rc != 0) {
221 console_printf("invalid 'own_addr_type' parameter\n");
222 return rc;
223 }
224
225 params.channel_map = parse_arg_uint8_dflt("channel_map", 0, &rc);
226 if (rc != 0) {
227 console_printf("invalid 'channel_map' parameter\n");
228 return rc;
229 }
230
231 params.filter_policy = parse_arg_kv_dflt("filter", cmd_adv_filt_types,
232 BLE_HCI_ADV_FILT_NONE, &rc);
233 if (rc != 0) {
234 console_printf("invalid 'filter' parameter\n");
235 return rc;
236 }
237
238 params.itvl_min = parse_arg_uint32_dflt("interval_min", 0, &rc);
239 if (rc != 0) {
240 console_printf("invalid 'interval_min' parameter\n");
241 return rc;
242 }
243
244 params.itvl_max = parse_arg_uint32_dflt("interval_max", 0, &rc);
245 if (rc != 0) {
246 console_printf("invalid 'interval_max' parameter\n");
247 return rc;
248 }
249
250 params.tx_power = parse_arg_long_bounds_dflt("tx_power",
251 -127, 127, 127, &rc);
252 if (rc != 0) {
253 console_printf("invalid 'tx_power' parameter\n");
254 return rc;
255 }
256
257 params.primary_phy = parse_arg_kv_dflt("primary_phy", cmd_ext_adv_phy_opts,
258 1, &rc);
259 if (rc != 0) {
260 console_printf("invalid 'primary_phy' parameter\n");
261 return rc;
262 }
263
264 params.secondary_phy = parse_arg_kv_dflt("secondary_phy",
265 cmd_ext_adv_phy_opts,
266 params.primary_phy, &rc);
267 if (rc != 0) {
268 console_printf("invalid 'secondary_phy' parameter\n");
269 return rc;
270 }
271
272 params.sid = parse_arg_uint8_dflt("sid", 0, &rc);
273 if (rc != 0) {
274 console_printf("invalid 'sid' parameter\n");
275 return rc;
276 }
277
278 rc = btshell_ext_adv_configure(instance, ¶ms, &selected_tx_power);
279 if (rc) {
280 console_printf("failed to configure advertising instance\n");
281 return rc;
282 }
283
284 console_printf("Instance %u configured (selected tx power: %d)\n",
285 instance, selected_tx_power);
286
287 adv_instances[instance] = true;
288
289 return 0;
290 }
291
292 static int
cmd_advertise_set_addr(int argc,char ** argv)293 cmd_advertise_set_addr(int argc, char **argv)
294 {
295 ble_addr_t addr;
296 uint8_t instance;
297 int rc;
298
299 rc = parse_arg_all(argc - 1, argv + 1);
300 if (rc != 0) {
301 return rc;
302 }
303
304 instance = parse_arg_uint8_dflt("instance", 0, &rc);
305 if (rc != 0 || instance >= BLE_ADV_INSTANCES) {
306 console_printf("invalid instance\n");
307 return rc;
308 }
309
310 if (!adv_instances[instance]) {
311 console_printf("instance not configured\n");
312 return rc;
313 }
314
315 rc = parse_arg_mac("addr", addr.val);
316 if (rc != 0) {
317 console_printf("invalid 'addr' parameter\n");
318 return rc;
319 }
320
321 addr.type = BLE_ADDR_RANDOM;
322
323 rc = ble_gap_ext_adv_set_addr(instance, &addr);
324 if (rc) {
325 console_printf("failed to start advertising instance\n");
326 return rc;
327 }
328
329 return 0;
330 }
331
332 static int
cmd_advertise_start(int argc,char ** argv)333 cmd_advertise_start(int argc, char **argv)
334 {
335 int max_events;
336 uint8_t instance;
337 int duration;
338 bool restart;
339 int rc;
340
341 rc = parse_arg_all(argc - 1, argv + 1);
342 if (rc != 0) {
343 return rc;
344 }
345
346 instance = parse_arg_uint8_dflt("instance", 0, &rc);
347 if (rc != 0 || instance >= BLE_ADV_INSTANCES) {
348 console_printf("invalid instance\n");
349 return rc;
350 }
351
352 if (!adv_instances[instance]) {
353 console_printf("instance not configured\n");
354 return rc;
355 }
356
357 duration = parse_arg_uint16_dflt("duration", 0, &rc);
358 if (rc != 0) {
359 console_printf("invalid 'duration' parameter\n");
360 return rc;
361 }
362
363 max_events = parse_arg_uint8_dflt("max_events", 0, &rc);
364 if (rc != 0) {
365 console_printf("invalid 'max_events' parameter\n");
366 return rc;
367 }
368
369 restart = parse_arg_bool_dflt("restart", 0, &rc);
370 if (rc != 0) {
371 console_printf("invalid 'restart' parameter\n");
372 return rc;
373 }
374
375 rc = btshell_ext_adv_start(instance, duration, max_events, restart);
376 if (rc) {
377 console_printf("failed to start advertising instance\n");
378 return rc;
379 }
380
381 return 0;
382 }
383
384 static int
cmd_advertise_stop(int argc,char ** argv)385 cmd_advertise_stop(int argc, char **argv)
386 {
387 uint8_t instance;
388 int rc;
389
390 rc = parse_arg_all(argc - 1, argv + 1);
391 if (rc != 0) {
392 return rc;
393 }
394
395 instance = parse_arg_uint8_dflt("instance", 0, &rc);
396 if (rc != 0 || instance >= BLE_ADV_INSTANCES) {
397 console_printf("invalid instance\n");
398 return rc;
399 }
400
401 if (!adv_instances[instance]) {
402 console_printf("instance not configured\n");
403 return rc;
404 }
405
406 rc = btshell_ext_adv_stop(instance);
407 if (rc) {
408 console_printf("failed to stop advertising instance\n");
409 return rc;
410 }
411
412 return 0;
413 }
414
415 static int
cmd_advertise_remove(int argc,char ** argv)416 cmd_advertise_remove(int argc, char **argv)
417 {
418 uint8_t instance;
419 int rc;
420
421 rc = parse_arg_all(argc - 1, argv + 1);
422 if (rc != 0) {
423 return rc;
424 }
425
426 instance = parse_arg_uint8_dflt("instance", 0, &rc);
427 if (rc != 0 || instance >= BLE_ADV_INSTANCES) {
428 console_printf("invalid instance\n");
429 return rc;
430 }
431
432 if (!adv_instances[instance]) {
433 console_printf("instance not configured\n");
434 return rc;
435 }
436
437 rc = ble_gap_ext_adv_remove(instance);
438 if (rc) {
439 console_printf("failed to remove advertising instance\n");
440 return rc;
441 }
442
443 adv_instances[instance] = false;
444
445 return 0;
446 }
447
448 #if MYNEWT_VAL(SHELL_CMD_HELP)
449 static const struct shell_param advertise_configure_params[] = {
450 {"instance", "default: 0"},
451 {"connectable", "connectable advertising, usage: =[0-1], default: 0"},
452 {"scannable", "scannable advertising, usage: =[0-1], default: 0"},
453 {"directed", "directed advertising, usage: =[0-1], default: 0"},
454 {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"},
455 {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"},
456 {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"},
457 {"channel_map", "usage: =[0x00-0xff], default: 0"},
458 {"filter", "usage: =[none|scan|conn|both], default: none"},
459 {"interval_min", "usage: =[0-UINT32_MAX], default: 0"},
460 {"interval_max", "usage: =[0-UINT32_MAX], default: 0"},
461 {"tx_power", "usage: =[-127-127], default: 127"},
462 {"primary_phy", "usage: =[1M|coded], default: 1M"},
463 {"secondary_phy", "usage: =[1M|2M|coded], default: primary_phy"},
464 {"sid", "usage: =[0-UINT8_MAX], default: 0"},
465 {"high_duty", "usage: =[0-1], default: 0"},
466 {"anonymous", "enable anonymous advertising, usage: =[0-1], default: 0"},
467 {"legacy", "use legacy PDUs, usage: =[0-1], default: 0"},
468 {"include_tx_power", "include TX power in PDU, usage: =[0-1], default: 0"},
469 {"scan_req_notif", "enable Scan Request notification usage: =[0-1], default: 0"},
470 {NULL, NULL}
471 };
472
473 static const struct shell_cmd_help advertise_configure_help = {
474 .summary = "configure new advertising instance",
475 .usage = NULL,
476 .params = advertise_configure_params,
477 };
478
479 static const struct shell_param advertise_set_addr_params[] = {
480 {"instance", "default: 0"},
481 {"addr", "usage: =[XX:XX:XX:XX:XX:XX]"},
482 {NULL, NULL}
483 };
484
485 static const struct shell_cmd_help advertise_set_addr_help = {
486 .summary = "set advertising instance random address",
487 .usage = NULL,
488 .params = advertise_set_addr_params,
489 };
490
491 static const struct shell_param advertise_start_params[] = {
492 {"instance", "default: 0"},
493 {"duration", "advertising duration in 10ms units, default: 0 (forever)"},
494 {"max_events", "max number of advertising events, default: 0 (no limit)"},
495 {"restart", "restart advertising after disconnect, usage: =[0-1], default: 0"},
496 {NULL, NULL}
497 };
498
499 static const struct shell_cmd_help advertise_start_help = {
500 .summary = "start advertising instance",
501 .usage = NULL,
502 .params = advertise_start_params,
503 };
504
505 static const struct shell_param advertise_stop_params[] = {
506 {"instance", "default: 0"},
507 {NULL, NULL}
508 };
509
510 static const struct shell_cmd_help advertise_stop_help = {
511 .summary = "stop advertising instance",
512 .usage = NULL,
513 .params = advertise_stop_params,
514 };
515
516 static const struct shell_param advertise_remove_params[] = {
517 {"instance", "default: 0"},
518 {NULL, NULL}
519 };
520
521 static const struct shell_cmd_help advertise_remove_help = {
522 .summary = "remove advertising instance",
523 .usage = NULL,
524 .params = advertise_remove_params,
525 };
526 #endif
527
528 #else
529 static const struct kv_pair cmd_adv_conn_modes[] = {
530 { "non", BLE_GAP_CONN_MODE_NON },
531 { "und", BLE_GAP_CONN_MODE_UND },
532 { "dir", BLE_GAP_CONN_MODE_DIR },
533 { NULL }
534 };
535
536 static const struct kv_pair cmd_adv_disc_modes[] = {
537 { "non", BLE_GAP_DISC_MODE_NON },
538 { "ltd", BLE_GAP_DISC_MODE_LTD },
539 { "gen", BLE_GAP_DISC_MODE_GEN },
540 { NULL }
541 };
542
543 static int
cmd_advertise(int argc,char ** argv)544 cmd_advertise(int argc, char **argv)
545 {
546 struct ble_gap_adv_params params;
547 int32_t duration_ms;
548 ble_addr_t peer_addr;
549 ble_addr_t *peer_addr_param = &peer_addr;
550 uint8_t own_addr_type;
551 bool restart;
552 int rc;
553
554 rc = parse_arg_all(argc - 1, argv + 1);
555 if (rc != 0) {
556 return rc;
557 }
558
559 if (argc > 1 && strcmp(argv[1], "stop") == 0) {
560 rc = btshell_adv_stop();
561 if (rc != 0) {
562 console_printf("advertise stop fail: %d\n", rc);
563 return rc;
564 }
565
566 return 0;
567 }
568
569 params.conn_mode = parse_arg_kv_dflt("conn", cmd_adv_conn_modes,
570 BLE_GAP_CONN_MODE_UND, &rc);
571 if (rc != 0) {
572 console_printf("invalid 'conn' parameter\n");
573 return rc;
574 }
575
576 params.disc_mode = parse_arg_kv_dflt("discov", cmd_adv_disc_modes,
577 BLE_GAP_DISC_MODE_GEN, &rc);
578 if (rc != 0) {
579 console_printf("invalid 'discov' parameter\n");
580 return rc;
581 }
582
583 peer_addr.type = parse_arg_kv_dflt("peer_addr_type", cmd_peer_addr_types,
584 BLE_ADDR_PUBLIC, &rc);
585 if (rc != 0) {
586 console_printf("invalid 'peer_addr_type' parameter\n");
587 return rc;
588 }
589
590 rc = parse_arg_mac("peer_addr", peer_addr.val);
591 if (rc == ENOENT) {
592 peer_addr_param = NULL;
593 } else if (rc != 0) {
594 console_printf("invalid 'peer_addr' parameter\n");
595 return rc;
596 }
597
598 restart = parse_arg_bool_dflt("restart", 0, &rc);
599 if (rc != 0) {
600 console_printf("invalid 'restart' parameter\n");
601 return rc;
602 }
603
604 own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types,
605 BLE_OWN_ADDR_PUBLIC, &rc);
606 if (rc != 0) {
607 console_printf("invalid 'own_addr_type' parameter\n");
608 return rc;
609 }
610
611 params.channel_map = parse_arg_uint8_dflt("channel_map", 0, &rc);
612 if (rc != 0) {
613 console_printf("invalid 'channel_map' parameter\n");
614 return rc;
615 }
616
617 params.filter_policy = parse_arg_kv_dflt("filter", cmd_adv_filt_types,
618 BLE_HCI_ADV_FILT_NONE, &rc);
619 if (rc != 0) {
620 console_printf("invalid 'filter' parameter\n");
621 return rc;
622 }
623
624 params.itvl_min = parse_arg_uint16_dflt("interval_min", 0, &rc);
625 if (rc != 0) {
626 console_printf("invalid 'interval_min' parameter\n");
627 return rc;
628 }
629
630 params.itvl_max = parse_arg_uint16_dflt("interval_max", 0, &rc);
631 if (rc != 0) {
632 console_printf("invalid 'interval_max' parameter\n");
633 return rc;
634 }
635
636 params.high_duty_cycle = parse_arg_bool_dflt("high_duty", 0, &rc);
637 if (rc != 0) {
638 console_printf("invalid 'high_duty' parameter\n");
639 return rc;
640 }
641
642 duration_ms = parse_arg_long_bounds_dflt("duration", 1, INT32_MAX,
643 BLE_HS_FOREVER, &rc);
644 if (rc != 0) {
645 console_printf("invalid 'duration' parameter\n");
646 return rc;
647 }
648
649 rc = btshell_adv_start(own_addr_type, peer_addr_param, duration_ms,
650 ¶ms, restart);
651 if (rc != 0) {
652 console_printf("advertise fail: %d\n", rc);
653 return rc;
654 }
655
656 return 0;
657 }
658
659 #if MYNEWT_VAL(SHELL_CMD_HELP)
660 static const struct shell_param advertise_params[] = {
661 {"stop", "stop advertising procedure"},
662 {"conn", "connectable mode, usage: =[non|und|dir], default: und"},
663 {"discov", "discoverable mode, usage: =[non|ltd|gen], default: gen"},
664 {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"},
665 {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"},
666 {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"},
667 {"channel_map", "usage: =[0x00-0xff], default: 0"},
668 {"filter", "usage: =[none|scan|conn|both], default: none"},
669 {"interval_min", "usage: =[0-UINT16_MAX], default: 0"},
670 {"interval_max", "usage: =[0-UINT16_MAX], default: 0"},
671 {"high_duty", "usage: =[0-1], default: 0"},
672 {"duration", "usage: =[1-INT32_MAX], default: INT32_MAX"},
673 {"restart", "restart advertising after disconnect, usage: =[0-1], default: 0"},
674 {NULL, NULL}
675 };
676
677 static const struct shell_cmd_help advertise_help = {
678 .summary = "start/stop advertising with specific parameters",
679 .usage = NULL,
680 .params = advertise_params,
681 };
682 #endif
683 #endif
684
685 /*****************************************************************************
686 * $connect *
687 *****************************************************************************/
688
689 static struct kv_pair cmd_ext_conn_phy_opts[] = {
690 { "none", 0x00 },
691 { "1M", 0x01 },
692 { "coded", 0x02 },
693 { "both", 0x03 },
694 { "all", 0x04 },
695 { NULL }
696 };
697
698 static int
cmd_connect(int argc,char ** argv)699 cmd_connect(int argc, char **argv)
700 {
701 struct ble_gap_conn_params phy_1M_params = {0};
702 struct ble_gap_conn_params phy_coded_params = {0};
703 struct ble_gap_conn_params phy_2M_params = {0};
704 uint8_t ext;
705 int32_t duration_ms;
706 ble_addr_t peer_addr;
707 ble_addr_t *peer_addr_param = &peer_addr;
708 int own_addr_type;
709 int rc;
710
711 rc = parse_arg_all(argc - 1, argv + 1);
712 if (rc != 0) {
713 return rc;
714 }
715
716 if (argc > 1 && strcmp(argv[1], "cancel") == 0) {
717 rc = btshell_conn_cancel();
718 if (rc != 0) {
719 console_printf("connection cancel fail: %d\n", rc);
720 return rc;
721 }
722
723 return 0;
724 }
725
726 ext = parse_arg_kv_dflt("extended", cmd_ext_conn_phy_opts, 0, &rc);
727 if (rc != 0) {
728 console_printf("invalid 'extended' parameter\n");
729 return rc;
730 }
731
732 peer_addr.type = parse_arg_kv_dflt("peer_addr_type", cmd_peer_addr_types,
733 BLE_ADDR_PUBLIC, &rc);
734 if (rc != 0) {
735 console_printf("invalid 'peer_addr_type' parameter\n");
736 return rc;
737 }
738
739 rc = parse_arg_mac("peer_addr", peer_addr.val);
740 if (rc == ENOENT) {
741 /* Allow "addr" for backwards compatibility. */
742 rc = parse_arg_mac("addr", peer_addr.val);
743 }
744
745 if (rc == ENOENT) {
746 /* With no "peer_addr" specified we'll use white list */
747 peer_addr_param = NULL;
748 } else if (rc != 0) {
749 console_printf("invalid 'peer_addr' parameter\n");
750 return rc;
751 }
752
753 own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types,
754 BLE_OWN_ADDR_PUBLIC, &rc);
755 if (rc != 0) {
756 console_printf("invalid 'own_addr_type' parameter\n");
757 return rc;
758 }
759
760 duration_ms = parse_arg_long_bounds_dflt("duration", 1, INT32_MAX, 0, &rc);
761 if (rc != 0) {
762 console_printf("invalid 'duration' parameter\n");
763 return rc;
764 }
765
766 phy_1M_params.scan_itvl = parse_arg_uint16_dflt("scan_interval", 0x0010, &rc);
767 if (rc != 0) {
768 console_printf("invalid 'scan_interval' parameter\n");
769 return rc;
770 }
771
772 phy_1M_params.scan_window = parse_arg_uint16_dflt("scan_window", 0x0010, &rc);
773 if (rc != 0) {
774 console_printf("invalid 'scan_window' parameter\n");
775 return rc;
776 }
777
778 phy_1M_params.itvl_min = parse_arg_uint16_dflt("interval_min",
779 BLE_GAP_INITIAL_CONN_ITVL_MIN,
780 &rc);
781 if (rc != 0) {
782 console_printf("invalid 'interval_min' parameter\n");
783 return rc;
784 }
785
786 phy_1M_params.itvl_max = parse_arg_uint16_dflt("interval_max",
787 BLE_GAP_INITIAL_CONN_ITVL_MAX,
788 &rc);
789 if (rc != 0) {
790 console_printf("invalid 'interval_max' parameter\n");
791 return rc;
792 }
793
794 phy_1M_params.latency = parse_arg_uint16_dflt("latency", 0, &rc);
795 if (rc != 0) {
796 console_printf("invalid 'latency' parameter\n");
797 return rc;
798 }
799
800 phy_1M_params.supervision_timeout = parse_arg_uint16_dflt("timeout", 0x0100, &rc);
801 if (rc != 0) {
802 console_printf("invalid 'timeout' parameter\n");
803 return rc;
804 }
805
806 phy_1M_params.min_ce_len = parse_arg_uint16_dflt("min_conn_event_len",
807 0x0010, &rc);
808 if (rc != 0) {
809 console_printf("invalid 'min_conn_event_len' parameter\n");
810 return rc;
811 }
812
813 phy_1M_params.max_ce_len = parse_arg_uint16_dflt("max_conn_event_len",
814 0x0300, &rc);
815 if (rc != 0) {
816 console_printf("invalid 'max_conn_event_len' parameter\n");
817 return rc;
818 }
819
820 if (ext == 0x00) {
821 rc = btshell_conn_initiate(own_addr_type, peer_addr_param, duration_ms,
822 &phy_1M_params);
823 console_printf("error connecting; rc=%d\n", rc);
824 return rc;
825 }
826
827 if (ext == 0x01) {
828 rc = btshell_ext_conn_initiate(own_addr_type, peer_addr_param,
829 duration_ms, &phy_1M_params,
830 NULL, NULL);
831 console_printf("error connecting; rc=%d\n", rc);
832 return rc;
833 }
834
835 /* Get coded params */
836 phy_coded_params.scan_itvl = parse_arg_uint16_dflt("coded_scan_interval",
837 0x0010, &rc);
838 if (rc != 0) {
839 console_printf("invalid 'coded_scan_interval' parameter\n");
840 return rc;
841 }
842
843 phy_coded_params.scan_window = parse_arg_uint16_dflt("coded_scan_window",
844 0x0010, &rc);
845 if (rc != 0) {
846 console_printf("invalid 'coded_scan_window' parameter\n");
847 return rc;
848 }
849
850 phy_coded_params.itvl_min = parse_arg_uint16_dflt("coded_interval_min",
851 BLE_GAP_INITIAL_CONN_ITVL_MIN,
852 &rc);
853 if (rc != 0) {
854 console_printf("invalid 'coded_interval_min' parameter\n");
855 return rc;
856 }
857
858 phy_coded_params.itvl_max = parse_arg_uint16_dflt("coded_interval_max",
859 BLE_GAP_INITIAL_CONN_ITVL_MAX,
860 &rc);
861 if (rc != 0) {
862 console_printf("invalid 'coded_interval_max' parameter\n");
863 return rc;
864 }
865
866 phy_coded_params.latency =
867 parse_arg_uint16_dflt("coded_latency", 0, &rc);
868 if (rc != 0) {
869 console_printf("invalid 'coded_latency' parameter\n");
870 return rc;
871 }
872
873 phy_coded_params.supervision_timeout =
874 parse_arg_uint16_dflt("coded_timeout", 0x0100, &rc);
875
876 if (rc != 0) {
877 console_printf("invalid 'coded_timeout' parameter\n");
878 return rc;
879 }
880
881 phy_coded_params.min_ce_len =
882 parse_arg_uint16_dflt("coded_min_conn_event", 0x0010, &rc);
883 if (rc != 0) {
884 console_printf("invalid 'coded_min_conn_event' parameter\n");
885 return rc;
886 }
887
888 phy_coded_params.max_ce_len = parse_arg_uint16_dflt("coded_max_conn_event",
889 0x0300, &rc);
890 if (rc != 0) {
891 console_printf("invalid 'coded_max_conn_event' parameter\n");
892 return rc;
893 }
894
895 /* Get 2M params */
896 phy_2M_params.itvl_min = parse_arg_uint16_dflt("2M_interval_min",
897 BLE_GAP_INITIAL_CONN_ITVL_MIN,
898 &rc);
899 if (rc != 0) {
900 console_printf("invalid '2M_interval_min' parameter\n");
901 return rc;
902 }
903
904 phy_2M_params.itvl_max = parse_arg_uint16_dflt("2M_interval_max",
905 BLE_GAP_INITIAL_CONN_ITVL_MAX, &rc);
906 if (rc != 0) {
907 console_printf("invalid '2M_interval_max' parameter\n");
908 return rc;
909 }
910
911 phy_2M_params.latency =
912 parse_arg_uint16_dflt("2M_latency", 0, &rc);
913 if (rc != 0) {
914 console_printf("invalid '2M_latency' parameter\n");
915 return rc;
916 }
917
918 phy_2M_params.supervision_timeout = parse_arg_uint16_dflt("2M_timeout",
919 0x0100, &rc);
920
921 if (rc != 0) {
922 console_printf("invalid '2M_timeout' parameter\n");
923 return rc;
924 }
925
926 phy_2M_params.min_ce_len = parse_arg_uint16_dflt("2M_min_conn_event", 0x0010,
927 &rc);
928 if (rc != 0) {
929 console_printf("invalid '2M_min_conn_event' parameter\n");
930 return rc;
931 }
932
933 phy_2M_params.max_ce_len = parse_arg_uint16_dflt("2M_max_conn_event",
934 0x0300, &rc);
935 if (rc != 0) {
936 console_printf("invalid '2M_max_conn_event' parameter\n");
937 return rc;
938 }
939
940 if (ext == 0x02) {
941 rc = btshell_ext_conn_initiate(own_addr_type, peer_addr_param,
942 duration_ms, NULL, NULL, &phy_coded_params);
943 return rc;
944 }
945
946 if (ext == 0x03) {
947 rc = btshell_ext_conn_initiate(own_addr_type, peer_addr_param,
948 duration_ms, &phy_1M_params, NULL,
949 &phy_coded_params);
950 return rc;
951 }
952
953 rc = btshell_ext_conn_initiate(own_addr_type, peer_addr_param,
954 duration_ms, &phy_1M_params,
955 &phy_2M_params,
956 &phy_coded_params);
957 return rc;
958 }
959
960 #if MYNEWT_VAL(SHELL_CMD_HELP)
961 static const struct shell_param connect_params[] = {
962 {"cancel", "cancel connection procedure"},
963 {"extended", "usage: =[none|1M|coded|both|all], default: none"},
964 {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"},
965 {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"},
966 {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"},
967 {"duration", "usage: =[1-INT32_MAX], default: 0"},
968 {"scan_interval", "usage: =[0-UINT16_MAX], default: 0x0010"},
969 {"scan_window", "usage: =[0-UINT16_MAX], default: 0x0010"},
970 {"interval_min", "usage: =[0-UINT16_MAX], default: 30"},
971 {"interval_max", "usage: =[0-UINT16_MAX], default: 50"},
972 {"latency", "usage: =[UINT16], default: 0"},
973 {"timeout", "usage: =[UINT16], default: 0x0100"},
974 {"min_conn_event_len", "usage: =[UINT16], default: 0x0010"},
975 {"max_conn_event_len", "usage: =[UINT16], default: 0x0300"},
976 {"coded_scan_interval", "usage: =[0-UINT16_MAX], default: 0x0010"},
977 {"coded_scan_window", "usage: =[0-UINT16_MAX], default: 0x0010"},
978 {"coded_interval_min", "usage: =[0-UINT16_MAX], default: 30"},
979 {"coded_interval_max", "usage: =[0-UINT16_MAX], default: 50"},
980 {"coded_latency", "usage: =[UINT16], default: 0"},
981 {"coded_timeout", "usage: =[UINT16], default: 0x0100"},
982 {"coded_min_conn_event_len", "usage: =[UINT16], default: 0x0010"},
983 {"coded_max_conn_event_len", "usage: =[UINT16], default: 0x0300"},
984 {"2M_interval_min", "usage: =[0-UINT16_MAX], default: 30"},
985 {"2M_interval_max", "usage: =[0-UINT16_MAX], default: 50"},
986 {"2M_latency", "usage: =[UINT16], default: 0"},
987 {"2M_timeout", "usage: =[UINT16], default: 0x0100"},
988 {"2M_min_conn_event_len", "usage: =[UINT16], default: 0x0010"},
989 {"2M_max_conn_event_len", "usage: =[UINT16], default: 0x0300"},
990 {NULL, NULL}
991 };
992
993 static const struct shell_cmd_help connect_help = {
994 .summary = "start/stop connection procedure with specific parameters",
995 .usage = NULL,
996 .params = connect_params,
997 };
998 #endif
999
1000 /*****************************************************************************
1001 * $disconnect *
1002 *****************************************************************************/
1003
1004 static int
cmd_disconnect(int argc,char ** argv)1005 cmd_disconnect(int argc, char **argv)
1006 {
1007 uint16_t conn_handle;
1008 uint8_t reason;
1009 int rc;
1010
1011 rc = parse_arg_all(argc - 1, argv + 1);
1012 if (rc != 0) {
1013 return rc;
1014 }
1015
1016 conn_handle = parse_arg_uint16("conn", &rc);
1017 if (rc != 0) {
1018 console_printf("invalid 'conn' parameter\n");
1019 return rc;
1020 }
1021
1022 reason = parse_arg_uint8_dflt("reason", BLE_ERR_REM_USER_CONN_TERM, &rc);
1023 if (rc != 0) {
1024 console_printf("invalid 'reason' parameter\n");
1025 return rc;
1026 }
1027
1028 rc = btshell_term_conn(conn_handle, reason);
1029 if (rc != 0) {
1030 console_printf("error terminating connection; rc=%d\n", rc);
1031 return rc;
1032 }
1033
1034 return 0;
1035 }
1036
1037 static int
cmd_show_conn(int argc,char ** argv)1038 cmd_show_conn(int argc, char **argv)
1039 {
1040 struct ble_gap_conn_desc conn_desc;
1041 struct btshell_conn *conn;
1042 int rc;
1043 int i;
1044
1045 for (i = 0; i < btshell_num_conns; i++) {
1046 conn = btshell_conns + i;
1047
1048 rc = ble_gap_conn_find(conn->handle, &conn_desc);
1049 if (rc == 0) {
1050 print_conn_desc(&conn_desc);
1051 }
1052 }
1053
1054 return 0;
1055 }
1056
1057 static int
cmd_show_addr(int argc,char ** argv)1058 cmd_show_addr(int argc, char **argv)
1059 {
1060 uint8_t id_addr[6];
1061 int rc;
1062
1063 console_printf("public_id_addr=");
1064 rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, id_addr, NULL);
1065 if (rc == 0) {
1066 print_addr(id_addr);
1067 } else {
1068 console_printf("none");
1069 }
1070
1071 console_printf(" random_id_addr=");
1072 rc = ble_hs_id_copy_addr(BLE_ADDR_RANDOM, id_addr, NULL);
1073 if (rc == 0) {
1074 print_addr(id_addr);
1075 } else {
1076 console_printf("none");
1077 }
1078 console_printf("\n");
1079
1080 return 0;
1081 }
1082
1083 #if MYNEWT_VAL(SHELL_CMD_HELP)
1084 static const struct shell_param disconnect_params[] = {
1085 {"conn", "connection handle parameter, usage: =<UINT16>"},
1086 {"reason", "disconnection reason, usage: =[UINT8], default: 19 (remote user terminated connection)"},
1087 {NULL, NULL}
1088 };
1089
1090 static const struct shell_cmd_help disconnect_help = {
1091 .summary = "disconnect command",
1092 .usage = NULL,
1093 .params = disconnect_params,
1094 };
1095 #endif
1096
1097 /*****************************************************************************
1098 * $set-scan-opts *
1099 *****************************************************************************/
1100
1101 static struct btshell_scan_opts g_scan_opts = {
1102 .limit = UINT16_MAX,
1103 .ignore_legacy = 0,
1104 };
1105
1106 static int
cmd_set_scan_opts(int argc,char ** argv)1107 cmd_set_scan_opts(int argc, char **argv)
1108 {
1109 int rc;
1110
1111 rc = parse_arg_all(argc - 1, argv + 1);
1112 if (rc != 0) {
1113 return rc;
1114 }
1115
1116 g_scan_opts.limit = parse_arg_uint16_dflt("decode_limit", UINT16_MAX, &rc);
1117 if (rc != 0) {
1118 console_printf("invalid 'decode_limit' parameter\n");
1119 return rc;
1120 }
1121
1122 g_scan_opts.ignore_legacy = parse_arg_bool_dflt("ignore_legacy", 0, &rc);
1123 if (rc != 0) {
1124 console_printf("invalid 'ignore_legacy' parameter\n");
1125 return rc;
1126 }
1127
1128 return rc;
1129 }
1130
1131 #if MYNEWT_VAL(SHELL_CMD_HELP)
1132 static const struct shell_param set_scan_opts_params[] = {
1133 {"decode_limit", "usage: =[0-UINT16_MAX], default: UINT16_MAX"},
1134 {"ignore_legacy", "usage: =[0-1], default: 0"},
1135 {NULL, NULL}
1136 };
1137
1138 static const struct shell_cmd_help set_scan_opts_help = {
1139 .summary = "set scan options",
1140 .usage = NULL,
1141 .params = set_scan_opts_params,
1142 };
1143 #endif
1144
1145 /*****************************************************************************
1146 * $scan *
1147 *****************************************************************************/
1148
1149 static const struct kv_pair cmd_scan_filt_policies[] = {
1150 { "no_wl", BLE_HCI_SCAN_FILT_NO_WL },
1151 { "use_wl", BLE_HCI_SCAN_FILT_USE_WL },
1152 { "no_wl_inita", BLE_HCI_SCAN_FILT_NO_WL_INITA },
1153 { "use_wl_inita", BLE_HCI_SCAN_FILT_USE_WL_INITA },
1154 { NULL }
1155 };
1156
1157 static struct kv_pair cmd_scan_ext_types[] = {
1158 { "none", 0x00 },
1159 { "1M", 0x01 },
1160 { "coded", 0x02 },
1161 { "both", 0x03 },
1162 { NULL }
1163 };
1164
1165 static struct btshell_scan_opts g_scan_opts;
1166
1167 static int
cmd_scan(int argc,char ** argv)1168 cmd_scan(int argc, char **argv)
1169 {
1170 struct ble_gap_disc_params params = {0};
1171 struct ble_gap_ext_disc_params uncoded = {0};
1172 struct ble_gap_ext_disc_params coded = {0};
1173 uint8_t extended;
1174 int32_t duration_ms;
1175 uint8_t own_addr_type;
1176 uint16_t duration;
1177 uint16_t period;
1178 int rc;
1179
1180 rc = parse_arg_all(argc - 1, argv + 1);
1181 if (rc != 0) {
1182 return rc;
1183 }
1184
1185 if (argc > 1 && strcmp(argv[1], "cancel") == 0) {
1186 rc = btshell_scan_cancel();
1187 if (rc != 0) {
1188 console_printf("scan cancel fail: %d\n", rc);
1189 return rc;
1190 }
1191 return 0;
1192 }
1193
1194 extended = parse_arg_kv_dflt("extended", cmd_scan_ext_types, 0, &rc);
1195 if (rc != 0) {
1196 console_printf("invalid 'extended' parameter\n");
1197 return rc;
1198 }
1199
1200 duration_ms = parse_arg_long_bounds_dflt("duration", 1, INT32_MAX,
1201 BLE_HS_FOREVER, &rc);
1202 if (rc != 0) {
1203 console_printf("invalid 'duration' parameter\n");
1204 return rc;
1205 }
1206
1207 params.limited = parse_arg_bool_dflt("limited", 0, &rc);
1208 if (rc != 0) {
1209 console_printf("invalid 'limited' parameter\n");
1210 return rc;
1211 }
1212
1213 params.passive = parse_arg_bool_dflt("passive", 0, &rc);
1214 if (rc != 0) {
1215 console_printf("invalid 'passive' parameter\n");
1216 return rc;
1217 }
1218
1219 params.itvl = parse_arg_uint16_dflt("interval", 0, &rc);
1220 if (rc != 0) {
1221 console_printf("invalid 'interval' parameter\n");
1222 return rc;
1223 }
1224
1225 params.window = parse_arg_uint16_dflt("window", 0, &rc);
1226 if (rc != 0) {
1227 console_printf("invalid 'window' parameter\n");
1228 return rc;
1229 }
1230
1231 params.filter_policy = parse_arg_kv_dflt("filter", cmd_scan_filt_policies,
1232 BLE_HCI_SCAN_FILT_NO_WL, &rc);
1233 if (rc != 0) {
1234 console_printf("invalid 'filter' parameter\n");
1235 return rc;
1236 }
1237
1238 params.filter_duplicates = parse_arg_bool_dflt("nodups", 0, &rc);
1239 if (rc != 0) {
1240 console_printf("invalid 'nodups' parameter\n");
1241 return rc;
1242 }
1243
1244 own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types,
1245 BLE_OWN_ADDR_PUBLIC, &rc);
1246 if (rc != 0) {
1247 console_printf("invalid 'own_addr_type' parameter\n");
1248 return rc;
1249 }
1250
1251 if (extended == 0) {
1252 rc = btshell_scan(own_addr_type, duration_ms, ¶ms, &g_scan_opts);
1253 if (rc != 0) {
1254 console_printf("error scanning; rc=%d\n", rc);
1255 return rc;
1256 }
1257
1258 return 0;
1259 }
1260
1261 /* Copy above parameters to uncoded params */
1262 uncoded.passive = params.passive;
1263 uncoded.itvl = params.itvl;
1264 uncoded.window = params.window;
1265
1266 duration = parse_arg_uint16_dflt("extended_duration", 0, &rc);
1267 if (rc != 0) {
1268 console_printf("invalid 'extended_duration' parameter\n");
1269 return rc;
1270 }
1271
1272 period = parse_arg_uint16_dflt("extended_period", 0, &rc);
1273 if (rc != 0) {
1274 console_printf("invalid 'extended_period' parameter\n");
1275 return rc;
1276 }
1277
1278 coded.itvl = parse_arg_uint16_dflt("longrange_interval", 0, &rc);
1279 if (rc != 0) {
1280 console_printf("invalid 'longrange_interval' parameter\n");
1281 return rc;
1282 }
1283
1284 coded.window = parse_arg_uint16_dflt("longrange_window", 0, &rc);
1285 if (rc != 0) {
1286 console_printf("invalid 'longrange_window' parameter\n");
1287 return rc;
1288 }
1289
1290 coded.passive = parse_arg_uint16_dflt("longrange_passive", 0, &rc);
1291 if (rc != 0) {
1292 console_printf("invalid 'longrange_passive' parameter\n");
1293 return rc;
1294 }
1295
1296 switch (extended) {
1297 case 0x01:
1298 rc = btshell_ext_scan(own_addr_type, duration, period,
1299 params.filter_duplicates, params.filter_policy,
1300 params.limited, &uncoded, NULL,
1301 &g_scan_opts);
1302 break;
1303 case 0x02:
1304 rc = btshell_ext_scan(own_addr_type, duration, period,
1305 params.filter_duplicates, params.filter_policy,
1306 params.limited, NULL, &coded,
1307 &g_scan_opts);
1308 break;
1309 case 0x03:
1310 rc = btshell_ext_scan(own_addr_type, duration, period,
1311 params.filter_duplicates, params.filter_policy,
1312 params.limited, &uncoded, &coded,
1313 &g_scan_opts);
1314 break;
1315 default:
1316 rc = -1;
1317 console_printf("invalid 'extended' parameter\n");
1318 break;
1319 }
1320
1321 return rc;
1322 }
1323
1324 #if MYNEWT_VAL(SHELL_CMD_HELP)
1325 static const struct shell_param scan_params[] = {
1326 {"cancel", "cancel scan procedure"},
1327 {"extended", "usage: =[none|1M|coded|both], default: none"},
1328 {"duration", "usage: =[1-INT32_MAX], default: INT32_MAX"},
1329 {"limited", "usage: =[0-1], default: 0"},
1330 {"passive", "usage: =[0-1], default: 0"},
1331 {"interval", "usage: =[0-UINT16_MAX], default: 0"},
1332 {"window", "usage: =[0-UINT16_MAX], default: 0"},
1333 {"filter", "usage: =[no_wl|use_wl|no_wl_inita|use_wl_inita], default: no_wl"},
1334 {"nodups", "usage: =[0-1], default: 0"},
1335 {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"},
1336 {"extended_duration", "usage: =[0-UINT16_MAX], default: 0"},
1337 {"extended_period", "usage: =[0-UINT16_MAX], default: 0"},
1338 {"longrange_interval", "usage: =[0-UINT16_MAX], default: 0"},
1339 {"longrange_window", "usage: =[0-UINT16_MAX], default: 0"},
1340 {"longrange_passive", "usage: =[0-1], default: 0"},
1341 {NULL, NULL}
1342 };
1343
1344 static const struct shell_cmd_help scan_help = {
1345 .summary = "start/stop scan procedure with specific parameters",
1346 .usage = NULL,
1347 .params = scan_params,
1348 };
1349 #endif
1350
1351 /*****************************************************************************
1352 * $set *
1353 *****************************************************************************/
1354
1355 static const struct kv_pair cmd_set_addr_types[] = {
1356 { "public", BLE_ADDR_PUBLIC },
1357 { "random", BLE_ADDR_RANDOM },
1358 { NULL }
1359 };
1360
1361 static int
cmd_set_addr(void)1362 cmd_set_addr(void)
1363 {
1364 uint8_t addr[6];
1365 int addr_type;
1366 int rc;
1367
1368 addr_type = parse_arg_kv_dflt("addr_type", cmd_set_addr_types,
1369 BLE_ADDR_PUBLIC, &rc);
1370 if (rc != 0) {
1371 console_printf("invalid 'addr_type' parameter\n");
1372 return rc;
1373 }
1374
1375 rc = parse_arg_mac("addr", addr);
1376 if (rc != 0) {
1377 console_printf("invalid 'addr' parameter\n");
1378 return rc;
1379 }
1380
1381 switch (addr_type) {
1382 #if MYNEWT_VAL(BLE_DEVICE)
1383 case BLE_ADDR_PUBLIC:
1384 /* We shouldn't be writing to the controller's address (g_dev_addr).
1385 * There is no standard way to set the local public address, so this is
1386 * our only option at the moment.
1387 */
1388 memcpy(g_dev_addr, addr, 6);
1389 ble_hs_id_set_pub(g_dev_addr);
1390 break;
1391 #endif
1392
1393 case BLE_ADDR_RANDOM:
1394 rc = ble_hs_id_set_rnd(addr);
1395 if (rc != 0) {
1396 return rc;
1397 }
1398 break;
1399
1400 default:
1401 return BLE_HS_EUNKNOWN;
1402 }
1403
1404 return 0;
1405 }
1406
1407 static int
cmd_set(int argc,char ** argv)1408 cmd_set(int argc, char **argv)
1409 {
1410 uint16_t mtu;
1411 uint8_t irk[16];
1412 int good = 0;
1413 int rc;
1414
1415 rc = parse_arg_all(argc - 1, argv + 1);
1416 if (rc != 0) {
1417 return rc;
1418 }
1419
1420 rc = parse_arg_find_idx("addr");
1421 if (rc != -1) {
1422 rc = cmd_set_addr();
1423 if (rc != 0) {
1424 return rc;
1425 }
1426 good = 1;
1427 }
1428
1429 mtu = parse_arg_uint16("mtu", &rc);
1430 if (rc == 0) {
1431 rc = ble_att_set_preferred_mtu(mtu);
1432 if (rc == 0) {
1433 good = 1;
1434 }
1435 } else if (rc != ENOENT) {
1436 console_printf("invalid 'mtu' parameter\n");
1437 return rc;
1438 }
1439
1440 rc = parse_arg_byte_stream_exact_length("irk", irk, 16);
1441 if (rc == 0) {
1442 good = 1;
1443 ble_hs_pvcy_set_our_irk(irk);
1444 } else if (rc != ENOENT) {
1445 console_printf("invalid 'irk' parameter\n");
1446 return rc;
1447 }
1448
1449 if (!good) {
1450 console_printf("Error: no valid settings specified\n");
1451 return -1;
1452 }
1453
1454 return 0;
1455 }
1456
1457 #if MYNEWT_VAL(SHELL_CMD_HELP)
1458 static const struct shell_param set_params[] = {
1459 {"addr", "set device address, usage: =[XX:XX:XX:XX:XX:XX]"},
1460 {"addr_type", "set device address type, usage: =[public|random], default: public"},
1461 {"mtu", "Maximum Transimssion Unit, usage: =[0-UINT16_MAX]"},
1462 {"irk", "Identity Resolving Key, usage: =[XX:XX...], len=16 octets"},
1463 {NULL, NULL}
1464 };
1465
1466 static const struct shell_cmd_help set_help = {
1467 .summary = "set device parameters",
1468 .usage = NULL,
1469 .params = set_params,
1470 };
1471 #endif
1472
1473 /*****************************************************************************
1474 * $set-adv-data *
1475 *****************************************************************************/
1476
1477 #define CMD_ADV_DATA_MAX_UUIDS16 8
1478 #define CMD_ADV_DATA_MAX_UUIDS32 8
1479 #define CMD_ADV_DATA_MAX_UUIDS128 2
1480 #define CMD_ADV_DATA_MAX_PUBLIC_TGT_ADDRS 8
1481 #define CMD_ADV_DATA_SVC_DATA_UUID16_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ
1482 #define CMD_ADV_DATA_SVC_DATA_UUID32_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ
1483 #define CMD_ADV_DATA_SVC_DATA_UUID128_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ
1484 #define CMD_ADV_DATA_URI_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ
1485 #define CMD_ADV_DATA_MFG_DATA_MAX_LEN BLE_HS_ADV_MAX_FIELD_SZ
1486
1487 #if MYNEWT_VAL(BLE_EXT_ADV)
1488 static void
update_pattern(uint8_t * buf,int counter)1489 update_pattern(uint8_t *buf, int counter)
1490 {
1491 int i;
1492
1493 for (i = 0; i < 10; i += 2) {
1494 counter += 2;
1495 buf[i] = (counter / 1000) << 4 | (counter / 100 % 10);
1496 buf[i + 1] = (counter / 10 % 10) << 4 | (counter % 10);
1497 }
1498 }
1499 #endif
1500
1501 static int
cmd_set_adv_data_or_scan_rsp(int argc,char ** argv,bool scan_rsp)1502 cmd_set_adv_data_or_scan_rsp(int argc, char **argv, bool scan_rsp)
1503 {
1504 static bssnz_t ble_uuid16_t uuids16[CMD_ADV_DATA_MAX_UUIDS16];
1505 static bssnz_t ble_uuid32_t uuids32[CMD_ADV_DATA_MAX_UUIDS32];
1506 static bssnz_t ble_uuid128_t uuids128[CMD_ADV_DATA_MAX_UUIDS128];
1507 static bssnz_t uint8_t
1508 public_tgt_addrs[CMD_ADV_DATA_MAX_PUBLIC_TGT_ADDRS]
1509 [BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN];
1510 static bssnz_t uint8_t slave_itvl_range[BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN];
1511 static bssnz_t uint8_t
1512 svc_data_uuid16[CMD_ADV_DATA_SVC_DATA_UUID16_MAX_LEN];
1513 static bssnz_t uint8_t
1514 svc_data_uuid32[CMD_ADV_DATA_SVC_DATA_UUID32_MAX_LEN];
1515 static bssnz_t uint8_t
1516 svc_data_uuid128[CMD_ADV_DATA_SVC_DATA_UUID128_MAX_LEN];
1517 static bssnz_t uint8_t uri[CMD_ADV_DATA_URI_MAX_LEN];
1518 static bssnz_t uint8_t mfg_data[CMD_ADV_DATA_MFG_DATA_MAX_LEN];
1519 struct ble_hs_adv_fields adv_fields;
1520 uint32_t uuid32;
1521 uint16_t uuid16;
1522 uint8_t uuid128[16];
1523 uint8_t public_tgt_addr[BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN];
1524 uint8_t eddystone_url_body_len;
1525 uint8_t eddystone_url_suffix;
1526 uint8_t eddystone_url_scheme;
1527 int8_t eddystone_measured_power = 0;
1528 char eddystone_url_body[BLE_EDDYSTONE_URL_MAX_LEN];
1529 char *eddystone_url_full;
1530 int svc_data_uuid16_len;
1531 int svc_data_uuid32_len;
1532 int svc_data_uuid128_len;
1533 int uri_len;
1534 int mfg_data_len;
1535 int tmp;
1536 int rc;
1537 #if MYNEWT_VAL(BLE_EXT_ADV)
1538 uint8_t instance;
1539 uint8_t extra_data[10];
1540 uint16_t counter;
1541 uint16_t extra_data_len;
1542 struct os_mbuf *adv_data;
1543 #endif
1544
1545 memset(&adv_fields, 0, sizeof adv_fields);
1546
1547 rc = parse_arg_all(argc - 1, argv + 1);
1548 if (rc != 0) {
1549 return rc;
1550 }
1551
1552 #if MYNEWT_VAL(BLE_EXT_ADV)
1553 instance = parse_arg_uint8_dflt("instance", 0, &rc);
1554 if (rc != 0 || instance >= BLE_ADV_INSTANCES) {
1555 console_printf("invalid instance\n");
1556 return rc;
1557 }
1558
1559 if (!adv_instances[instance]) {
1560 console_printf("instance not configured\n");
1561 return rc;
1562 }
1563 #endif
1564
1565 tmp = parse_arg_uint8("flags", &rc);
1566 if (rc == 0) {
1567 adv_fields.flags = tmp;
1568 } else if (rc != ENOENT) {
1569 console_printf("invalid 'flags' parameter\n");
1570 return rc;
1571 }
1572
1573 while (1) {
1574 uuid16 = parse_arg_uint16("uuid16", &rc);
1575 if (rc == 0) {
1576 if (adv_fields.num_uuids16 >= CMD_ADV_DATA_MAX_UUIDS16) {
1577 console_printf("invalid 'uuid16' parameter\n");
1578 return EINVAL;
1579 }
1580 uuids16[adv_fields.num_uuids16] = (ble_uuid16_t) BLE_UUID16_INIT(uuid16);
1581 adv_fields.num_uuids16++;
1582 } else if (rc == ENOENT) {
1583 break;
1584 } else {
1585 console_printf("invalid 'uuid16' parameter\n");
1586 return rc;
1587 }
1588 }
1589 if (adv_fields.num_uuids16 > 0) {
1590 adv_fields.uuids16 = uuids16;
1591 }
1592
1593 tmp = parse_arg_bool_dflt("uuids16_is_complete", 0, &rc);
1594 if (rc != 0) {
1595 console_printf("invalid 'uuids16_is_complete' parameter\n");
1596 return rc;
1597 }
1598
1599 while (1) {
1600 uuid32 = parse_arg_uint32("uuid32", &rc);
1601 if (rc == 0) {
1602 if (adv_fields.num_uuids32 >= CMD_ADV_DATA_MAX_UUIDS32) {
1603 console_printf("invalid 'uuid32' parameter\n");
1604 return EINVAL;
1605 }
1606 uuids32[adv_fields.num_uuids32] = (ble_uuid32_t) BLE_UUID32_INIT(uuid32);
1607 adv_fields.num_uuids32++;
1608 } else if (rc == ENOENT) {
1609 break;
1610 } else {
1611 console_printf("invalid 'uuid32' parameter\n");
1612 return rc;
1613 }
1614 }
1615 if (adv_fields.num_uuids32 > 0) {
1616 adv_fields.uuids32 = uuids32;
1617 }
1618
1619 tmp = parse_arg_bool_dflt("uuids32_is_complete", 0, &rc);
1620 if (rc != 0) {
1621 console_printf("invalid 'uuids32_is_complete' parameter\n");
1622 return rc;
1623 }
1624
1625 while (1) {
1626 rc = parse_arg_byte_stream_exact_length("uuid128", uuid128, 16);
1627 if (rc == 0) {
1628 if (adv_fields.num_uuids128 >= CMD_ADV_DATA_MAX_UUIDS128) {
1629 console_printf("invalid 'uuid128' parameter\n");
1630 return EINVAL;
1631 }
1632 ble_uuid_init_from_buf((ble_uuid_any_t *) &uuids128[adv_fields.num_uuids128],
1633 uuid128, 16);
1634 adv_fields.num_uuids128++;
1635 } else if (rc == ENOENT) {
1636 break;
1637 } else {
1638 console_printf("invalid 'uuid128' parameter\n");
1639 return rc;
1640 }
1641 }
1642 if (adv_fields.num_uuids128 > 0) {
1643 adv_fields.uuids128 = uuids128;
1644 }
1645
1646 tmp = parse_arg_bool_dflt("uuids128_is_complete", 0, &rc);
1647 if (rc != 0) {
1648 console_printf("invalid 'uuids128_is_complete' parameter\n");
1649 return rc;
1650 }
1651
1652 adv_fields.name = (uint8_t *)parse_arg_extract("name");
1653 if (adv_fields.name != NULL) {
1654 adv_fields.name_len = strlen((char *)adv_fields.name);
1655 }
1656
1657 tmp = parse_arg_long_bounds("tx_power_level", INT8_MIN, INT8_MAX, &rc);
1658 if (rc == 0) {
1659 adv_fields.tx_pwr_lvl = tmp;
1660 adv_fields.tx_pwr_lvl_is_present = 1;
1661 } else if (rc != ENOENT) {
1662 console_printf("invalid 'tx_power_level' parameter\n");
1663 return rc;
1664 }
1665
1666 rc = parse_arg_byte_stream_exact_length("slave_interval_range",
1667 slave_itvl_range,
1668 BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
1669 if (rc == 0) {
1670 adv_fields.slave_itvl_range = slave_itvl_range;
1671 } else if (rc != ENOENT) {
1672 console_printf("invalid 'slave_interval_range' parameter\n");
1673 return rc;
1674 }
1675
1676 rc = parse_arg_byte_stream("service_data_uuid16",
1677 CMD_ADV_DATA_SVC_DATA_UUID16_MAX_LEN,
1678 svc_data_uuid16, &svc_data_uuid16_len);
1679 if (rc == 0) {
1680 adv_fields.svc_data_uuid16 = svc_data_uuid16;
1681 adv_fields.svc_data_uuid16_len = svc_data_uuid16_len;
1682 } else if (rc != ENOENT) {
1683 console_printf("invalid 'service_data_uuid16' parameter\n");
1684 return rc;
1685 }
1686
1687 while (1) {
1688 rc = parse_arg_byte_stream_exact_length(
1689 "public_target_address", public_tgt_addr,
1690 BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN);
1691 if (rc == 0) {
1692 if (adv_fields.num_public_tgt_addrs >=
1693 CMD_ADV_DATA_MAX_PUBLIC_TGT_ADDRS) {
1694
1695 console_printf("invalid 'public_target_address' parameter\n");
1696 return EINVAL;
1697 }
1698 memcpy(public_tgt_addrs[adv_fields.num_public_tgt_addrs],
1699 public_tgt_addr, BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN);
1700 adv_fields.num_public_tgt_addrs++;
1701 } else if (rc == ENOENT) {
1702 break;
1703 } else {
1704 console_printf("invalid 'public_target_address' parameter\n");
1705 return rc;
1706 }
1707 }
1708 if (adv_fields.num_public_tgt_addrs > 0) {
1709 adv_fields.public_tgt_addr = (void *)public_tgt_addrs;
1710 }
1711
1712 adv_fields.appearance = parse_arg_uint16("appearance", &rc);
1713 if (rc == 0) {
1714 adv_fields.appearance_is_present = 1;
1715 } else if (rc != ENOENT) {
1716 console_printf("invalid 'appearance' parameter\n");
1717 return rc;
1718 }
1719
1720 adv_fields.adv_itvl = parse_arg_uint16("advertising_interval", &rc);
1721 if (rc == 0) {
1722 adv_fields.adv_itvl_is_present = 1;
1723 } else if (rc != ENOENT) {
1724 console_printf("invalid 'advertising_interval' parameter\n");
1725 return rc;
1726 }
1727
1728 rc = parse_arg_byte_stream("service_data_uuid32",
1729 CMD_ADV_DATA_SVC_DATA_UUID32_MAX_LEN,
1730 svc_data_uuid32, &svc_data_uuid32_len);
1731 if (rc == 0) {
1732 adv_fields.svc_data_uuid32 = svc_data_uuid32;
1733 adv_fields.svc_data_uuid32_len = svc_data_uuid32_len;
1734 } else if (rc != ENOENT) {
1735 console_printf("invalid 'service_data_uuid32' parameter\n");
1736 return rc;
1737 }
1738
1739 rc = parse_arg_byte_stream("service_data_uuid128",
1740 CMD_ADV_DATA_SVC_DATA_UUID128_MAX_LEN,
1741 svc_data_uuid128, &svc_data_uuid128_len);
1742 if (rc == 0) {
1743 adv_fields.svc_data_uuid128 = svc_data_uuid128;
1744 adv_fields.svc_data_uuid128_len = svc_data_uuid128_len;
1745 } else if (rc != ENOENT) {
1746 console_printf("invalid 'service_data_uuid128' parameter\n");
1747 return rc;
1748 }
1749
1750 rc = parse_arg_byte_stream("uri", CMD_ADV_DATA_URI_MAX_LEN, uri, &uri_len);
1751 if (rc == 0) {
1752 adv_fields.uri = uri;
1753 adv_fields.uri_len = uri_len;
1754 } else if (rc != ENOENT) {
1755 console_printf("invalid 'uri' parameter\n");
1756 return rc;
1757 }
1758
1759 rc = parse_arg_byte_stream("mfg_data", CMD_ADV_DATA_MFG_DATA_MAX_LEN,
1760 mfg_data, &mfg_data_len);
1761 if (rc == 0) {
1762 adv_fields.mfg_data = mfg_data;
1763 adv_fields.mfg_data_len = mfg_data_len;
1764 } else if (rc != ENOENT) {
1765 console_printf("invalid 'mfg_data' parameter\n");
1766 return rc;
1767 }
1768
1769 tmp = parse_arg_long_bounds("eddystone_measured_power", -100, 20, &rc);
1770 if (rc == 0) {
1771 eddystone_measured_power = tmp;
1772 } else if (rc != ENOENT) {
1773 console_printf("invalid 'eddystone_measured_power' parameter\n");
1774 return rc;
1775 }
1776
1777 eddystone_url_full = parse_arg_extract("eddystone_url");
1778 if (eddystone_url_full != NULL) {
1779 rc = parse_eddystone_url(eddystone_url_full, &eddystone_url_scheme,
1780 eddystone_url_body,
1781 &eddystone_url_body_len,
1782 &eddystone_url_suffix);
1783 if (rc != 0) {
1784 goto done;
1785 }
1786
1787 rc = ble_eddystone_set_adv_data_url(&adv_fields, eddystone_url_scheme,
1788 eddystone_url_body,
1789 eddystone_url_body_len,
1790 eddystone_url_suffix,
1791 eddystone_measured_power);
1792 } else {
1793 #if MYNEWT_VAL(BLE_EXT_ADV)
1794 /* Default to legacy PDUs size, mbuf chain will be increased if needed
1795 */
1796 adv_data = os_msys_get_pkthdr(BLE_HCI_MAX_ADV_DATA_LEN, 0);
1797 if (!adv_data) {
1798 rc = ENOMEM;
1799 goto done;
1800 }
1801
1802 rc = ble_hs_adv_set_fields_mbuf(&adv_fields, adv_data);
1803 if (rc) {
1804 goto done;
1805 }
1806
1807 /* Append some extra data, if requested */
1808 extra_data_len = parse_arg_uint16("extra_data_len", &rc);
1809 if (rc == 0) {
1810 counter = 0;
1811 extra_data_len = min(extra_data_len, 1650);
1812 while (counter < extra_data_len) {
1813 update_pattern(extra_data, counter);
1814
1815 os_mbuf_append(adv_data, extra_data,
1816 min(extra_data_len - counter, 10));
1817
1818 counter += 10;
1819 }
1820 }
1821
1822 if (scan_rsp) {
1823 rc = ble_gap_ext_adv_rsp_set_data(instance, adv_data);
1824 } else {
1825 rc = ble_gap_ext_adv_set_data(instance, adv_data);
1826 }
1827 #else
1828 if (scan_rsp) {
1829 rc = ble_gap_adv_rsp_set_fields(&adv_fields);
1830 } else {
1831 rc = ble_gap_adv_set_fields(&adv_fields);
1832 }
1833 #endif
1834 }
1835 done:
1836 if (rc != 0) {
1837 console_printf("error setting advertisement data; rc=%d\n", rc);
1838 return rc;
1839 }
1840
1841 return 0;
1842 }
1843
1844 static int
cmd_set_adv_data(int argc,char ** argv)1845 cmd_set_adv_data(int argc, char **argv)
1846 {
1847 return cmd_set_adv_data_or_scan_rsp(argc, argv, false);
1848 }
1849
1850 static int
cmd_set_scan_rsp(int argc,char ** argv)1851 cmd_set_scan_rsp(int argc, char **argv)
1852 {
1853 return cmd_set_adv_data_or_scan_rsp(argc, argv, true);
1854 }
1855
1856 #if MYNEWT_VAL(SHELL_CMD_HELP)
1857 static const struct shell_param set_adv_data_params[] = {
1858 {"instance", "default: 0"},
1859 {"flags", "usage: =[0-UINT8_MAX]"},
1860 {"uuid16", "usage: =[UINT16]"},
1861 {"uuid16_is_complete", "usage: =[0-1], default=0"},
1862 {"uuid32", "usage: =[UINT32]"},
1863 {"uuid32_is_complete", "usage: =[0-1], default=0"},
1864 {"uuid128", "usage: =[XX:XX...], len=16 octets"},
1865 {"uuid128_is_complete", "usage: =[0-1], default=0"},
1866 {"tx_power_level", "usage: =[INT8_MIN-INT8_MAX]"},
1867 {"slave_interval_range", "usage: =[XX:XX:XX:XX]"},
1868 {"public_target_address", "usage: =[XX:XX:XX:XX:XX:XX]"},
1869 {"appearance", "usage: =[UINT16]"},
1870 {"name", "usage: =[string]"},
1871 {"advertising_interval", "usage: =[UINT16]"},
1872 {"service_data_uuid16", "usage: =[XX:XX...]"},
1873 {"service_data_uuid32", "usage: =[XX:XX...]"},
1874 {"service_data_uuid128", "usage: =[XX:XX...]"},
1875 {"uri", "usage: =[XX:XX...]"},
1876 {"mfg_data", "usage: =[XX:XX...]"},
1877 {"measured_power", "usage: =[-100-20]"},
1878 {"eddystone_url", "usage: =[string]"},
1879 #if MYNEWT_VAL(BLE_EXT_ADV)
1880 {"extra_data_len", "usage: =[UINT16]"},
1881 #endif
1882 {NULL, NULL}
1883 };
1884
1885 static const struct shell_cmd_help set_adv_data_help = {
1886 .summary = "set advertising data",
1887 .usage = NULL,
1888 .params = set_adv_data_params,
1889 };
1890
1891 static const struct shell_cmd_help set_scan_rsp_help = {
1892 .summary = "set scan response",
1893 .usage = NULL,
1894 .params = set_adv_data_params,
1895 };
1896 #endif
1897
1898 /*****************************************************************************
1899 * $set-priv-mode *
1900 *****************************************************************************/
1901
1902 static int
cmd_set_priv_mode(int argc,char ** argv)1903 cmd_set_priv_mode(int argc, char **argv)
1904 {
1905 ble_addr_t addr;
1906 uint8_t priv_mode;
1907 int rc;
1908
1909 rc = parse_arg_all(argc - 1, argv + 1);
1910 if (rc != 0) {
1911 return rc;
1912 }
1913
1914 addr.type = parse_arg_kv_dflt("addr_type", cmd_set_addr_types,
1915 BLE_ADDR_PUBLIC, &rc);
1916 if (rc != 0) {
1917 console_printf("invalid 'addr_type' parameter\n");
1918 return rc;
1919 }
1920
1921 rc = parse_arg_mac("addr", addr.val);
1922 if (rc != 0) {
1923 console_printf("invalid 'addr' parameter\n");
1924 return rc;
1925 }
1926
1927 priv_mode = parse_arg_uint8("mode", &rc);
1928 if (rc != 0) {
1929 console_printf("missing mode\n");
1930 return rc;
1931 }
1932
1933 return ble_gap_set_priv_mode(&addr, priv_mode);
1934 }
1935
1936 #if MYNEWT_VAL(SHELL_CMD_HELP)
1937 static const struct shell_param set_priv_mode_params[] = {
1938 {"addr", "set priv mode for device address, usage: =[XX:XX:XX:XX:XX:XX]"},
1939 {"addr_type", "set priv mode for device address type, usage: =[public|random], default: public"},
1940 {"mode", "set priv mode, usage: =[0-UINT8_MAX]"},
1941 {NULL, NULL}
1942 };
1943
1944 static const struct shell_cmd_help set_priv_mode_help = {
1945 .summary = "set priv mode",
1946 .usage = NULL,
1947 .params = set_priv_mode_params,
1948 };
1949 #endif
1950
1951 /*****************************************************************************
1952 * $white-list *
1953 *****************************************************************************/
1954
1955 #define CMD_WL_MAX_SZ 8
1956
1957 static int
cmd_white_list(int argc,char ** argv)1958 cmd_white_list(int argc, char **argv)
1959 {
1960 static ble_addr_t addrs[CMD_WL_MAX_SZ];
1961 int addrs_cnt;
1962 int rc;
1963
1964 rc = parse_arg_all(argc - 1, argv + 1);
1965 if (rc != 0) {
1966 return rc;
1967 }
1968
1969 addrs_cnt = 0;
1970 while (1) {
1971 if (addrs_cnt >= CMD_WL_MAX_SZ) {
1972 return EINVAL;
1973 }
1974
1975 rc = parse_arg_mac("addr", addrs[addrs_cnt].val);
1976 if (rc == ENOENT) {
1977 break;
1978 } else if (rc != 0) {
1979 console_printf("invalid 'addr' parameter\n");
1980 return rc;
1981 }
1982
1983 addrs[addrs_cnt].type = parse_arg_kv("addr_type", cmd_addr_type, &rc);
1984 if (rc != 0) {
1985 console_printf("invalid 'addr' parameter\n");
1986 return rc;
1987 }
1988
1989 addrs_cnt++;
1990 }
1991
1992 if (addrs_cnt == 0) {
1993 return EINVAL;
1994 }
1995
1996 btshell_wl_set(addrs, addrs_cnt);
1997
1998 return 0;
1999 }
2000
2001 #if MYNEWT_VAL(SHELL_CMD_HELP)
2002 static const struct shell_param white_list_params[] = {
2003 {"addr", "white-list device addresses, usage: =[XX:XX:XX:XX:XX:XX]"},
2004 {"addr_type", "white-list address types, usage: =[public|random]"},
2005 {NULL, NULL}
2006 };
2007
2008 static const struct shell_cmd_help white_list_help = {
2009 .summary = "set white-list addresses",
2010 .usage = NULL,
2011 .params = white_list_params,
2012 };
2013 #endif
2014
2015 /*****************************************************************************
2016 * $conn-rssi *
2017 *****************************************************************************/
2018
2019 static int
cmd_conn_rssi(int argc,char ** argv)2020 cmd_conn_rssi(int argc, char **argv)
2021 {
2022 uint16_t conn_handle;
2023 int8_t rssi;
2024 int rc;
2025
2026 rc = parse_arg_all(argc - 1, argv + 1);
2027 if (rc != 0) {
2028 return rc;
2029 }
2030
2031 conn_handle = parse_arg_uint16("conn", &rc);
2032 if (rc != 0) {
2033 console_printf("invalid 'conn' parameter\n");
2034 return rc;
2035 }
2036
2037 rc = btshell_rssi(conn_handle, &rssi);
2038 if (rc != 0) {
2039 console_printf("error reading rssi; rc=%d\n", rc);
2040 return rc;
2041 }
2042
2043 console_printf("conn=%d rssi=%d\n", conn_handle, rssi);
2044
2045 return 0;
2046 }
2047
2048 #if MYNEWT_VAL(SHELL_CMD_HELP)
2049 static const struct shell_param conn_rssi_params[] = {
2050 {"conn", "connection handle parameter, usage: =<UINT16>"},
2051 {NULL, NULL}
2052 };
2053
2054 static const struct shell_cmd_help conn_rssi_help = {
2055 .summary = "check connection rssi",
2056 .usage = NULL,
2057 .params = conn_rssi_params,
2058 };
2059 #endif
2060
2061 /*****************************************************************************
2062 * $conn-update-params *
2063 *****************************************************************************/
2064
2065 static int
cmd_conn_update_params(int argc,char ** argv)2066 cmd_conn_update_params(int argc, char **argv)
2067 {
2068 struct ble_gap_upd_params params;
2069 uint16_t conn_handle;
2070 int rc;
2071
2072 rc = parse_arg_all(argc - 1, argv + 1);
2073 if (rc != 0) {
2074 return rc;
2075 }
2076
2077 conn_handle = parse_arg_uint16("conn", &rc);
2078 if (rc != 0) {
2079 console_printf("invalid 'conn' parameter\n");
2080 return rc;
2081 }
2082
2083 params.itvl_min = parse_arg_uint16_dflt("interval_min",
2084 BLE_GAP_INITIAL_CONN_ITVL_MIN,
2085 &rc);
2086 if (rc != 0) {
2087 console_printf("invalid 'interval_min' parameter\n");
2088 return rc;
2089 }
2090
2091 params.itvl_max = parse_arg_uint16_dflt("interval_max",
2092 BLE_GAP_INITIAL_CONN_ITVL_MAX,
2093 &rc);
2094 if (rc != 0) {
2095 console_printf("invalid 'interval_max' parameter\n");
2096 return rc;
2097 }
2098
2099 params.latency = parse_arg_uint16_dflt("latency", 0, &rc);
2100 if (rc != 0) {
2101 console_printf("invalid 'latency' parameter\n");
2102 return rc;
2103 }
2104
2105 params.supervision_timeout = parse_arg_uint16_dflt("timeout", 0x0100, &rc);
2106 if (rc != 0) {
2107 console_printf("invalid 'timeout' parameter\n");
2108 return rc;
2109 }
2110
2111 params.min_ce_len = parse_arg_uint16_dflt("min_conn_event_len",
2112 0x0010, &rc);
2113 if (rc != 0) {
2114 console_printf("invalid 'min_conn_event_len' parameter\n");
2115 return rc;
2116 }
2117
2118 params.max_ce_len = parse_arg_uint16_dflt("max_conn_event_len",
2119 0x0300, &rc);
2120 if (rc != 0) {
2121 console_printf("invalid 'max_conn_event_len' parameter\n");
2122 return rc;
2123 }
2124
2125 rc = btshell_update_conn(conn_handle, ¶ms);
2126 if (rc != 0) {
2127 console_printf("error updating connection; rc=%d\n", rc);
2128 return rc;
2129 }
2130
2131 return 0;
2132 }
2133
2134 #if MYNEWT_VAL(SHELL_CMD_HELP)
2135 static const struct shell_param conn_update_params_params[] = {
2136 {"conn", "conn_update_paramsion handle, usage: =<UINT16>"},
2137 {"interval_min", "usage: =[0-UINT16_MAX], default: 30"},
2138 {"interval_max", "usage: =[0-UINT16_MAX], default: 50"},
2139 {"latency", "usage: =[UINT16], default: 0"},
2140 {"timeout", "usage: =[UINT16], default: 0x0100"},
2141 {"min_conn_event_len", "usage: =[UINT16], default: 0x0010"},
2142 {"max_conn_event_len", "usage: =[UINT16], default: 0x0300"},
2143 {NULL, NULL}
2144 };
2145
2146 static const struct shell_cmd_help conn_update_params_help = {
2147 .summary = "update connection parameters",
2148 .usage = "conn_update_params usage",
2149 .params = conn_update_params_params,
2150 };
2151 #endif
2152
2153 /*****************************************************************************
2154 * $conn-datalen *
2155 *****************************************************************************/
2156
2157 static int
cmd_conn_datalen(int argc,char ** argv)2158 cmd_conn_datalen(int argc, char **argv)
2159 {
2160 uint16_t conn_handle;
2161 uint16_t tx_octets;
2162 uint16_t tx_time;
2163 int rc;
2164
2165 rc = parse_arg_all(argc - 1, argv + 1);
2166 if (rc != 0) {
2167 return rc;
2168 }
2169
2170 conn_handle = parse_arg_uint16("conn", &rc);
2171 if (rc != 0) {
2172 console_printf("invalid 'conn' parameter\n");
2173 return rc;
2174 }
2175
2176 tx_octets = parse_arg_uint16("octets", &rc);
2177 if (rc != 0) {
2178 console_printf("invalid 'octets' parameter\n");
2179 return rc;
2180 }
2181
2182 tx_time = parse_arg_uint16("time", &rc);
2183 if (rc != 0) {
2184 console_printf("invalid 'time' parameter\n");
2185 return rc;
2186 }
2187
2188 rc = btshell_datalen(conn_handle, tx_octets, tx_time);
2189 if (rc != 0) {
2190 console_printf("error setting data length; rc=%d\n", rc);
2191 return rc;
2192 }
2193
2194 return 0;
2195 }
2196
2197 #if MYNEWT_VAL(SHELL_CMD_HELP)
2198 static const struct shell_param conn_datalen_params[] = {
2199 {"conn", "conn_datalen handle, usage: =<UINT16>"},
2200 {"octets", "usage: =<UINT16>"},
2201 {"time", "usage: =<UINT16>"},
2202 {NULL, NULL}
2203 };
2204
2205 static const struct shell_cmd_help conn_datalen_help = {
2206 .summary = "set data length parameters for connection",
2207 .usage = NULL,
2208 .params = conn_datalen_params,
2209 };
2210 #endif
2211
2212 /*****************************************************************************
2213 * keystore *
2214 *****************************************************************************/
2215
2216 static const struct kv_pair cmd_keystore_entry_type[] = {
2217 { "msec", BLE_STORE_OBJ_TYPE_PEER_SEC },
2218 { "ssec", BLE_STORE_OBJ_TYPE_OUR_SEC },
2219 { "cccd", BLE_STORE_OBJ_TYPE_CCCD },
2220 { NULL }
2221 };
2222
2223 static int
cmd_keystore_parse_keydata(int argc,char ** argv,union ble_store_key * out,int * obj_type)2224 cmd_keystore_parse_keydata(int argc, char **argv, union ble_store_key *out,
2225 int *obj_type)
2226 {
2227 int rc;
2228
2229 memset(out, 0, sizeof(*out));
2230 *obj_type = parse_arg_kv("type", cmd_keystore_entry_type, &rc);
2231 if (rc != 0) {
2232 console_printf("invalid 'type' parameter\n");
2233 return rc;
2234 }
2235
2236 switch (*obj_type) {
2237 case BLE_STORE_OBJ_TYPE_PEER_SEC:
2238 case BLE_STORE_OBJ_TYPE_OUR_SEC:
2239 out->sec.peer_addr.type = parse_arg_kv("addr_type",
2240 cmd_addr_type, &rc);
2241 if (rc != 0) {
2242 console_printf("invalid 'addr_type' parameter\n");
2243 return rc;
2244 }
2245
2246 rc = parse_arg_mac("addr", out->sec.peer_addr.val);
2247 if (rc != 0) {
2248 console_printf("invalid 'addr' parameter\n");
2249 return rc;
2250 }
2251
2252 out->sec.ediv = parse_arg_uint16("ediv", &rc);
2253 if (rc != 0) {
2254 console_printf("invalid 'ediv' parameter\n");
2255 return rc;
2256 }
2257
2258 out->sec.rand_num = parse_arg_uint64("rand", &rc);
2259 if (rc != 0) {
2260 console_printf("invalid 'rand' parameter\n");
2261 return rc;
2262 }
2263 return 0;
2264
2265 default:
2266 return EINVAL;
2267 }
2268 }
2269
2270 static int
cmd_keystore_parse_valuedata(int argc,char ** argv,int obj_type,union ble_store_key * key,union ble_store_value * out)2271 cmd_keystore_parse_valuedata(int argc, char **argv,
2272 int obj_type,
2273 union ble_store_key *key,
2274 union ble_store_value *out)
2275 {
2276 int rc;
2277 int valcnt = 0;
2278 memset(out, 0, sizeof(*out));
2279
2280 switch (obj_type) {
2281 case BLE_STORE_OBJ_TYPE_PEER_SEC:
2282 case BLE_STORE_OBJ_TYPE_OUR_SEC:
2283 rc = parse_arg_byte_stream_exact_length("ltk", out->sec.ltk, 16);
2284 if (rc == 0) {
2285 out->sec.ltk_present = 1;
2286 swap_in_place(out->sec.ltk, 16);
2287 valcnt++;
2288 } else if (rc != ENOENT) {
2289 console_printf("invalid 'ltk' parameter\n");
2290 return rc;
2291 }
2292 rc = parse_arg_byte_stream_exact_length("irk", out->sec.irk, 16);
2293 if (rc == 0) {
2294 out->sec.irk_present = 1;
2295 swap_in_place(out->sec.irk, 16);
2296 valcnt++;
2297 } else if (rc != ENOENT) {
2298 console_printf("invalid 'irk' parameter\n");
2299 return rc;
2300 }
2301 rc = parse_arg_byte_stream_exact_length("csrk", out->sec.csrk, 16);
2302 if (rc == 0) {
2303 out->sec.csrk_present = 1;
2304 swap_in_place(out->sec.csrk, 16);
2305 valcnt++;
2306 } else if (rc != ENOENT) {
2307 console_printf("invalid 'csrk' parameter\n");
2308 return rc;
2309 }
2310 out->sec.peer_addr = key->sec.peer_addr;
2311 out->sec.ediv = key->sec.ediv;
2312 out->sec.rand_num = key->sec.rand_num;
2313 break;
2314 }
2315
2316 if (valcnt) {
2317 return 0;
2318 }
2319 return -1;
2320 }
2321
2322 /*****************************************************************************
2323 * keystore-add *
2324 *****************************************************************************/
2325
2326 static int
cmd_keystore_add(int argc,char ** argv)2327 cmd_keystore_add(int argc, char **argv)
2328 {
2329 union ble_store_key key;
2330 union ble_store_value value;
2331 int obj_type;
2332 int rc;
2333
2334 rc = parse_arg_all(argc - 1, argv + 1);
2335 if (rc != 0) {
2336 return rc;
2337 }
2338
2339 rc = cmd_keystore_parse_keydata(argc, argv, &key, &obj_type);
2340
2341 if (rc) {
2342 return rc;
2343 }
2344
2345 rc = cmd_keystore_parse_valuedata(argc, argv, obj_type, &key, &value);
2346
2347 if (rc) {
2348 return rc;
2349 }
2350
2351 switch(obj_type) {
2352 case BLE_STORE_OBJ_TYPE_PEER_SEC:
2353 rc = ble_store_write_peer_sec(&value.sec);
2354 break;
2355 case BLE_STORE_OBJ_TYPE_OUR_SEC:
2356 rc = ble_store_write_our_sec(&value.sec);
2357 break;
2358 case BLE_STORE_OBJ_TYPE_CCCD:
2359 rc = ble_store_write_cccd(&value.cccd);
2360 break;
2361 default:
2362 rc = ble_store_write(obj_type, &value);
2363 }
2364 return rc;
2365 }
2366
2367 #if MYNEWT_VAL(SHELL_CMD_HELP)
2368 static const struct shell_param keystore_add_params[] = {
2369 {"type", "entry type, usage: =<msec|ssec|cccd>"},
2370 {"addr_type", "usage: =<public|random>"},
2371 {"addr", "usage: =<XX:XX:XX:XX:XX:XX>"},
2372 {"ediv", "usage: =<UINT16>"},
2373 {"rand", "usage: =<UINT64>"},
2374 {"ltk", "usage: =<XX:XX:...>, len=16 octets"},
2375 {"irk", "usage: =<XX:XX:...>, len=16 octets"},
2376 {"csrk", "usage: =<XX:XX:...>, len=16 octets"},
2377 {NULL, NULL}
2378 };
2379
2380 static const struct shell_cmd_help keystore_add_help = {
2381 .summary = "add data to keystore",
2382 .usage = NULL,
2383 .params = keystore_add_params,
2384 };
2385 #endif
2386
2387 /*****************************************************************************
2388 * keystore-del *
2389 *****************************************************************************/
2390
2391 static int
cmd_keystore_del(int argc,char ** argv)2392 cmd_keystore_del(int argc, char **argv)
2393 {
2394 union ble_store_key key;
2395 int obj_type;
2396 int rc;
2397
2398 rc = parse_arg_all(argc - 1, argv + 1);
2399 if (rc != 0) {
2400 return rc;
2401 }
2402
2403 rc = cmd_keystore_parse_keydata(argc, argv, &key, &obj_type);
2404
2405 if (rc) {
2406 return rc;
2407 }
2408 rc = ble_store_delete(obj_type, &key);
2409 return rc;
2410 }
2411
2412 #if MYNEWT_VAL(SHELL_CMD_HELP)
2413 static const struct shell_param keystore_del_params[] = {
2414 {"type", "entry type, usage: =<msec|ssec|cccd>"},
2415 {"addr_type", "usage: =<public|random>"},
2416 {"addr", "usage: =<XX:XX:XX:XX:XX:XX>"},
2417 {"ediv", "usage: =<UINT16>"},
2418 {"rand", "usage: =<UINT64>"},
2419 {NULL, NULL}
2420 };
2421
2422 static const struct shell_cmd_help keystore_del_help = {
2423 .summary = "remove data from keystore",
2424 .usage = NULL,
2425 .params = keystore_del_params,
2426 };
2427 #endif
2428
2429 /*****************************************************************************
2430 * keystore-show *
2431 *****************************************************************************/
2432
2433 static int
cmd_keystore_iterator(int obj_type,union ble_store_value * val,void * cookie)2434 cmd_keystore_iterator(int obj_type,
2435 union ble_store_value *val,
2436 void *cookie) {
2437
2438 switch (obj_type) {
2439 case BLE_STORE_OBJ_TYPE_PEER_SEC:
2440 case BLE_STORE_OBJ_TYPE_OUR_SEC:
2441 console_printf("Key: ");
2442 if (ble_addr_cmp(&val->sec.peer_addr, BLE_ADDR_ANY) == 0) {
2443 console_printf("ediv=%u ", val->sec.ediv);
2444 console_printf("ediv=%llu ", val->sec.rand_num);
2445 } else {
2446 console_printf("addr_type=%u ", val->sec.peer_addr.type);
2447 print_addr(val->sec.peer_addr.val);
2448 }
2449 console_printf("\n");
2450
2451 if (val->sec.ltk_present) {
2452 console_printf(" LTK: ");
2453 print_bytes(val->sec.ltk, 16);
2454 console_printf("\n");
2455 }
2456 if (val->sec.irk_present) {
2457 console_printf(" IRK: ");
2458 print_bytes(val->sec.irk, 16);
2459 console_printf("\n");
2460 }
2461 if (val->sec.csrk_present) {
2462 console_printf(" CSRK: ");
2463 print_bytes(val->sec.csrk, 16);
2464 console_printf("\n");
2465 }
2466 break;
2467 }
2468 return 0;
2469 }
2470
2471 static int
cmd_keystore_show(int argc,char ** argv)2472 cmd_keystore_show(int argc, char **argv)
2473 {
2474 int type;
2475 int rc;
2476
2477 rc = parse_arg_all(argc - 1, argv + 1);
2478 if (rc != 0) {
2479 return rc;
2480 }
2481
2482 type = parse_arg_kv("type", cmd_keystore_entry_type, &rc);
2483 if (rc != 0) {
2484 console_printf("invalid 'type' parameter\n");
2485 return rc;
2486 }
2487
2488 ble_store_iterate(type, &cmd_keystore_iterator, NULL);
2489 return 0;
2490 }
2491
2492 #if MYNEWT_VAL(SHELL_CMD_HELP)
2493 static const struct shell_param keystore_show_params[] = {
2494 {"type", "entry type, usage: =<msec|ssec|cccd>"},
2495 {NULL, NULL}
2496 };
2497
2498 static const struct shell_cmd_help keystore_show_help = {
2499 .summary = "show data in keystore",
2500 .usage = NULL,
2501 .params = keystore_show_params,
2502 };
2503 #endif
2504
2505 #if NIMBLE_BLE_SM
2506 /*****************************************************************************
2507 * $auth-passkey *
2508 *****************************************************************************/
2509
2510 static int
cmd_auth_passkey(int argc,char ** argv)2511 cmd_auth_passkey(int argc, char **argv)
2512 {
2513 uint16_t conn_handle;
2514 struct ble_sm_io pk;
2515 char *yesno;
2516 int rc;
2517
2518 rc = parse_arg_all(argc - 1, argv + 1);
2519 if (rc != 0) {
2520 return rc;
2521 }
2522
2523 conn_handle = parse_arg_uint16("conn", &rc);
2524 if (rc != 0) {
2525 console_printf("invalid 'conn' parameter\n");
2526 return rc;
2527 }
2528
2529 pk.action = parse_arg_uint16("action", &rc);
2530 if (rc != 0) {
2531 console_printf("invalid 'action' parameter\n");
2532 return rc;
2533 }
2534
2535 switch (pk.action) {
2536 case BLE_SM_IOACT_INPUT:
2537 case BLE_SM_IOACT_DISP:
2538 /* passkey is 6 digit number */
2539 pk.passkey = parse_arg_long_bounds("key", 0, 999999, &rc);
2540 if (rc != 0) {
2541 console_printf("invalid 'key' parameter\n");
2542 return rc;
2543 }
2544 break;
2545
2546 case BLE_SM_IOACT_OOB:
2547 rc = parse_arg_byte_stream_exact_length("oob", pk.oob, 16);
2548 if (rc != 0) {
2549 console_printf("invalid 'oob' parameter\n");
2550 return rc;
2551 }
2552 break;
2553
2554 case BLE_SM_IOACT_NUMCMP:
2555 yesno = parse_arg_extract("yesno");
2556 if (yesno == NULL) {
2557 console_printf("invalid 'yesno' parameter\n");
2558 return EINVAL;
2559 }
2560
2561 switch (yesno[0]) {
2562 case 'y':
2563 case 'Y':
2564 pk.numcmp_accept = 1;
2565 break;
2566 case 'n':
2567 case 'N':
2568 pk.numcmp_accept = 0;
2569 break;
2570
2571 default:
2572 console_printf("invalid 'yesno' parameter\n");
2573 return EINVAL;
2574 }
2575 break;
2576
2577 default:
2578 console_printf("invalid passkey action action=%d\n", pk.action);
2579 return EINVAL;
2580 }
2581
2582 rc = ble_sm_inject_io(conn_handle, &pk);
2583 if (rc != 0) {
2584 console_printf("error providing passkey; rc=%d\n", rc);
2585 return rc;
2586 }
2587
2588 return 0;
2589 }
2590
2591 #if MYNEWT_VAL(SHELL_CMD_HELP)
2592 static const struct shell_param auth_passkey_params[] = {
2593 {"conn", "connection handle, usage: =<UINT16>"},
2594 {"action", "auth action type, usage: =<UINT16>"},
2595 {"key", "usage: =[0-999999]"},
2596 {"oob", "usage: =[XX:XX...], len=16 octets"},
2597 {"yesno", "usage: =[string]"},
2598 {NULL, NULL}
2599 };
2600
2601 static const struct shell_cmd_help auth_passkey_help = {
2602 .summary = "set authorization passkey options",
2603 .usage = NULL,
2604 .params = auth_passkey_params,
2605 };
2606 #endif
2607
2608 /*****************************************************************************
2609 * $security-pair *
2610 *****************************************************************************/
2611
2612 static int
cmd_security_pair(int argc,char ** argv)2613 cmd_security_pair(int argc, char **argv)
2614 {
2615 uint16_t conn_handle;
2616 int rc;
2617
2618 rc = parse_arg_all(argc - 1, argv + 1);
2619 if (rc != 0) {
2620 return rc;
2621 }
2622
2623 conn_handle = parse_arg_uint16("conn", &rc);
2624 if (rc != 0) {
2625 console_printf("invalid 'conn' parameter\n");
2626 return rc;
2627 }
2628
2629 rc = btshell_sec_pair(conn_handle);
2630 if (rc != 0) {
2631 console_printf("error initiating pairing; rc=%d\n", rc);
2632 return rc;
2633 }
2634
2635 return 0;
2636 }
2637
2638 #if MYNEWT_VAL(SHELL_CMD_HELP)
2639 static const struct shell_param security_pair_params[] = {
2640 {"conn", "connection handle, usage: =<UINT16>"},
2641 {NULL, NULL}
2642 };
2643
2644 static const struct shell_cmd_help security_pair_help = {
2645 .summary = "start pairing procedure for connection",
2646 .usage = NULL,
2647 .params = security_pair_params,
2648 };
2649 #endif
2650
2651 /*****************************************************************************
2652 * $security-unpair *
2653 *****************************************************************************/
2654
2655 static int
cmd_security_unpair(int argc,char ** argv)2656 cmd_security_unpair(int argc, char **argv)
2657 {
2658 ble_addr_t peer;
2659 int rc;
2660
2661 rc = parse_arg_all(argc - 1, argv + 1);
2662 if (rc != 0) {
2663 return rc;
2664 }
2665
2666 rc = parse_arg_mac("peer_addr", peer.val);
2667 if (rc == 0) {
2668
2669 peer.type = parse_arg_kv_dflt("peer_addr_type",
2670 cmd_peer_addr_types,
2671 BLE_ADDR_PUBLIC, &rc);
2672 if (rc != 0) {
2673 console_printf("invalid 'peer_addr_type' parameter\n");
2674 return rc;
2675 }
2676 } else {
2677 console_printf("invalid 'peer_addr' parameter\n");
2678 return rc;
2679 }
2680
2681 rc = ble_gap_unpair(&peer);
2682 if (rc != 0) {
2683 console_printf("error unpairing; rc=%d\n", rc);
2684 return rc;
2685 }
2686
2687 return 0;
2688 }
2689
2690 #if MYNEWT_VAL(SHELL_CMD_HELP)
2691 static const struct shell_param security_unpair_params[] = {
2692 {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"},
2693 {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"},
2694 {NULL, NULL}
2695 };
2696
2697 static const struct shell_cmd_help security_unpair_help = {
2698 .summary = "unpair a peer device",
2699 .usage = NULL,
2700 .params = security_unpair_params,
2701 };
2702 #endif
2703
2704 /*****************************************************************************
2705 * $security-start *
2706 *****************************************************************************/
2707
2708 static int
cmd_security_start(int argc,char ** argv)2709 cmd_security_start(int argc, char **argv)
2710 {
2711 uint16_t conn_handle;
2712 int rc;
2713
2714 rc = parse_arg_all(argc - 1, argv + 1);
2715 if (rc != 0) {
2716 return rc;
2717 }
2718
2719 conn_handle = parse_arg_uint16("conn", &rc);
2720 if (rc != 0) {
2721 console_printf("invalid 'conn' parameter\n");
2722 return rc;
2723 }
2724
2725 rc = btshell_sec_start(conn_handle);
2726 if (rc != 0) {
2727 console_printf("error starting security; rc=%d\n", rc);
2728 return rc;
2729 }
2730
2731 return 0;
2732 }
2733
2734 #if MYNEWT_VAL(SHELL_CMD_HELP)
2735 static const struct shell_param security_start_params[] = {
2736 {"conn", "connection handle, usage: =<UINT16>"},
2737 {NULL, NULL}
2738 };
2739
2740 static const struct shell_cmd_help security_start_help = {
2741 .summary = "start security procedure for connection",
2742 .usage = NULL,
2743 .params = security_start_params,
2744 };
2745 #endif
2746
2747 /*****************************************************************************
2748 * $security-encryption *
2749 *****************************************************************************/
2750
2751 static int
cmd_security_encryption(int argc,char ** argv)2752 cmd_security_encryption(int argc, char **argv)
2753 {
2754 uint16_t conn_handle;
2755 uint16_t ediv;
2756 uint64_t rand_val;
2757 uint8_t ltk[16];
2758 int rc;
2759 int auth;
2760
2761 rc = parse_arg_all(argc - 1, argv + 1);
2762 if (rc != 0) {
2763 return rc;
2764 }
2765
2766 conn_handle = parse_arg_uint16("conn", &rc);
2767 if (rc != 0) {
2768 console_printf("invalid 'conn' parameter\n");
2769 return rc;
2770 }
2771
2772 ediv = parse_arg_uint16("ediv", &rc);
2773 if (rc == ENOENT) {
2774 rc = btshell_sec_restart(conn_handle, NULL, 0, 0, 0);
2775 } else {
2776 rand_val = parse_arg_uint64("rand", &rc);
2777 if (rc != 0) {
2778 console_printf("invalid 'rand' parameter\n");
2779 return rc;
2780 }
2781
2782 auth = parse_arg_bool("auth", &rc);
2783 if (rc != 0) {
2784 console_printf("invalid 'auth' parameter\n");
2785 return rc;
2786 }
2787
2788 rc = parse_arg_byte_stream_exact_length("ltk", ltk, 16);
2789 if (rc != 0) {
2790 console_printf("invalid 'ltk' parameter\n");
2791 return rc;
2792 }
2793
2794 rc = btshell_sec_restart(conn_handle, ltk, ediv, rand_val, auth);
2795 }
2796
2797 if (rc != 0) {
2798 console_printf("error initiating encryption; rc=%d\n", rc);
2799 return rc;
2800 }
2801
2802 return 0;
2803 }
2804
2805 #if MYNEWT_VAL(SHELL_CMD_HELP)
2806 static const struct shell_param security_encryption_params[] = {
2807 {"conn", "connection handle, usage: =<UINT16>"},
2808 {"ediv", "usage: =[UINT16]"},
2809 {"rand", "usage: =[UINT64]"},
2810 {"auth", "usage: =[0-1]"},
2811 {"ltk", "usage: =[XX:XX...], len=16 octets"},
2812 {NULL, NULL}
2813 };
2814
2815 static const struct shell_cmd_help security_encryption_help = {
2816 .summary = "start encryption procedure for connection",
2817 .usage = NULL,
2818 .params = security_encryption_params,
2819 };
2820 #endif
2821
2822 /*****************************************************************************
2823 * $security-set-data *
2824 *****************************************************************************/
2825
2826 static int
cmd_security_set_data(int argc,char ** argv)2827 cmd_security_set_data(int argc, char **argv)
2828 {
2829 uint8_t tmp;
2830 int good;
2831 int rc;
2832
2833 good = 0;
2834
2835 rc = parse_arg_all(argc - 1, argv + 1);
2836 if (rc != 0) {
2837 return rc;
2838 }
2839
2840 tmp = parse_arg_bool("oob_flag", &rc);
2841 if (rc == 0) {
2842 ble_hs_cfg.sm_oob_data_flag = tmp;
2843 good++;
2844 } else if (rc != ENOENT) {
2845 console_printf("invalid 'oob_flag' parameter\n");
2846 return rc;
2847 }
2848
2849 tmp = parse_arg_bool("mitm_flag", &rc);
2850 if (rc == 0) {
2851 good++;
2852 ble_hs_cfg.sm_mitm = tmp;
2853 } else if (rc != ENOENT) {
2854 console_printf("invalid 'mitm_flag' parameter\n");
2855 return rc;
2856 }
2857
2858 tmp = parse_arg_uint8("io_capabilities", &rc);
2859 if (rc == 0) {
2860 good++;
2861 ble_hs_cfg.sm_io_cap = tmp;
2862 } else if (rc != ENOENT) {
2863 console_printf("invalid 'io_capabilities' parameter\n");
2864 return rc;
2865 }
2866
2867 tmp = parse_arg_uint8("our_key_dist", &rc);
2868 if (rc == 0) {
2869 good++;
2870 ble_hs_cfg.sm_our_key_dist = tmp;
2871 } else if (rc != ENOENT) {
2872 console_printf("invalid 'our_key_dist' parameter\n");
2873 return rc;
2874 }
2875
2876 tmp = parse_arg_uint8("their_key_dist", &rc);
2877 if (rc == 0) {
2878 good++;
2879 ble_hs_cfg.sm_their_key_dist = tmp;
2880 } else if (rc != ENOENT) {
2881 console_printf("invalid 'their_key_dist' parameter\n");
2882 return rc;
2883 }
2884
2885 tmp = parse_arg_bool("bonding", &rc);
2886 if (rc == 0) {
2887 good++;
2888 ble_hs_cfg.sm_bonding = tmp;
2889 } else if (rc != ENOENT) {
2890 console_printf("invalid 'bonding' parameter\n");
2891 return rc;
2892 }
2893
2894 tmp = parse_arg_bool("sc", &rc);
2895 if (rc == 0) {
2896 good++;
2897 ble_hs_cfg.sm_sc = tmp;
2898 } else if (rc != ENOENT) {
2899 console_printf("invalid 'sc' parameter\n");
2900 return rc;
2901 }
2902
2903 if (!good) {
2904 console_printf("Error: no valid settings specified\n");
2905 return -1;
2906 }
2907
2908 return 0;
2909 }
2910
2911 #if MYNEWT_VAL(SHELL_CMD_HELP)
2912 static const struct shell_param security_set_data_params[] = {
2913 {"oob_flag", "usage: =[0-1]"},
2914 {"mitm_flag", "usage: =[0-1]"},
2915 {"io_capabilities", "usage: =[UINT8]"},
2916 {"our_key_dist", "usage: =[UINT8]"},
2917 {"their_key_dist", "usage: =[UINT8]"},
2918 {"bonding", "usage: =[0-1]"},
2919 {"sc", "usage: =[0-1]"},
2920 {NULL, NULL}
2921 };
2922
2923 static const struct shell_cmd_help security_set_data_help = {
2924 .summary = "set security data",
2925 .usage = NULL,
2926 .params = security_set_data_params,
2927 };
2928 #endif
2929 #endif
2930
2931 /*****************************************************************************
2932 * $test-tx *
2933 * *
2934 * Command to transmit 'num' packets of size 'len' at rate 'r' to
2935 * handle 'h' Note that length must be <= 251. The rate is in msecs.
2936 *
2937 *****************************************************************************/
2938
2939 static int
cmd_test_tx(int argc,char ** argv)2940 cmd_test_tx(int argc, char **argv)
2941 {
2942 int rc;
2943 uint16_t rate;
2944 uint16_t len;
2945 uint16_t handle;
2946 uint16_t num;
2947
2948 rc = parse_arg_all(argc - 1, argv + 1);
2949 if (rc != 0) {
2950 return rc;
2951 }
2952
2953 rate = parse_arg_uint16("rate", &rc);
2954 if (rc != 0) {
2955 console_printf("invalid 'rate' parameter\n");
2956 return rc;
2957 }
2958
2959 len = parse_arg_uint16("length", &rc);
2960 if (rc != 0) {
2961 console_printf("invalid 'length' parameter\n");
2962 return rc;
2963 }
2964 if ((len > 251) || (len < 4)) {
2965 console_printf("error: len must be between 4 and 251, inclusive");
2966 }
2967
2968 num = parse_arg_uint16("num", &rc);
2969 if (rc != 0) {
2970 console_printf("invalid 'num' parameter\n");
2971 return rc;
2972 }
2973
2974 handle = parse_arg_uint16("handle", &rc);
2975 if (rc != 0) {
2976 console_printf("invalid 'handle' parameter\n");
2977 return rc;
2978 }
2979
2980 rc = btshell_tx_start(handle, len, rate, num);
2981 return rc;
2982 }
2983
2984 #if MYNEWT_VAL(SHELL_CMD_HELP)
2985 static const struct shell_param test_tx_params[] = {
2986 {"num", "number of packets, usage: =<UINT16>"},
2987 {"length", "size of packet, usage: =<UINT16>"},
2988 {"rate", "rate of tx, usage: =<UINT16>"},
2989 {"handle", "handle to tx to, usage: =<UINT16>"},
2990 {NULL, NULL}
2991 };
2992
2993 static const struct shell_cmd_help test_tx_help = {
2994 .summary = "test packet transmission",
2995 .usage = NULL,
2996 .params = test_tx_params,
2997 };
2998 #endif
2999
3000 /*****************************************************************************
3001 * $phy-set *
3002 *****************************************************************************/
3003
3004 static int
cmd_phy_set(int argc,char ** argv)3005 cmd_phy_set(int argc, char **argv)
3006 {
3007 uint16_t conn;
3008 uint8_t tx_phys_mask;
3009 uint8_t rx_phys_mask;
3010 uint16_t phy_opts;
3011 int rc;
3012
3013 rc = parse_arg_all(argc - 1, argv + 1);
3014 if (rc != 0) {
3015 return rc;
3016 }
3017
3018 conn = parse_arg_uint16("conn", &rc);
3019 if (rc != 0) {
3020 console_printf("invalid 'conn' parameter\n");
3021 return rc;
3022 }
3023
3024 tx_phys_mask = parse_arg_uint8("tx_phys_mask", &rc);
3025 if (rc != 0) {
3026 console_printf("invalid 'tx_phys_mask' parameter\n");
3027 return rc;
3028 }
3029
3030 rx_phys_mask = parse_arg_uint8("rx_phys_mask", &rc);
3031 if (rc != 0) {
3032 console_printf("invalid 'rx_phys_mask' parameter\n");
3033 return rc;
3034 }
3035
3036 phy_opts = parse_arg_uint16("phy_opts", &rc);
3037 if (rc != 0) {
3038 console_printf("invalid 'phy_opts' parameter\n");
3039 return rc;
3040 }
3041
3042 return ble_gap_set_prefered_le_phy(conn, tx_phys_mask, rx_phys_mask,
3043 phy_opts);
3044 }
3045
3046 #if MYNEWT_VAL(SHELL_CMD_HELP)
3047 static const struct shell_param phy_set_params[] = {
3048 {"conn", "connection handle, usage: =<UINT16>"},
3049 {"tx_phys_mask", "usage: =<UINT8>"},
3050 {"rx_phys_mask", "usage: =<UINT8>"},
3051 {"phy_opts", "usage: =<UINT16>"},
3052 {NULL, NULL}
3053 };
3054
3055 static const struct shell_cmd_help phy_set_help = {
3056 .summary = "set preferred PHYs",
3057 .usage = NULL,
3058 .params = phy_set_params,
3059 };
3060 #endif
3061
3062 /*****************************************************************************
3063 * $phy-set-default *
3064 *****************************************************************************/
3065
3066 static int
cmd_phy_set_default(int argc,char ** argv)3067 cmd_phy_set_default(int argc, char **argv)
3068 {
3069 uint8_t tx_phys_mask;
3070 uint8_t rx_phys_mask;
3071 int rc;
3072
3073 rc = parse_arg_all(argc - 1, argv + 1);
3074 if (rc != 0) {
3075 return rc;
3076 }
3077
3078 tx_phys_mask = parse_arg_uint8("tx_phys_mask", &rc);
3079 if (rc != 0) {
3080 console_printf("invalid 'tx_phys_mask' parameter\n");
3081 return rc;
3082 }
3083
3084 rx_phys_mask = parse_arg_uint8("rx_phys_mask", &rc);
3085 if (rc != 0) {
3086 console_printf("invalid 'rx_phys_mask' parameter\n");
3087 return rc;
3088 }
3089
3090 return ble_gap_set_prefered_default_le_phy(tx_phys_mask, rx_phys_mask);
3091 }
3092
3093 #if MYNEWT_VAL(SHELL_CMD_HELP)
3094 static const struct shell_param phy_set_default_params[] = {
3095 {"tx_phys_mask", "usage: =<UINT8>"},
3096 {"rx_phys_mask", "usage: =<UINT8>"},
3097 {NULL, NULL}
3098 };
3099
3100 static const struct shell_cmd_help phy_set_default_help = {
3101 .summary = "set preferred default PHYs",
3102 .usage = NULL,
3103 .params = phy_set_default_params,
3104 };
3105 #endif
3106
3107 /*****************************************************************************
3108 * $phy-read *
3109 *****************************************************************************/
3110
3111 static int
cmd_phy_read(int argc,char ** argv)3112 cmd_phy_read(int argc, char **argv)
3113 {
3114 uint16_t conn = 0;
3115 uint8_t tx_phy;
3116 uint8_t rx_phy;
3117 int rc;
3118
3119 rc = parse_arg_all(argc - 1, argv + 1);
3120 if (rc != 0) {
3121 return rc;
3122 }
3123
3124 conn = parse_arg_uint16("conn", &rc);
3125 if (rc != 0) {
3126 console_printf("invalid 'conn' parameter\n");
3127 return rc;
3128 }
3129
3130 rc = ble_gap_read_le_phy(conn, &tx_phy, &rx_phy);
3131 if (rc != 0) {
3132 console_printf("Could not read PHY error: %d\n", rc);
3133 return rc;
3134 }
3135
3136 console_printf("TX_PHY: %d\n", tx_phy);
3137 console_printf("RX_PHY: %d\n", tx_phy);
3138
3139 return 0;
3140 }
3141
3142 #if MYNEWT_VAL(SHELL_CMD_HELP)
3143 static const struct shell_param phy_read_params[] = {
3144 {"conn", "connection handle, usage: =<UINT16>"},
3145 {NULL, NULL}
3146 };
3147
3148 static const struct shell_cmd_help phy_read_help = {
3149 .summary = "read PHYs",
3150 .usage = NULL,
3151 .params = phy_read_params,
3152 };
3153 #endif
3154
3155 /*****************************************************************************
3156 * $host-enable *
3157 *****************************************************************************/
3158
3159 static int
cmd_host_enable(int argc,char ** argv)3160 cmd_host_enable(int argc, char **argv)
3161 {
3162 ble_hs_sched_start();
3163
3164 return 0;
3165 }
3166
3167 #if MYNEWT_VAL(SHELL_CMD_HELP)
3168 static const struct shell_cmd_help host_enable_help = {
3169 .summary = "start the NimBLE host",
3170 .usage = NULL,
3171 .params = NULL,
3172 };
3173 #endif
3174
3175 /*****************************************************************************
3176 * $host-disable *
3177 *****************************************************************************/
3178
3179 static void
on_stop(int status,void * arg)3180 on_stop(int status, void *arg)
3181 {
3182 if (status == 0) {
3183 console_printf("host stopped\n");
3184 } else {
3185 console_printf("host failed to stop; rc=%d\n", status);
3186 }
3187 }
3188
3189 static int
cmd_host_disable(int argc,char ** argv)3190 cmd_host_disable(int argc, char **argv)
3191 {
3192 static struct ble_hs_stop_listener listener;
3193 int rc;
3194
3195 rc = ble_hs_stop(&listener, on_stop, NULL);
3196 return rc;
3197 }
3198
3199 #if MYNEWT_VAL(SHELL_CMD_HELP)
3200 static const struct shell_cmd_help host_disable_help = {
3201 .summary = "stop the NimBLE host",
3202 .usage = NULL,
3203 .params = NULL,
3204 };
3205 #endif
3206
3207 /*****************************************************************************
3208 * $gatt-discover *
3209 *****************************************************************************/
3210
3211 static const struct shell_param gatt_discover_characteristic_params[] = {
3212 {"conn", "connection handle, usage: =<UINT16>"},
3213 {"uuid", "discover by uuid, usage: =[UUID]"},
3214 {"start", "start handle, usage: =<UINT16>"},
3215 {"end", "end handle, usage: =<UINT16>"},
3216 {NULL, NULL}
3217 };
3218
3219 static const struct shell_cmd_help gatt_discover_characteristic_help = {
3220 .summary = "perform characteristic discovery procedure",
3221 .usage = NULL,
3222 .params = gatt_discover_characteristic_params,
3223 };
3224
3225 static const struct shell_param gatt_discover_descriptor_params[] = {
3226 {"conn", "connection handle, usage: =<UINT16>"},
3227 {"start", "start handle, usage: =<UINT16>"},
3228 {"end", "end handle, usage: =<UINT16>"},
3229 {NULL, NULL}
3230 };
3231
3232 static const struct shell_cmd_help gatt_discover_descriptor_help = {
3233 .summary = "perform descriptor discovery procedure",
3234 .usage = NULL,
3235 .params = gatt_discover_descriptor_params,
3236 };
3237
3238 static const struct shell_param gatt_discover_service_params[] = {
3239 {"conn", "connection handle, usage: =<UINT16>"},
3240 {"uuid", "discover by uuid, usage: =[UUID]"},
3241 {NULL, NULL}
3242 };
3243
3244 static const struct shell_cmd_help gatt_discover_service_help = {
3245 .summary = "perform service discovery procedure",
3246 .usage = NULL,
3247 .params = gatt_discover_service_params,
3248 };
3249
3250 static const struct shell_param gatt_discover_full_params[] = {
3251 {"conn", "connection handle, usage: =<UINT16>"},
3252 {NULL, NULL}
3253 };
3254
3255 static const struct shell_cmd_help gatt_discover_full_help = {
3256 .summary = "perform full discovery procedure",
3257 .usage = NULL,
3258 .params = gatt_discover_full_params,
3259 };
3260
3261 /*****************************************************************************
3262 * $gatt-exchange-mtu *
3263 *****************************************************************************/
3264
3265 static const struct shell_param gatt_exchange_mtu_params[] = {
3266 {"conn", "connection handle, usage: =<UINT16>"},
3267 {NULL, NULL}
3268 };
3269
3270 static const struct shell_cmd_help gatt_exchange_mtu_help = {
3271 .summary = "perform mtu exchange procedure",
3272 .usage = NULL,
3273 .params = gatt_exchange_mtu_params,
3274 };
3275
3276 /*****************************************************************************
3277 * $gatt-find-included-services *
3278 *****************************************************************************/
3279
3280 static const struct shell_param gatt_find_included_services_params[] = {
3281 {"conn", "connection handle, usage: =<UINT16>"},
3282 {"start", "start handle, usage: =<UINT16>"},
3283 {"end", "end handle, usage: =<UINT16>"},
3284 {NULL, NULL}
3285 };
3286
3287 static const struct shell_cmd_help gatt_find_included_services_help = {
3288 .summary = "perform find included services procedure",
3289 .usage = NULL,
3290 .params = gatt_find_included_services_params,
3291 };
3292
3293 /*****************************************************************************
3294 * $gatt-notify *
3295 *****************************************************************************/
3296
3297 static const struct shell_param gatt_notify_params[] = {
3298 {"attr", "attribute handle, usage: =<UINT16>"},
3299 {NULL, NULL}
3300 };
3301
3302 static const struct shell_cmd_help gatt_notify_help = {
3303 .summary = "notify about attribute value changed",
3304 .usage = NULL,
3305 .params = gatt_notify_params,
3306 };
3307
3308 /*****************************************************************************
3309 * $gatt-read *
3310 *****************************************************************************/
3311
3312 static const struct shell_param gatt_read_params[] = {
3313 {"conn", "connection handle, usage: =<UINT16>"},
3314 {"long", "is read long, usage: =[0-1], default=0"},
3315 {"attr", "attribute handle, usage: =<UINT16>"},
3316 {"offset", "offset value, usage: =<UINT16>"},
3317 {"uuid", "read by uuid, usage: =[UUID]"},
3318 {"start", "start handle, usage: =<UINT16>"},
3319 {"end", "end handle, usage: =<UINT16>"},
3320 {NULL, NULL}
3321 };
3322
3323 static const struct shell_cmd_help gatt_read_help = {
3324 .summary = "perform gatt read procedure",
3325 .usage = NULL,
3326 .params = gatt_read_params,
3327 };
3328
3329 /*****************************************************************************
3330 * $gatt-service-changed *
3331 *****************************************************************************/
3332
3333 static const struct shell_param gatt_service_changed_params[] = {
3334 {"start", "start handle, usage: =<UINT16>"},
3335 {"end", "end handle, usage: =<UINT16>"},
3336 {NULL, NULL}
3337 };
3338
3339 static const struct shell_cmd_help gatt_service_changed_help = {
3340 .summary = "send service changed indication",
3341 .usage = NULL,
3342 .params = gatt_service_changed_params,
3343 };
3344
3345 /*****************************************************************************
3346 * $gatt-service-visibility *
3347 *****************************************************************************/
3348
3349 static const struct shell_param gatt_service_visibility_params[] = {
3350 {"handle", "usage: =<UINT16>"},
3351 {"visibility", "usage: =<0-1>"},
3352 {NULL, NULL}
3353 };
3354
3355 static const struct shell_cmd_help gatt_service_visibility_help = {
3356 .summary = "change service visibility",
3357 .usage = NULL,
3358 .params = gatt_service_visibility_params,
3359 };
3360
3361 /*****************************************************************************
3362 * $gatt-show *
3363 *****************************************************************************/
3364
3365 static const struct shell_param gatt_show_params[] = {
3366 {NULL, NULL}
3367 };
3368
3369 static const struct shell_cmd_help gatt_show_help = {
3370 .summary = "show discovered gatt database",
3371 .usage = NULL,
3372 .params = gatt_show_params,
3373 };
3374
3375 static const struct shell_cmd_help gatt_show_local_help = {
3376 .summary = "show local gatt database",
3377 .usage = NULL,
3378 .params = gatt_show_params,
3379 };
3380
3381 static const struct shell_cmd_help gatt_show_addr_help = {
3382 .summary = "show device address",
3383 .usage = NULL,
3384 .params = gatt_show_params,
3385 };
3386
3387 static const struct shell_cmd_help gatt_show_conn_help = {
3388 .summary = "show connections information",
3389 .usage = NULL,
3390 .params = gatt_show_params,
3391 };
3392
3393 /*****************************************************************************
3394 * $gatt-write *
3395 *****************************************************************************/
3396
3397 static const struct shell_param gatt_write_params[] = {
3398 {"conn", "connection handle, usage: =<UINT16>"},
3399 {"no_rsp", "write without response, usage: =[0-1], default=0"},
3400 {"long", "is write long, usage: =[0-1], default=0"},
3401 {"attr", "attribute handle, usage: =<UINT16>"},
3402 {"offset", "attribute handle, usage: =<UINT16>"},
3403 {"value", "usage: =<octets>"},
3404 {NULL, NULL}
3405 };
3406
3407 static const struct shell_cmd_help gatt_write_help = {
3408 .summary = "perform gatt write procedure",
3409 .usage = NULL,
3410 .params = gatt_write_params,
3411 };
3412
3413 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
3414 #if MYNEWT_VAL(SHELL_CMD_HELP)
3415 /*****************************************************************************
3416 * $l2cap-update *
3417 *****************************************************************************/
3418
3419 static const struct shell_param l2cap_update_params[] = {
3420 {"conn", "connection handle, usage: =<UINT16>"},
3421 {"interval_min", "usage: =[0-UINT16_MAX], default: 30"},
3422 {"interval_max", "usage: =[0-UINT16_MAX], default: 50"},
3423 {"latency", "usage: =[UINT16], default: 0"},
3424 {"timeout", "usage: =[UINT16], default: 0x0100"},
3425 {NULL, NULL}
3426 };
3427
3428 static const struct shell_cmd_help l2cap_update_help = {
3429 .summary = "update l2cap parameters for connection",
3430 .usage = NULL,
3431 .params = l2cap_update_params,
3432 };
3433
3434 /*****************************************************************************
3435 * $l2cap-create-server *
3436 *****************************************************************************/
3437
3438 static const struct shell_param l2cap_create_server_params[] = {
3439 {"psm", "usage: =<UINT16>"},
3440 {"error", "usage: used for PTS testing:"},
3441 {"", "0 - always accept"},
3442 {"", "1 - reject with insufficient authentication"},
3443 {"", "2 - reject with insufficient authorization"},
3444 {"", "3 - reject with insufficient key size"},
3445 {NULL, NULL}
3446 };
3447
3448 static const struct shell_cmd_help l2cap_create_server_help = {
3449 .summary = "create l2cap server",
3450 .usage = NULL,
3451 .params = l2cap_create_server_params,
3452 };
3453
3454 /*****************************************************************************
3455 * $l2cap-connect *
3456 *****************************************************************************/
3457
3458 static const struct shell_param l2cap_connect_params[] = {
3459 {"conn", "connection handle, usage: =<UINT16>"},
3460 {"psm", "usage: =<UINT16>"},
3461 {NULL, NULL}
3462 };
3463
3464 static const struct shell_cmd_help l2cap_connect_help = {
3465 .summary = "perform l2cap connect procedure",
3466 .usage = NULL,
3467 .params = l2cap_connect_params,
3468 };
3469
3470 /*****************************************************************************
3471 * $l2cap-disconnect *
3472 *****************************************************************************/
3473
3474 static const struct shell_param l2cap_disconnect_params[] = {
3475 {"conn", "connection handle, usage: =<UINT16>"},
3476 {"idx", "usage: =<UINT16>"},
3477 {NULL, NULL}
3478 };
3479
3480 static const struct shell_cmd_help l2cap_disconnect_help = {
3481 .summary = "perform l2cap disconnect procedure",
3482 .usage = "use gatt-show-coc to get the parameters",
3483 .params = l2cap_disconnect_params,
3484 };
3485
3486 /*****************************************************************************
3487 * $l2cap-send *
3488 *****************************************************************************/
3489
3490 static const struct shell_param l2cap_send_params[] = {
3491 {"conn", "connection handle, usage: =<UINT16>"},
3492 {"idx", "usage: =<UINT16>"},
3493 {"bytes", "number of bytes to send, usage: =<UINT16>"},
3494 {NULL, NULL}
3495 };
3496
3497 static const struct shell_cmd_help l2cap_send_help = {
3498 .summary = "perform l2cap send procedure",
3499 .usage = "use l2cap-show-coc to get the parameters",
3500 .params = l2cap_send_params,
3501 };
3502
3503 /*****************************************************************************
3504 * $l2cap-show-coc *
3505 *****************************************************************************/
3506
3507 static const struct shell_param l2cap_show_coc_params[] = {
3508 {NULL, NULL}
3509 };
3510
3511 static const struct shell_cmd_help l2cap_show_coc_help = {
3512 .summary = "show coc information",
3513 .usage = NULL,
3514 .params = l2cap_show_coc_params,
3515 };
3516
3517 #endif
3518 #endif
3519
3520 static const struct shell_cmd btshell_commands[] = {
3521 #if MYNEWT_VAL(BLE_EXT_ADV)
3522 {
3523 .sc_cmd = "advertise-configure",
3524 .sc_cmd_func = cmd_advertise_configure,
3525 #if MYNEWT_VAL(SHELL_CMD_HELP)
3526 .help = &advertise_configure_help,
3527 #endif
3528 },
3529 {
3530 .sc_cmd = "advertise-set-addr",
3531 .sc_cmd_func = cmd_advertise_set_addr,
3532 #if MYNEWT_VAL(SHELL_CMD_HELP)
3533 .help = &advertise_set_addr_help,
3534 #endif
3535 },
3536 {
3537 .sc_cmd = "advertise-set-adv-data",
3538 .sc_cmd_func = cmd_set_adv_data,
3539 #if MYNEWT_VAL(SHELL_CMD_HELP)
3540 .help = &set_adv_data_help,
3541 #endif
3542 },
3543 {
3544 .sc_cmd = "advertise-set-scan-rsp",
3545 .sc_cmd_func = cmd_set_scan_rsp,
3546 #if MYNEWT_VAL(SHELL_CMD_HELP)
3547 .help = &set_scan_rsp_help,
3548 #endif
3549 },
3550 {
3551 .sc_cmd = "advertise-start",
3552 .sc_cmd_func = cmd_advertise_start,
3553 #if MYNEWT_VAL(SHELL_CMD_HELP)
3554 .help = &advertise_start_help,
3555 #endif
3556 },
3557 {
3558 .sc_cmd = "advertise-stop",
3559 .sc_cmd_func = cmd_advertise_stop,
3560 #if MYNEWT_VAL(SHELL_CMD_HELP)
3561 .help = &advertise_stop_help,
3562 #endif
3563 },
3564 {
3565 .sc_cmd = "advertise-remove",
3566 .sc_cmd_func = cmd_advertise_remove,
3567 #if MYNEWT_VAL(SHELL_CMD_HELP)
3568 .help = &advertise_remove_help,
3569 #endif
3570 },
3571 #else
3572 {
3573 .sc_cmd = "advertise",
3574 .sc_cmd_func = cmd_advertise,
3575 #if MYNEWT_VAL(SHELL_CMD_HELP)
3576 .help = &advertise_help,
3577 #endif
3578 },
3579 #endif
3580 {
3581 .sc_cmd = "connect",
3582 .sc_cmd_func = cmd_connect,
3583 #if MYNEWT_VAL(SHELL_CMD_HELP)
3584 .help = &connect_help,
3585 #endif
3586 },
3587 {
3588 .sc_cmd = "disconnect",
3589 .sc_cmd_func = cmd_disconnect,
3590 #if MYNEWT_VAL(SHELL_CMD_HELP)
3591 .help = &disconnect_help,
3592 #endif
3593 },
3594 {
3595 .sc_cmd = "show-addr",
3596 .sc_cmd_func = cmd_show_addr,
3597 #if MYNEWT_VAL(SHELL_CMD_HELP)
3598 .help = &gatt_show_addr_help,
3599 #endif
3600 },
3601 {
3602 .sc_cmd = "show-conn",
3603 .sc_cmd_func = cmd_show_conn,
3604 #if MYNEWT_VAL(SHELL_CMD_HELP)
3605 .help = &gatt_show_conn_help,
3606 #endif
3607 },
3608 {
3609 .sc_cmd = "set-scan-opts",
3610 .sc_cmd_func = cmd_set_scan_opts,
3611 #if MYNEWT_VAL(SHELL_CMD_HELP)
3612 .help = &set_scan_opts_help,
3613 #endif
3614 },
3615 {
3616 .sc_cmd = "scan",
3617 .sc_cmd_func = cmd_scan,
3618 #if MYNEWT_VAL(SHELL_CMD_HELP)
3619 .help = &scan_help,
3620 #endif
3621 },
3622 {
3623 .sc_cmd = "set",
3624 .sc_cmd_func = cmd_set,
3625 #if MYNEWT_VAL(SHELL_CMD_HELP)
3626 .help = &set_help,
3627 #endif
3628 },
3629 #if !MYNEWT_VAL(BLE_EXT_ADV)
3630 {
3631 .sc_cmd = "set-adv-data",
3632 .sc_cmd_func = cmd_set_adv_data,
3633 #if MYNEWT_VAL(SHELL_CMD_HELP)
3634 .help = &set_adv_data_help,
3635 #endif
3636 },
3637 {
3638 .sc_cmd = "set-scan-rsp",
3639 .sc_cmd_func = cmd_set_scan_rsp,
3640 #if MYNEWT_VAL(SHELL_CMD_HELP)
3641 .help = &set_scan_rsp_help,
3642 #endif
3643 },
3644 #endif
3645 {
3646 .sc_cmd = "set-priv-mode",
3647 .sc_cmd_func = cmd_set_priv_mode,
3648 #if MYNEWT_VAL(SHELL_CMD_HELP)
3649 .help = &set_priv_mode_help,
3650 #endif
3651 },
3652 {
3653 .sc_cmd = "white-list",
3654 .sc_cmd_func = cmd_white_list,
3655 #if MYNEWT_VAL(SHELL_CMD_HELP)
3656 .help = &white_list_help,
3657 #endif
3658 },
3659 {
3660 .sc_cmd = "conn-rssi",
3661 .sc_cmd_func = cmd_conn_rssi,
3662 #if MYNEWT_VAL(SHELL_CMD_HELP)
3663 .help = &conn_rssi_help,
3664 #endif
3665 },
3666 {
3667 .sc_cmd = "conn-update-params",
3668 .sc_cmd_func = cmd_conn_update_params,
3669 #if MYNEWT_VAL(SHELL_CMD_HELP)
3670 .help = &conn_update_params_help,
3671 #endif
3672 },
3673 {
3674 .sc_cmd = "conn-datalen",
3675 .sc_cmd_func = cmd_conn_datalen,
3676 #if MYNEWT_VAL(SHELL_CMD_HELP)
3677 .help = &conn_datalen_help,
3678 #endif
3679 },
3680 {
3681 .sc_cmd = "gatt-discover-characteristic",
3682 .sc_cmd_func = cmd_gatt_discover_characteristic,
3683 #if MYNEWT_VAL(SHELL_CMD_HELP)
3684 .help = &gatt_discover_characteristic_help,
3685 #endif
3686 },
3687 {
3688 .sc_cmd = "gatt-discover-descriptor",
3689 .sc_cmd_func = cmd_gatt_discover_descriptor,
3690 #if MYNEWT_VAL(SHELL_CMD_HELP)
3691 .help = &gatt_discover_descriptor_help,
3692 #endif
3693 },
3694 {
3695 .sc_cmd = "gatt-discover-service",
3696 .sc_cmd_func = cmd_gatt_discover_service,
3697 #if MYNEWT_VAL(SHELL_CMD_HELP)
3698 .help = &gatt_discover_service_help,
3699 #endif
3700 },
3701 {
3702 .sc_cmd = "gatt-discover-full",
3703 .sc_cmd_func = cmd_gatt_discover_full,
3704 #if MYNEWT_VAL(SHELL_CMD_HELP)
3705 .help = &gatt_discover_full_help,
3706 #endif
3707 },
3708 {
3709 .sc_cmd = "gatt-find-included-services",
3710 .sc_cmd_func = cmd_gatt_find_included_services,
3711 #if MYNEWT_VAL(SHELL_CMD_HELP)
3712 .help = &gatt_find_included_services_help,
3713 #endif
3714 },
3715 {
3716 .sc_cmd = "gatt-exchange-mtu",
3717 .sc_cmd_func = cmd_gatt_exchange_mtu,
3718 #if MYNEWT_VAL(SHELL_CMD_HELP)
3719 .help = &gatt_exchange_mtu_help,
3720 #endif
3721 },
3722 {
3723 .sc_cmd = "gatt-read",
3724 .sc_cmd_func = cmd_gatt_read,
3725 #if MYNEWT_VAL(SHELL_CMD_HELP)
3726 .help = &gatt_read_help,
3727 #endif
3728 },
3729 {
3730 .sc_cmd = "gatt-notify",
3731 .sc_cmd_func = cmd_gatt_notify,
3732 #if MYNEWT_VAL(SHELL_CMD_HELP)
3733 .help = &gatt_notify_help,
3734 #endif
3735 },
3736 {
3737 .sc_cmd = "gatt-service-changed",
3738 .sc_cmd_func = cmd_gatt_service_changed,
3739 #if MYNEWT_VAL(SHELL_CMD_HELP)
3740 .help = &gatt_service_changed_help,
3741 #endif
3742 },
3743 {
3744 .sc_cmd = "gatt-service-visibility",
3745 .sc_cmd_func = cmd_gatt_service_visibility,
3746 #if MYNEWT_VAL(SHELL_CMD_HELP)
3747 .help = &gatt_service_visibility_help,
3748 #endif
3749 },
3750 {
3751 .sc_cmd = "gatt-show",
3752 .sc_cmd_func = cmd_gatt_show,
3753 #if MYNEWT_VAL(SHELL_CMD_HELP)
3754 .help = &gatt_show_help,
3755 #endif
3756 },
3757 {
3758 .sc_cmd = "gatt-show-local",
3759 .sc_cmd_func = cmd_gatt_show_local,
3760 #if MYNEWT_VAL(SHELL_CMD_HELP)
3761 .help = &gatt_show_local_help,
3762 #endif
3763 },
3764 {
3765 .sc_cmd = "gatt-write",
3766 .sc_cmd_func = cmd_gatt_write,
3767 #if MYNEWT_VAL(SHELL_CMD_HELP)
3768 .help = &gatt_write_help,
3769 #endif
3770 },
3771 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
3772 {
3773 .sc_cmd = "l2cap-update",
3774 .sc_cmd_func = cmd_l2cap_update,
3775 #if MYNEWT_VAL(SHELL_CMD_HELP)
3776 .help = &l2cap_update_help,
3777 #endif
3778 },
3779 {
3780 .sc_cmd = "l2cap-create-server",
3781 .sc_cmd_func = cmd_l2cap_create_server,
3782 #if MYNEWT_VAL(SHELL_CMD_HELP)
3783 .help = &l2cap_create_server_help,
3784 #endif
3785 },
3786 {
3787 .sc_cmd = "l2cap-connect",
3788 .sc_cmd_func = cmd_l2cap_connect,
3789 #if MYNEWT_VAL(SHELL_CMD_HELP)
3790 .help = &l2cap_connect_help,
3791 #endif
3792 },
3793 {
3794 .sc_cmd = "l2cap-disconnect",
3795 .sc_cmd_func = cmd_l2cap_disconnect,
3796 #if MYNEWT_VAL(SHELL_CMD_HELP)
3797 .help = &l2cap_disconnect_help,
3798 #endif
3799 },
3800 {
3801 .sc_cmd = "l2cap-send",
3802 .sc_cmd_func = cmd_l2cap_send,
3803 #if MYNEWT_VAL(SHELL_CMD_HELP)
3804 .help = &l2cap_send_help,
3805 #endif
3806 },
3807 {
3808 .sc_cmd = "l2cap-show-coc",
3809 .sc_cmd_func = cmd_l2cap_show_coc,
3810 #if MYNEWT_VAL(SHELL_CMD_HELP)
3811 .help = &l2cap_show_coc_help,
3812 #endif
3813 },
3814 #endif
3815 {
3816 .sc_cmd = "keystore-add",
3817 .sc_cmd_func = cmd_keystore_add,
3818 #if MYNEWT_VAL(SHELL_CMD_HELP)
3819 .help = &keystore_add_help,
3820 #endif
3821 },
3822 {
3823 .sc_cmd = "keystore-del",
3824 .sc_cmd_func = cmd_keystore_del,
3825 #if MYNEWT_VAL(SHELL_CMD_HELP)
3826 .help = &keystore_del_help,
3827 #endif
3828 },
3829 {
3830 .sc_cmd = "keystore-show",
3831 .sc_cmd_func = cmd_keystore_show,
3832 #if MYNEWT_VAL(SHELL_CMD_HELP)
3833 .help = &keystore_show_help,
3834 #endif
3835 },
3836 #if NIMBLE_BLE_SM
3837 {
3838 .sc_cmd = "auth-passkey",
3839 .sc_cmd_func = cmd_auth_passkey,
3840 #if MYNEWT_VAL(SHELL_CMD_HELP)
3841 .help = &auth_passkey_help,
3842 #endif
3843 },
3844 {
3845 .sc_cmd = "security-pair",
3846 .sc_cmd_func = cmd_security_pair,
3847 #if MYNEWT_VAL(SHELL_CMD_HELP)
3848 .help = &security_pair_help,
3849 #endif
3850 },
3851 {
3852 .sc_cmd = "security-unpair",
3853 .sc_cmd_func = cmd_security_unpair,
3854 #if MYNEWT_VAL(SHELL_CMD_HELP)
3855 .help = &security_unpair_help,
3856 #endif
3857 },
3858 {
3859 .sc_cmd = "security-start",
3860 .sc_cmd_func = cmd_security_start,
3861 #if MYNEWT_VAL(SHELL_CMD_HELP)
3862 .help = &security_start_help,
3863 #endif
3864 },
3865 {
3866 .sc_cmd = "security-encryption",
3867 .sc_cmd_func = cmd_security_encryption,
3868 #if MYNEWT_VAL(SHELL_CMD_HELP)
3869 .help = &security_encryption_help,
3870 #endif
3871 },
3872 {
3873 .sc_cmd = "security-set-data",
3874 .sc_cmd_func = cmd_security_set_data,
3875 #if MYNEWT_VAL(SHELL_CMD_HELP)
3876 .help = &security_set_data_help,
3877 #endif
3878 },
3879 #endif
3880 {
3881 .sc_cmd = "test-tx",
3882 .sc_cmd_func = cmd_test_tx,
3883 #if MYNEWT_VAL(SHELL_CMD_HELP)
3884 .help = &test_tx_help,
3885 #endif
3886 },
3887 {
3888 .sc_cmd = "phy-set",
3889 .sc_cmd_func = cmd_phy_set,
3890 #if MYNEWT_VAL(SHELL_CMD_HELP)
3891 .help = &phy_set_help,
3892 #endif
3893 },
3894 {
3895 .sc_cmd = "phy-set-default",
3896 .sc_cmd_func = cmd_phy_set_default,
3897 #if MYNEWT_VAL(SHELL_CMD_HELP)
3898 .help = &phy_set_default_help,
3899 #endif
3900 },
3901 {
3902 .sc_cmd = "phy-read",
3903 .sc_cmd_func = cmd_phy_read,
3904 #if MYNEWT_VAL(SHELL_CMD_HELP)
3905 .help = &phy_read_help,
3906 #endif
3907 },
3908 {
3909 .sc_cmd = "host-enable",
3910 .sc_cmd_func = cmd_host_enable,
3911 #if MYNEWT_VAL(SHELL_CMD_HELP)
3912 .help = &host_enable_help,
3913 #endif
3914 },
3915 {
3916 .sc_cmd = "host-disable",
3917 .sc_cmd_func = cmd_host_disable,
3918 #if MYNEWT_VAL(SHELL_CMD_HELP)
3919 .help = &host_disable_help,
3920 #endif
3921 },
3922 { NULL, NULL, NULL },
3923 };
3924
3925
3926 void
cmd_init(void)3927 cmd_init(void)
3928 {
3929 shell_register(BTSHELL_MODULE, btshell_commands);
3930 shell_register_default_module(BTSHELL_MODULE);
3931 }
3932