xref: /nrf52832-nimble/packages/NimBLE-latest/apps/btshell/src/cmd.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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(&params, 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, &params, &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                            &params, 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, &params, &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, &params);
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