xref: /freebsd/usr.sbin/bluetooth/hccontrol/le.c (revision 2c6feab253297c21d00601ceef818fcbe4da70d8)
1 /*
2  * le.c
3  *
4  * Copyright (c) 2015 Takanori Watanabe <takawata@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $
29  */
30 
31 #include <sys/types.h>
32 #include <sys/ioctl.h>
33 #include <sys/sysctl.h>
34 #include <sys/select.h>
35 #include <assert.h>
36 #include <bitstring.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <netgraph/ng_message.h>
40 #include <errno.h>
41 #include <stdbool.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <stdint.h>
47 #define L2CAP_SOCKET_CHECKED
48 #include <bluetooth.h>
49 #include "hccontrol.h"
50 
51 static int le_set_scan_param(int s, int argc, char *argv[]);
52 static int le_set_scan_enable(int s, int argc, char *argv[]);
53 static int parse_param(int argc, char *argv[], char *buf, int *len);
54 static int le_set_scan_response(int s, int argc, char *argv[]);
55 static int le_read_supported_states(int s, int argc, char *argv[]);
56 static int le_read_local_supported_features(int s, int argc ,char *argv[]);
57 static int set_le_event_mask(int s, uint64_t mask);
58 static int set_event_mask(int s, uint64_t mask);
59 static int le_enable(int s, int argc, char *argv[]);
60 static int le_set_advertising_enable(int s, int argc, char *argv[]);
61 static int le_set_advertising_param(int s, int argc, char *argv[]);
62 static int le_read_advertising_channel_tx_power(int s, int argc, char *argv[]);
63 static int le_scan(int s, int argc, char *argv[]);
64 static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose);
65 static int le_read_white_list_size(int s, int argc, char *argv[]);
66 static int le_clear_white_list(int s, int argc, char *argv[]);
67 static int le_add_device_to_white_list(int s, int argc, char *argv[]);
68 static int le_remove_device_from_white_list(int s, int argc, char *argv[]);
69 static int le_connect(int s, int argc, char *argv[]);
70 static void handle_le_connection_event(ng_hci_event_pkt_t* e, bool verbose);
71 static int le_read_channel_map(int s, int argc, char *argv[]);
72 static void handle_le_remote_features_event(ng_hci_event_pkt_t* e);
73 static int le_rand(int s, int argc, char *argv[]);
74 
75 static int
le_set_scan_param(int s,int argc,char * argv[])76 le_set_scan_param(int s, int argc, char *argv[])
77 {
78 	int type;
79 	int interval;
80 	int window;
81 	int adrtype;
82 	int policy;
83 	int n;
84 
85 	ng_hci_le_set_scan_parameters_cp cp;
86 	ng_hci_le_set_scan_parameters_rp rp;
87 
88 	if (argc != 5)
89 		return (USAGE);
90 
91 	if (strcmp(argv[0], "active") == 0)
92 		type = 1;
93 	else if (strcmp(argv[0], "passive") == 0)
94 		type = 0;
95 	else
96 		return (USAGE);
97 
98 	interval = (int)(atof(argv[1])/0.625);
99 	interval = (interval < 4)? 4: interval;
100 	window = (int)(atof(argv[2])/0.625);
101 	window = (window < 4) ? 4 : interval;
102 
103 	if (strcmp(argv[3], "public") == 0)
104 		adrtype = 0;
105 	else if (strcmp(argv[3], "random") == 0)
106 		adrtype = 1;
107 	else
108 		return (USAGE);
109 
110 	if (strcmp(argv[4], "all") == 0)
111 		policy = 0;
112 	else if (strcmp(argv[4], "whitelist") == 0)
113 		policy = 1;
114 	else
115 		return (USAGE);
116 
117 	cp.le_scan_type = type;
118 	cp.le_scan_interval = interval;
119 	cp.own_address_type = adrtype;
120 	cp.le_scan_window = window;
121 	cp.scanning_filter_policy = policy;
122 	n = sizeof(rp);
123 
124 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
125 		NG_HCI_OCF_LE_SET_SCAN_PARAMETERS),
126 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
127 		return (ERROR);
128 
129 	if (rp.status != 0x00) {
130 		fprintf(stdout, "Status: %s [%#02x]\n",
131 			hci_status2str(rp.status), rp.status);
132 		return (FAILED);
133 	}
134 
135 	return (OK);
136 }
137 
138 static int
le_set_scan_enable(int s,int argc,char * argv[])139 le_set_scan_enable(int s, int argc, char *argv[])
140 {
141 	ng_hci_le_set_scan_enable_cp cp;
142 	ng_hci_le_set_scan_enable_rp rp;
143 	int n, enable = 0;
144 
145 	if (argc != 1)
146 		return (USAGE);
147 
148 	if (strcmp(argv[0], "enable") == 0)
149 		enable = 1;
150 	else if (strcmp(argv[0], "disable") != 0)
151 		return (USAGE);
152 
153 	n = sizeof(rp);
154 	cp.le_scan_enable = enable;
155 	cp.filter_duplicates = 0;
156 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
157 		NG_HCI_OCF_LE_SET_SCAN_ENABLE),
158 		(void *)&cp, sizeof(cp),
159 		(void *)&rp, &n) == ERROR)
160 		return (ERROR);
161 
162 	if (rp.status != 0x00) {
163 		fprintf(stdout, "Status: %s [%#02x]\n",
164 			hci_status2str(rp.status), rp.status);
165 		return (FAILED);
166 	}
167 
168 	fprintf(stdout, "LE Scan: %s\n",
169 		enable? "Enabled" : "Disabled");
170 
171 	return (OK);
172 }
173 
174 static int
parse_param(int argc,char * argv[],char * buf,int * len)175 parse_param(int argc, char *argv[], char *buf, int *len)
176 {
177 	char *buflast  =  buf + (*len);
178 	char *curbuf = buf;
179 	char *token,*lenpos;
180 	int ch;
181 	int datalen;
182 	uint16_t value;
183 	optreset = 1;
184 	optind = 0;
185 	while ((ch = getopt(argc, argv , "n:f:u:b:")) != -1) {
186 		switch(ch){
187 		case 'n':
188 			datalen = strlen(optarg);
189 			if ((curbuf + datalen + 2) >= buflast)
190 				goto done;
191 			curbuf[0] = datalen + 1;
192 			curbuf[1] = 8;
193 			curbuf += 2;
194 			memcpy(curbuf, optarg, datalen);
195 			curbuf += datalen;
196 			break;
197 		case 'f':
198 			if (curbuf+3 > buflast)
199 				goto done;
200 			curbuf[0] = 2;
201 			curbuf[1] = 1;
202 			curbuf[2] = (uint8_t)strtol(optarg, NULL, 16);
203 			curbuf += 3;
204 			break;
205 		case 'u':
206 			if ((buf+2) >= buflast)
207 				goto done;
208 			lenpos = curbuf;
209 			curbuf[1] = 2;
210 			*lenpos = 1;
211 			curbuf += 2;
212 			while ((token = strsep(&optarg, ",")) != NULL) {
213 				value = strtol(token, NULL, 16);
214 				if ((curbuf+2) >= buflast)
215 					break;
216 				curbuf[0] = value &0xff;
217 				curbuf[1] = (value>>8)&0xff;
218 				curbuf += 2;
219 				*lenpos += 2;
220 			}
221 			break;
222 		case 'b':
223 			datalen = 1;
224 			token = optarg;
225 			while ((token = strchr(token, ',')) != NULL) {
226 				datalen++;
227 				token++;
228 			}
229 			if ((curbuf + datalen + 1) >= buflast)
230 				goto done;
231 			curbuf[0] = datalen;
232 			curbuf++;
233 			token = optarg;
234 			while ((token = strsep(&optarg, ",")) != NULL) {
235 				value = strtol(token, NULL, 16);
236 				curbuf[0] = value & 0xff;
237 				curbuf++;
238 			}
239 		}
240 	}
241 done:
242 	*len = curbuf - buf;
243 
244 	return (OK);
245 }
246 
247 static int
le_set_scan_response(int s,int argc,char * argv[])248 le_set_scan_response(int s, int argc, char *argv[])
249 {
250 	ng_hci_le_set_scan_response_data_cp cp;
251 	ng_hci_le_set_scan_response_data_rp rp;
252 	int n;
253 	int len;
254 	char buf[NG_HCI_ADVERTISING_DATA_SIZE];
255 
256 	len = sizeof(buf);
257 	parse_param(argc, argv, buf, &len);
258 	memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data));
259 	cp.scan_response_data_length = len;
260 	memcpy(cp.scan_response_data, buf, len);
261 	n = sizeof(rp);
262 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
263 			NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA),
264 			(void *)&cp, sizeof(cp),
265 			(void *)&rp, &n) == ERROR)
266 		return (ERROR);
267 
268 	if (rp.status != 0x00) {
269 		fprintf(stdout, "Status: %s [%#02x]\n",
270 			hci_status2str(rp.status), rp.status);
271 		return (FAILED);
272 	}
273 
274 	return (OK);
275 }
276 
277 static int
le_read_local_supported_features(int s,int argc,char * argv[])278 le_read_local_supported_features(int s, int argc ,char *argv[])
279 {
280 	ng_hci_le_read_local_supported_features_rp rp;
281 	int n = sizeof(rp);
282 
283 	union {
284 		uint64_t raw;
285 		uint8_t octets[8];
286 	} le_features;
287 
288 	char buffer[2048];
289 
290 	if (hci_simple_request(s,
291 			NG_HCI_OPCODE(NG_HCI_OGF_LE,
292 			NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES),
293 			(void *)&rp, &n) == ERROR)
294 		return (ERROR);
295 
296 	if (rp.status != 0x00) {
297 		fprintf(stdout, "Status: %s [%#02x]\n",
298 			hci_status2str(rp.status), rp.status);
299 		return (FAILED);
300 	}
301 
302 	le_features.raw = rp.le_features;
303 
304 	fprintf(stdout, "LE Features: ");
305 	for(int i = 0; i < 8; i++)
306                 fprintf(stdout, " %#02x", le_features.octets[i]);
307 	fprintf(stdout, "\n%s\n", hci_le_features2str(le_features.octets,
308 		buffer, sizeof(buffer)));
309 	fprintf(stdout, "\n");
310 
311 	return (OK);
312 }
313 
314 static int
le_read_supported_states(int s,int argc,char * argv[])315 le_read_supported_states(int s, int argc, char *argv[])
316 {
317 	ng_hci_le_read_supported_states_rp rp;
318 	int n = sizeof(rp);
319 
320 	if (hci_simple_request(s, NG_HCI_OPCODE(
321 					NG_HCI_OGF_LE,
322 					NG_HCI_OCF_LE_READ_SUPPORTED_STATES),
323 			       		(void *)&rp, &n) == ERROR)
324 		return (ERROR);
325 
326 	if (rp.status != 0x00) {
327 		fprintf(stdout, "Status: %s [%#02x]\n",
328 			hci_status2str(rp.status), rp.status);
329 		return (FAILED);
330 	}
331 
332 	fprintf(stdout, "LE States: %jx\n", rp.le_states);
333 
334 	return (OK);
335 }
336 
337 static int
set_le_event_mask(int s,uint64_t mask)338 set_le_event_mask(int s, uint64_t mask)
339 {
340 	ng_hci_le_set_event_mask_cp semc;
341 	ng_hci_le_set_event_mask_rp rp;
342 	int i, n;
343 
344 	n = sizeof(rp);
345 
346 	for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) {
347 		semc.event_mask[i] = mask&0xff;
348 		mask >>= 8;
349 	}
350 	if(hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
351 			NG_HCI_OCF_LE_SET_EVENT_MASK),
352 			(void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR)
353 		return (ERROR);
354 
355 	if (rp.status != 0x00) {
356 		fprintf(stdout, "Status: %s [%#02x]\n",
357 			hci_status2str(rp.status), rp.status);
358 		return (FAILED);
359 	}
360 
361 	return (OK);
362 }
363 
364 static int
set_event_mask(int s,uint64_t mask)365 set_event_mask(int s, uint64_t mask)
366 {
367 	ng_hci_set_event_mask_cp semc;
368 	ng_hci_set_event_mask_rp rp;
369 	int i, n;
370 
371 	n = sizeof(rp);
372 
373 	for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) {
374 		semc.event_mask[i] = mask&0xff;
375 		mask >>= 8;
376 	}
377 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
378 			NG_HCI_OCF_SET_EVENT_MASK),
379 			(void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR)
380 		return (ERROR);
381 
382 	if (rp.status != 0x00) {
383 		fprintf(stdout, "Status: %s [%#02x]\n",
384 			hci_status2str(rp.status), rp.status);
385 		return (FAILED);
386 	}
387 
388 	return (OK);
389 }
390 
391 static
le_enable(int s,int argc,char * argv[])392 int le_enable(int s, int argc, char *argv[])
393 {
394         int result;
395 
396 	if (argc != 1)
397 		return (USAGE);
398 
399 	if (strcasecmp(argv[0], "enable") == 0) {
400 		result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT |
401 			       NG_HCI_EVENT_MASK_LE);
402 		if (result != OK)
403 			return result;
404 		result = set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL);
405 		if (result == OK) {
406 			fprintf(stdout, "LE enabled\n");
407 			return (OK);
408 		} else
409 			return result;
410 	} else if (strcasecmp(argv[0], "disable") == 0) {
411 		result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT);
412 		if (result == OK) {
413 			fprintf(stdout, "LE disabled\n");
414 			return (OK);
415 		} else
416 			return result;
417 	} else
418 		return (USAGE);
419 }
420 
421 static int
le_set_advertising_enable(int s,int argc,char * argv[])422 le_set_advertising_enable(int s, int argc, char *argv[])
423 {
424 	ng_hci_le_set_advertise_enable_cp cp;
425 	ng_hci_le_set_advertise_enable_rp rp;
426 	int n, enable = 0;
427 
428 	if (argc != 1)
429 		return USAGE;
430 
431 	if (strcmp(argv[0], "enable") == 0)
432 		enable = 1;
433 	else if (strcmp(argv[0], "disable") != 0)
434 		return USAGE;
435 
436 	n = sizeof(rp);
437 	cp.advertising_enable = enable;
438 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
439 		NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE),
440 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
441 		return (ERROR);
442 
443 	if (rp.status != 0x00) {
444 		fprintf(stdout, "Status: %s [%#02x]\n",
445 			hci_status2str(rp.status), rp.status);
446 		return (FAILED);
447 	}
448         fprintf(stdout, "LE Advertising %s\n", (enable ? "enabled" : "disabled"));
449 
450 	return (OK);
451 }
452 
453 static int
le_set_advertising_param(int s,int argc,char * argv[])454 le_set_advertising_param(int s, int argc, char *argv[])
455 {
456 	ng_hci_le_set_advertising_parameters_cp cp;
457 	ng_hci_le_set_advertising_parameters_rp rp;
458 
459 	int n, ch;
460 
461 	cp.advertising_interval_min = 0x800;
462 	cp.advertising_interval_max = 0x800;
463 	cp.advertising_type = 0;
464 	cp.own_address_type = 0;
465 	cp.direct_address_type = 0;
466 
467 	cp.advertising_channel_map = 7;
468 	cp.advertising_filter_policy = 0;
469 
470 	optreset = 1;
471 	optind = 0;
472 	while ((ch = getopt(argc, argv , "m:M:t:o:p:a:c:f:")) != -1) {
473 		switch(ch) {
474 		case 'm':
475 			cp.advertising_interval_min =
476 				(uint16_t)(strtod(optarg, NULL)/0.625);
477 			break;
478 		case 'M':
479 			cp.advertising_interval_max =
480 				(uint16_t)(strtod(optarg, NULL)/0.625);
481 			break;
482 		case 't':
483 			cp.advertising_type =
484 				(uint8_t)strtod(optarg, NULL);
485 			break;
486 		case 'o':
487 			cp.own_address_type =
488 				(uint8_t)strtod(optarg, NULL);
489 			break;
490 		case 'p':
491 			cp.direct_address_type =
492 				(uint8_t)strtod(optarg, NULL);
493 			break;
494 		case 'a':
495 			if (!bt_aton(optarg, &cp.direct_address)) {
496 				struct hostent	*he = NULL;
497 
498 				if ((he = bt_gethostbyname(optarg)) == NULL)
499 					return (USAGE);
500 
501 				memcpy(&cp.direct_address, he->h_addr, sizeof(cp.direct_address));
502 			}
503 			break;
504 		case 'c':
505 			cp.advertising_channel_map =
506 				(uint8_t)strtod(optarg, NULL);
507 			break;
508 		case 'f':
509 			cp.advertising_filter_policy =
510 				(uint8_t)strtod(optarg, NULL);
511 			break;
512 		}
513 	}
514 
515 	n = sizeof(rp);
516 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
517 		NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS),
518 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
519 		return (ERROR);
520 
521 	if (rp.status != 0x00) {
522 		fprintf(stdout, "Status: %s [%#02x]\n",
523 			hci_status2str(rp.status), rp.status);
524 		return (FAILED);
525 	}
526 
527 	return (OK);
528 }
529 
530 static int
le_read_advertising_channel_tx_power(int s,int argc,char * argv[])531 le_read_advertising_channel_tx_power(int s, int argc, char *argv[])
532 {
533 	ng_hci_le_read_advertising_channel_tx_power_rp rp;
534 	int n;
535 
536 	n = sizeof(rp);
537 
538 	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
539 		NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER),
540 		(void *)&rp, &n) == ERROR)
541 		return (ERROR);
542 
543 	if (rp.status != 0x00) {
544 		fprintf(stdout, "Status: %s [%#02x]\n",
545 			hci_status2str(rp.status), rp.status);
546 		return (FAILED);
547 	}
548 
549         fprintf(stdout, "Advertising transmit power level: %d dBm\n",
550 		(int8_t)rp.transmit_power_level);
551 
552 	return (OK);
553 }
554 
555 static int
le_set_advertising_data(int s,int argc,char * argv[])556 le_set_advertising_data(int s, int argc, char *argv[])
557 {
558 	ng_hci_le_set_advertising_data_cp cp;
559 	ng_hci_le_set_advertising_data_rp rp;
560 	int n, len;
561 
562 	n = sizeof(rp);
563 
564 	char buf[NG_HCI_ADVERTISING_DATA_SIZE];
565 
566 	len = sizeof(buf);
567 	parse_param(argc, argv, buf, &len);
568 	memset(cp.advertising_data, 0, sizeof(cp.advertising_data));
569 	cp.advertising_data_length = len;
570 	memcpy(cp.advertising_data, buf, len);
571 
572 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
573 		NG_HCI_OCF_LE_SET_ADVERTISING_DATA),
574 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
575 		return (ERROR);
576 
577 	if (rp.status != 0x00) {
578 		fprintf(stdout, "Status: %s [%#02x]\n",
579 			hci_status2str(rp.status), rp.status);
580 		return (FAILED);
581 	}
582 
583 	return (OK);
584 }
585 static int
le_read_buffer_size(int s,int argc,char * argv[])586 le_read_buffer_size(int s, int argc, char *argv[])
587 {
588 	union {
589 		ng_hci_le_read_buffer_size_rp 		v1;
590 		ng_hci_le_read_buffer_size_rp_v2	v2;
591 	} rp;
592 
593 	int n, ch;
594 	uint8_t v;
595 	uint16_t cmd;
596 
597 	optreset = 1;
598 	optind = 0;
599 
600 	/* Default to version 1*/
601 	v = 1;
602 	cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE;
603 
604 	while ((ch = getopt(argc, argv , "v:")) != -1) {
605 		switch(ch) {
606 		case 'v':
607 			v = (uint8_t)strtol(optarg, NULL, 16);
608 			if (v == 2)
609 				cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE_V2;
610 			else if (v > 2)
611 				return (USAGE);
612 			break;
613 		default:
614 			v = 1;
615 		}
616 	}
617 
618 	n = sizeof(rp);
619 	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, cmd),
620 		(void *)&rp, &n) == ERROR)
621 		return (ERROR);
622 
623 	if (rp.v1.status != 0x00) {
624 		fprintf(stdout, "Status: %s [%#02x]\n",
625 			hci_status2str(rp.v1.status), rp.v1.status);
626 		return (FAILED);
627 	}
628 
629 	fprintf(stdout, "ACL data packet length: %d\n",
630 		rp.v1.hc_le_data_packet_length);
631 	fprintf(stdout, "Number of ACL data packets: %d\n",
632 		rp.v1.hc_total_num_le_data_packets);
633 
634 	if (v == 2) {
635 		fprintf(stdout, "ISO data packet length: %d\n",
636 			rp.v2.hc_iso_data_packet_length);
637 		fprintf(stdout, "Number of ISO data packets: %d\n",
638 			rp.v2.hc_total_num_iso_data_packets);
639 	}
640 
641 	return (OK);
642 }
643 
644 static int
le_scan(int s,int argc,char * argv[])645 le_scan(int s, int argc, char *argv[])
646 {
647 	int n, bufsize, scancount, numscans;
648 	bool verbose;
649 	uint8_t active = 0;
650 	char ch;
651 
652 	char			 b[512];
653 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
654 
655 	ng_hci_le_set_scan_parameters_cp scan_param_cp;
656 	ng_hci_le_set_scan_parameters_rp scan_param_rp;
657 
658 	ng_hci_le_set_scan_enable_cp scan_enable_cp;
659 	ng_hci_le_set_scan_enable_rp scan_enable_rp;
660 
661 	optreset = 1;
662 	optind = 0;
663 	verbose = false;
664 	numscans = 1;
665 
666 	while ((ch = getopt(argc, argv , "an:v")) != -1) {
667 		switch(ch) {
668 		case 'a':
669 			active = 1;
670 			break;
671 		case 'n':
672 			numscans = (uint8_t)strtol(optarg, NULL, 10);
673 			break;
674 		case 'v':
675 			verbose = true;
676 			break;
677 		}
678 	}
679 
680 	scan_param_cp.le_scan_type = active;
681 	scan_param_cp.le_scan_interval = (uint16_t)(100/0.625);
682 	scan_param_cp.le_scan_window = (uint16_t)(50/0.625);
683 	/* Address type public */
684 	scan_param_cp.own_address_type = 0;
685 	/* 'All' filter policy */
686 	scan_param_cp.scanning_filter_policy = 0;
687 	n = sizeof(scan_param_rp);
688 
689 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
690 		NG_HCI_OCF_LE_SET_SCAN_PARAMETERS),
691 		(void *)&scan_param_cp, sizeof(scan_param_cp),
692 		(void *)&scan_param_rp, &n) == ERROR)
693 		return (ERROR);
694 
695 	if (scan_param_rp.status != 0x00) {
696 		fprintf(stdout, "LE_Set_Scan_Parameters failed. Status: %s [%#02x]\n",
697 			hci_status2str(scan_param_rp.status),
698 			scan_param_rp.status);
699 		return (FAILED);
700 	}
701 
702 	/* Enable scanning */
703 	n = sizeof(scan_enable_rp);
704 	scan_enable_cp.le_scan_enable = 1;
705 	scan_enable_cp.filter_duplicates = 1;
706 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
707 		NG_HCI_OCF_LE_SET_SCAN_ENABLE),
708 		(void *)&scan_enable_cp, sizeof(scan_enable_cp),
709 		(void *)&scan_enable_rp, &n) == ERROR)
710 		return (ERROR);
711 
712 	if (scan_enable_rp.status != 0x00) {
713 		fprintf(stdout, "LE_Scan_Enable enable failed. Status: %s [%#02x]\n",
714 			hci_status2str(scan_enable_rp.status),
715 			scan_enable_rp.status);
716 		return (FAILED);
717 	}
718 
719 	scancount = 0;
720 	while (scancount < numscans) {
721 		/* wait for scan events */
722 		bufsize = sizeof(b);
723 		if (hci_recv(s, b, &bufsize) == ERROR) {
724 			return (ERROR);
725 		}
726 
727 		if (bufsize < sizeof(*e)) {
728 			errno = EIO;
729 			return (ERROR);
730 		}
731 		scancount++;
732 		if (e->event == NG_HCI_EVENT_LE) {
733 		 	fprintf(stdout, "Scan %d\n", scancount);
734 			handle_le_event(e, verbose);
735 		}
736 	}
737 
738 	fprintf(stdout, "Scan complete\n");
739 
740 	/* Disable scanning */
741 	n = sizeof(scan_enable_rp);
742 	scan_enable_cp.le_scan_enable = 0;
743 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
744 		NG_HCI_OCF_LE_SET_SCAN_ENABLE),
745 		(void *)&scan_enable_cp, sizeof(scan_enable_cp),
746 		(void *)&scan_enable_rp, &n) == ERROR)
747 		return (ERROR);
748 
749 	if (scan_enable_rp.status != 0x00) {
750 		fprintf(stdout, "LE_Scan_Enable disable failed. Status: %s [%#02x]\n",
751 			hci_status2str(scan_enable_rp.status),
752 			scan_enable_rp.status);
753 		return (FAILED);
754 	}
755 
756 	return (OK);
757 }
758 
handle_le_event(ng_hci_event_pkt_t * e,bool verbose)759 static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose)
760 {
761 	int rc;
762 	ng_hci_le_ep	*leer =
763 			(ng_hci_le_ep *)(e + 1);
764 	ng_hci_le_advertising_report_ep *advrep =
765 		(ng_hci_le_advertising_report_ep *)(leer + 1);
766 	ng_hci_le_advreport	*reports =
767 		(ng_hci_le_advreport *)(advrep + 1);
768 
769 	if (leer->subevent_code == NG_HCI_LEEV_ADVREP) {
770 		fprintf(stdout, "Scan result, num_reports: %d\n",
771 			advrep->num_reports);
772 		for(rc = 0; rc < advrep->num_reports; rc++) {
773 			uint8_t length = (uint8_t)reports[rc].length_data;
774 			fprintf(stdout, "\tBD_ADDR %s \n",
775 				hci_bdaddr2str(&reports[rc].bdaddr));
776 			fprintf(stdout, "\tAddress type: %s\n",
777 				hci_addrtype2str(reports[rc].addr_type));
778 			if (length > 0 && verbose) {
779 				dump_adv_data(length, reports[rc].data);
780 				print_adv_data(length, reports[rc].data);
781 				fprintf(stdout,
782 					"\tRSSI: %d dBm\n",
783 					(int8_t)reports[rc].data[length]);
784 				fprintf(stdout, "\n");
785 			}
786 		}
787 	}
788 }
789 
790 static int
le_read_white_list_size(int s,int argc,char * argv[])791 le_read_white_list_size(int s, int argc, char *argv[])
792 {
793 	ng_hci_le_read_white_list_size_rp rp;
794 	int n;
795 
796 	n = sizeof(rp);
797 
798 	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
799 		NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE),
800 		(void *)&rp, &n) == ERROR)
801 		return (ERROR);
802 
803 	if (rp.status != 0x00) {
804 		fprintf(stdout, "Status: %s [%#02x]\n",
805 			hci_status2str(rp.status), rp.status);
806 		return (FAILED);
807 	}
808 
809         fprintf(stdout, "White list size: %d\n",
810 		(uint8_t)rp.white_list_size);
811 
812 	return (OK);
813 }
814 
815 static int
le_clear_white_list(int s,int argc,char * argv[])816 le_clear_white_list(int s, int argc, char *argv[])
817 {
818 	ng_hci_le_clear_white_list_rp rp;
819 	int n;
820 
821 	n = sizeof(rp);
822 
823 	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
824 		NG_HCI_OCF_LE_CLEAR_WHITE_LIST),
825 		(void *)&rp, &n) == ERROR)
826 		return (ERROR);
827 
828 	if (rp.status != 0x00) {
829 		fprintf(stdout, "Status: %s [%#02x]\n",
830 			hci_status2str(rp.status), rp.status);
831 		return (FAILED);
832 	}
833 
834         fprintf(stdout, "White list cleared\n");
835 
836 	return (OK);
837 }
838 
839 static int
le_add_device_to_white_list(int s,int argc,char * argv[])840 le_add_device_to_white_list(int s, int argc, char *argv[])
841 {
842 	ng_hci_le_add_device_to_white_list_cp cp;
843 	ng_hci_le_add_device_to_white_list_rp rp;
844 	int n;
845 	char ch;
846 	optreset = 1;
847 	optind = 0;
848 	bool addr_set = false;
849 
850 	n = sizeof(rp);
851 
852 	cp.address_type = 0x00;
853 
854 	while ((ch = getopt(argc, argv , "t:a:")) != -1) {
855 		switch(ch) {
856 		case 't':
857 			if (strcmp(optarg, "public") == 0)
858 				cp.address_type = 0x00;
859 			else if (strcmp(optarg, "random") == 0)
860 				cp.address_type = 0x01;
861 			else
862 				return (USAGE);
863 			break;
864 		case 'a':
865 			addr_set = true;
866 			if (!bt_aton(optarg, &cp.address)) {
867 				struct hostent	*he = NULL;
868 
869 				if ((he = bt_gethostbyname(optarg)) == NULL)
870 					return (USAGE);
871 
872 				memcpy(&cp.address, he->h_addr,
873 					sizeof(cp.address));
874 			}
875 			break;
876 		}
877 	}
878 
879 	if (addr_set == false)
880 		return (USAGE);
881 
882 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
883 		NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST),
884 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
885 		return (ERROR);
886 
887 	if (rp.status != 0x00) {
888 		fprintf(stdout, "Status: %s [%#02x]\n",
889 			hci_status2str(rp.status), rp.status);
890 		return (FAILED);
891 	}
892 
893         fprintf(stdout, "Address added to white list\n");
894 
895 	return (OK);
896 }
897 
898 static int
le_remove_device_from_white_list(int s,int argc,char * argv[])899 le_remove_device_from_white_list(int s, int argc, char *argv[])
900 {
901 	ng_hci_le_remove_device_from_white_list_cp cp;
902 	ng_hci_le_remove_device_from_white_list_rp rp;
903 	int n;
904 	char ch;
905 	optreset = 1;
906 	optind = 0;
907 	bool addr_set = false;
908 
909 	n = sizeof(rp);
910 
911 	cp.address_type = 0x00;
912 
913 	while ((ch = getopt(argc, argv , "t:a:")) != -1) {
914 		switch(ch) {
915 		case 't':
916 			if (strcmp(optarg, "public") == 0)
917 				cp.address_type = 0x00;
918 			else if (strcmp(optarg, "random") == 0)
919 				cp.address_type = 0x01;
920 			else
921 				return (USAGE);
922 			break;
923 		case 'a':
924 			addr_set = true;
925 			if (!bt_aton(optarg, &cp.address)) {
926 				struct hostent	*he = NULL;
927 
928 				if ((he = bt_gethostbyname(optarg)) == NULL)
929 					return (USAGE);
930 
931 				memcpy(&cp.address, he->h_addr,
932 					sizeof(cp.address));
933 			}
934 			break;
935 		}
936 	}
937 
938 	if (addr_set == false)
939 		return (USAGE);
940 
941 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
942 		NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST),
943 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
944 		return (ERROR);
945 
946 	if (rp.status != 0x00) {
947 		fprintf(stdout, "Status: %s [%#02x]\n",
948 			hci_status2str(rp.status), rp.status);
949 		return (FAILED);
950 	}
951 
952         fprintf(stdout, "Address removed from white list\n");
953 
954 	return (OK);
955 }
956 
957 static int
le_connect(int s,int argc,char * argv[])958 le_connect(int s, int argc, char *argv[])
959 {
960 	ng_hci_le_create_connection_cp cp;
961 	ng_hci_status_rp rp;
962 	char 			b[512];
963 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
964 
965 	int n, scancount, bufsize;
966 	char ch;
967 	bool addr_set = false;
968 	bool verbose = false;
969 
970 	optreset = 1;
971 	optind = 0;
972 
973 	/* minimal scan interval (2.5ms) */
974 	cp.scan_interval = htole16(4);
975 	cp.scan_window = htole16(4);
976 
977 	/* Don't use the whitelist */
978 	cp.filter_policy = 0x00;
979 
980 	/* Default to public peer address */
981 	cp.peer_addr_type = 0x00;
982 
983 	/* Own address type public */
984 	cp.own_address_type = 0x00;
985 
986 	/* 18.75ms min connection interval */
987 	cp.conn_interval_min = htole16(0x000F);
988 	/* 18.75ms max connection interval */
989 	cp.conn_interval_max = htole16(0x000F);
990 
991 	/* 0 events connection latency */
992 	cp.conn_latency = htole16(0x0000);
993 
994 	/* 32s supervision timeout */
995 	cp.supervision_timeout = htole16(0x0C80);
996 
997 	/* Min CE Length 0.625 ms */
998 	cp.min_ce_length = htole16(1);
999 	/* Max CE Length 0.625 ms */
1000 	cp.max_ce_length = htole16(1);
1001 
1002 	while ((ch = getopt(argc, argv , "a:t:v")) != -1) {
1003 		switch(ch) {
1004 		case 't':
1005 			if (strcmp(optarg, "public") == 0)
1006 				cp.peer_addr_type = 0x00;
1007 			else if (strcmp(optarg, "random") == 0)
1008 				cp.peer_addr_type = 0x01;
1009 			else
1010 				return (USAGE);
1011 			break;
1012 		case 'a':
1013 			addr_set = true;
1014 			if (!bt_aton(optarg, &cp.peer_addr)) {
1015 				struct hostent	*he = NULL;
1016 
1017 				if ((he = bt_gethostbyname(optarg)) == NULL)
1018 					return (USAGE);
1019 
1020 				memcpy(&cp.peer_addr, he->h_addr,
1021 					sizeof(cp.peer_addr));
1022 			}
1023 			break;
1024 		case 'v':
1025 			verbose = true;
1026 			break;
1027 		}
1028 	}
1029 
1030 	if (addr_set == false)
1031 		return (USAGE);
1032 
1033 	n = sizeof(rp);
1034 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
1035 		NG_HCI_OCF_LE_CREATE_CONNECTION),
1036 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
1037 		return (ERROR);
1038 
1039 	if (rp.status != 0x00) {
1040 		fprintf(stdout,
1041 			"Create connection failed. Status: %s [%#02x]\n",
1042 			hci_status2str(rp.status), rp.status);
1043 		return (FAILED);
1044 	}
1045 
1046 	scancount = 0;
1047 	while (scancount < 3) {
1048 		/* wait for connection events */
1049 		bufsize = sizeof(b);
1050 		if (hci_recv(s, b, &bufsize) == ERROR) {
1051 			return (ERROR);
1052 		}
1053 
1054 		if (bufsize < sizeof(*e)) {
1055 			errno = EIO;
1056 			return (ERROR);
1057 		}
1058 		scancount++;
1059 		if (e->event == NG_HCI_EVENT_LE) {
1060 			handle_le_connection_event(e, verbose);
1061 			break;
1062 		}
1063 	}
1064 
1065 	return (OK);
1066 }
1067 
handle_le_connection_event(ng_hci_event_pkt_t * e,bool verbose)1068 static void handle_le_connection_event(ng_hci_event_pkt_t* e, bool verbose)
1069 {
1070 	ng_hci_le_ep	*ev_pkt;
1071 	ng_hci_le_connection_complete_ep *conn_event;
1072 
1073 	ev_pkt = (ng_hci_le_ep *)(e + 1);
1074 
1075 	if (ev_pkt->subevent_code == NG_HCI_LEEV_CON_COMPL) {
1076 		conn_event =(ng_hci_le_connection_complete_ep *)(ev_pkt + 1);
1077 		fprintf(stdout, "Handle: %d\n", le16toh(conn_event->handle));
1078 		if (verbose) {
1079 			fprintf(stdout,
1080 				"Status: %s\n",
1081 				hci_status2str(conn_event->status));
1082 			fprintf(stdout,
1083 				"Role: %s\n",
1084 				hci_role2str(conn_event->role));
1085 			fprintf(stdout,
1086 				"Address Type: %s\n",
1087 				hci_addrtype2str(conn_event->address_type));
1088 			fprintf(stdout,
1089 				"Address: %s\n",
1090 				hci_bdaddr2str(&conn_event->address));
1091 			fprintf(stdout,
1092 				"Interval: %.2fms\n",
1093 				6.25 * le16toh(conn_event->interval));
1094 			fprintf(stdout,
1095 				"Latency: %d events\n", conn_event->latency);
1096 			fprintf(stdout,
1097 				"Supervision timeout: %dms\n",
1098 				 10 * le16toh(conn_event->supervision_timeout));
1099 			fprintf(stdout,
1100 				"Master clock accuracy: %s\n",
1101 				hci_mc_accuracy2str(
1102 					conn_event->master_clock_accuracy));
1103 		}
1104 	}
1105 }
1106 
1107 static int
le_read_channel_map(int s,int argc,char * argv[])1108 le_read_channel_map(int s, int argc, char *argv[])
1109 {
1110 	ng_hci_le_read_channel_map_cp	cp;
1111 	ng_hci_le_read_channel_map_rp	rp;
1112 	int				n;
1113 	char 				buffer[2048];
1114 
1115 	/* parse command parameters */
1116 	switch (argc) {
1117 	case 1:
1118 		/* connection handle */
1119 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
1120 			return (USAGE);
1121 
1122 		cp.connection_handle = (uint16_t) (n & 0x0fff);
1123 		cp.connection_handle = htole16(cp.connection_handle);
1124 		break;
1125 
1126 	default:
1127 		return (USAGE);
1128 	}
1129 
1130 	n = sizeof(rp);
1131 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
1132 		NG_HCI_OCF_LE_READ_CHANNEL_MAP),
1133 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
1134 		return (ERROR);
1135 
1136 	if (rp.status != 0x00) {
1137 		fprintf(stdout,
1138 			"Read channel map failed. Status: %s [%#02x]\n",
1139 			hci_status2str(rp.status), rp.status);
1140 		return (FAILED);
1141 	}
1142 
1143 	fprintf(stdout, "Connection handle: %d\n",
1144 		le16toh(rp.connection_handle));
1145 	fprintf(stdout, "Used channels:\n");
1146 	fprintf(stdout, "\n%s\n", hci_le_chanmap2str(rp.le_channel_map,
1147 		buffer, sizeof(buffer)));
1148 
1149 	return (OK);
1150 } /* le_read_channel_map */
1151 
1152 static int
le_read_remote_features(int s,int argc,char * argv[])1153 le_read_remote_features(int s, int argc, char *argv[])
1154 {
1155 	ng_hci_le_read_remote_used_features_cp	cp;
1156 	ng_hci_status_rp 			rp;
1157 	int					n, bufsize;
1158 	char 					b[512];
1159 
1160 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
1161 
1162 	/* parse command parameters */
1163 	switch (argc) {
1164 	case 1:
1165 		/* connection handle */
1166 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
1167 			return (USAGE);
1168 
1169 		cp.connection_handle = (uint16_t) (n & 0x0fff);
1170 		cp.connection_handle = htole16(cp.connection_handle);
1171 		break;
1172 
1173 	default:
1174 		return (USAGE);
1175 	}
1176 
1177 	n = sizeof(rp);
1178 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
1179 		NG_HCI_OCF_LE_READ_REMOTE_USED_FEATURES),
1180 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
1181 		return (ERROR);
1182 
1183 	if (rp.status != 0x00) {
1184 		fprintf(stdout,
1185 			"Read remote features failed. Status: %s [%#02x]\n",
1186 			hci_status2str(rp.status), rp.status);
1187 		return (FAILED);
1188 	}
1189 
1190 	/* wait for connection events */
1191 	bufsize = sizeof(b);
1192 	if (hci_recv(s, b, &bufsize) == ERROR) {
1193 		return (ERROR);
1194 	}
1195 
1196 	if (bufsize < sizeof(*e)) {
1197 		errno = EIO;
1198 		return (ERROR);
1199 	}
1200 	if (e->event == NG_HCI_EVENT_LE) {
1201 		handle_le_remote_features_event(e);
1202 	}
1203 
1204 	return (OK);
1205 } /* le_read_remote_features */
1206 
handle_le_remote_features_event(ng_hci_event_pkt_t * e)1207 static void handle_le_remote_features_event(ng_hci_event_pkt_t* e)
1208 {
1209 	ng_hci_le_ep	*ev_pkt;
1210 	ng_hci_le_read_remote_features_ep *feat_event;
1211 	char	buffer[2048];
1212 
1213 	ev_pkt = (ng_hci_le_ep *)(e + 1);
1214 
1215 	if (ev_pkt->subevent_code == NG_HCI_LEEV_READ_REMOTE_FEATURES_COMPL) {
1216 		feat_event =(ng_hci_le_read_remote_features_ep *)(ev_pkt + 1);
1217 		fprintf(stdout, "Handle: %d\n",
1218 			le16toh(feat_event->connection_handle));
1219 		fprintf(stdout,
1220 			"Status: %s\n",
1221 			hci_status2str(feat_event->status));
1222 		fprintf(stdout, "Features:\n%s\n",
1223 			hci_le_features2str(feat_event->features,
1224 				buffer, sizeof(buffer)));
1225 	}
1226 } /* handle_le_remote_features_event */
1227 
le_rand(int s,int argc,char * argv[])1228 static int le_rand(int s, int argc, char *argv[])
1229 {
1230 	ng_hci_le_rand_rp rp;
1231 	int n;
1232 
1233 	n = sizeof(rp);
1234 
1235 	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
1236 		NG_HCI_OCF_LE_RAND),
1237 		(void *)&rp, &n) == ERROR)
1238 		return (ERROR);
1239 
1240 	if (rp.status != 0x00) {
1241 		fprintf(stdout, "Status: %s [%#02x]\n",
1242 			hci_status2str(rp.status), rp.status);
1243 		return (FAILED);
1244 	}
1245 
1246 	fprintf(stdout,
1247 		"Random number : %08llx\n",
1248 		(unsigned long long)le64toh(rp.random_number));
1249 
1250 	return (OK);
1251 }
1252 
1253 
1254 
1255 struct hci_command le_commands[] = {
1256 {
1257 	"le_enable",
1258 	"le_enable [enable|disable] \n"
1259 	"Enable LE event ",
1260 	&le_enable,
1261 },
1262   {
1263 	  "le_read_local_supported_features",
1264 	  "le_read_local_supported_features\n"
1265 	  "read local supported features mask",
1266 	  &le_read_local_supported_features,
1267   },
1268   {
1269 	  "le_read_supported_states",
1270 	  "le_read_supported_states\n"
1271 	  "read supported status"
1272 	  ,
1273 	  &le_read_supported_states,
1274   },
1275   {
1276 	  "le_set_scan_response",
1277 	  "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n"
1278 	  "set LE scan response data"
1279 	  ,
1280 	  &le_set_scan_response,
1281   },
1282   {
1283 	  "le_set_scan_enable",
1284 	  "le_set_scan_enable [enable|disable] \n"
1285 	  "enable or disable LE device scan",
1286 	  &le_set_scan_enable
1287   },
1288   {
1289 	  "le_set_scan_param",
1290 	  "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n"
1291 	  "set LE device scan parameter",
1292 	  &le_set_scan_param
1293   },
1294   {
1295 	  "le_set_advertising_enable",
1296 	  "le_set_advertising_enable [enable|disable] \n"
1297 	  "start or stop advertising",
1298 	  &le_set_advertising_enable
1299   },
1300   {
1301 	  "le_read_advertising_channel_tx_power",
1302 	  "le_read_advertising_channel_tx_power\n"
1303 	  "read host advertising transmit poser level (dBm)",
1304 	  &le_read_advertising_channel_tx_power
1305   },
1306   {
1307 	  "le_set_advertising_param",
1308 	  "le_set_advertising_param  [-m min_interval(ms)] [-M max_interval(ms)]\n"
1309 	  "[-t advertising_type] [-o own_address_type] [-p peer_address_type]\n"
1310 	  "[-c advertising_channel_map] [-f advertising_filter_policy]\n"
1311 	  "[-a peer_address]\n"
1312 	  "set LE device advertising parameters",
1313 	  &le_set_advertising_param
1314   },
1315   {
1316 	  "le_set_advertising_data",
1317 	  "le_set_advertising_data -n $name -f $flag -u $uuid16,$uuid16 -b $byte,$byte,...,$byte\n"
1318 	  "set LE device advertising packed data",
1319 	  &le_set_advertising_data
1320   },
1321   {
1322 	  "le_read_buffer_size",
1323 	  "le_read_buffer_size [-v 1|2]\n"
1324 	  "Read the maximum size of ACL and ISO data packets",
1325 	  &le_read_buffer_size
1326   },
1327   {
1328 	  "le_scan",
1329 	  "le_scan [-a] [-v] [-n number_of_scans]\n"
1330 	  "Do an LE scan",
1331 	  &le_scan
1332   },
1333   {
1334 	  "le_read_white_list_size",
1335 	  "le_read_white_list_size\n"
1336 	  "Read total number of white list entries that can be stored",
1337 	  &le_read_white_list_size
1338   },
1339   {
1340 	  "le_clear_white_list",
1341 	  "le_clear_white_list\n"
1342 	  "Clear the white list in the controller",
1343 	  &le_clear_white_list
1344   },
1345   {
1346 	  "le_add_device_to_white_list",
1347 	  "le_add_device_to_white_list\n"
1348 	  "[-t public|random] -a address\n"
1349 	  "Add device to the white list",
1350 	  &le_add_device_to_white_list
1351   },
1352   {
1353 	  "le_remove_device_from_white_list",
1354 	  "le_remove_device_from_white_list\n"
1355 	  "[-t public|random] -a address\n"
1356 	  "Remove device from the white list",
1357 	  &le_remove_device_from_white_list
1358   },
1359   {
1360 	  "le_connect",
1361 	  "le_connect -a address [-t public|random] [-v]\n"
1362 	  "Connect to an LE device",
1363 	  &le_connect
1364   },
1365   {
1366 	  "le_read_channel_map",
1367 	  "le_read_channel_map <connection_handle>\n"
1368 	  "Read the channel map for a connection",
1369 	  &le_read_channel_map
1370   },
1371   {
1372 	  "le_read_remote_features",
1373 	  "le_read_remote_features <connection_handle>\n"
1374 	  "Read supported features for the device\n"
1375 	  "identified by the connection handle",
1376 	  &le_read_remote_features
1377   },
1378   {
1379 	  "le_rand",
1380 	  "le_rand\n"
1381 	  "Generate 64 bits of random data",
1382 	  &le_rand
1383   },
1384   {
1385 	  NULL,
1386   }
1387 };
1388