xref: /freebsd/usr.sbin/bluetooth/hccontrol/le.c (revision 11fb4bdb4d581ea0202e358ed031edc34ac9cfcb)
1bcff2d91STakanori Watanabe /*
2bcff2d91STakanori Watanabe  * le.c
3bcff2d91STakanori Watanabe  *
4bcff2d91STakanori Watanabe  * Copyright (c) 2015 Takanori Watanabe <takawata@freebsd.org>
5bcff2d91STakanori Watanabe  * All rights reserved.
6bcff2d91STakanori Watanabe  *
7bcff2d91STakanori Watanabe  * Redistribution and use in source and binary forms, with or without
8bcff2d91STakanori Watanabe  * modification, are permitted provided that the following conditions
9bcff2d91STakanori Watanabe  * are met:
10bcff2d91STakanori Watanabe  * 1. Redistributions of source code must retain the above copyright
11bcff2d91STakanori Watanabe  *    notice, this list of conditions and the following disclaimer.
12bcff2d91STakanori Watanabe  * 2. Redistributions in binary form must reproduce the above copyright
13bcff2d91STakanori Watanabe  *    notice, this list of conditions and the following disclaimer in the
14bcff2d91STakanori Watanabe  *    documentation and/or other materials provided with the distribution.
15bcff2d91STakanori Watanabe  *
16bcff2d91STakanori Watanabe  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17bcff2d91STakanori Watanabe  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18bcff2d91STakanori Watanabe  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19bcff2d91STakanori Watanabe  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20bcff2d91STakanori Watanabe  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21bcff2d91STakanori Watanabe  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22bcff2d91STakanori Watanabe  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23bcff2d91STakanori Watanabe  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24bcff2d91STakanori Watanabe  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25bcff2d91STakanori Watanabe  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26bcff2d91STakanori Watanabe  * SUCH DAMAGE.
27bcff2d91STakanori Watanabe  *
28bcff2d91STakanori Watanabe  * $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $
29bcff2d91STakanori Watanabe  * $FreeBSD$
30bcff2d91STakanori Watanabe  */
31bcff2d91STakanori Watanabe 
32bcff2d91STakanori Watanabe #include <sys/types.h>
33bcff2d91STakanori Watanabe #include <sys/ioctl.h>
34bcff2d91STakanori Watanabe #include <sys/sysctl.h>
35bcff2d91STakanori Watanabe #include <sys/select.h>
36bcff2d91STakanori Watanabe #include <assert.h>
378907f744SAlan Somers #include <bitstring.h>
38bcff2d91STakanori Watanabe #include <err.h>
39bcff2d91STakanori Watanabe #include <errno.h>
40bcff2d91STakanori Watanabe #include <netgraph/ng_message.h>
41bcff2d91STakanori Watanabe #include <errno.h>
429287f06dSTakanori Watanabe #include <stdbool.h>
43bcff2d91STakanori Watanabe #include <stdio.h>
44bcff2d91STakanori Watanabe #include <stdlib.h>
45bcff2d91STakanori Watanabe #include <string.h>
46bcff2d91STakanori Watanabe #include <unistd.h>
474cae2db2STakanori Watanabe #include <stdint.h>
48bcff2d91STakanori Watanabe #define L2CAP_SOCKET_CHECKED
49bcff2d91STakanori Watanabe #include <bluetooth.h>
50bcff2d91STakanori Watanabe #include "hccontrol.h"
519c3471faSMarcelo Araujo 
52bcff2d91STakanori Watanabe static int le_set_scan_param(int s, int argc, char *argv[]);
53bcff2d91STakanori Watanabe static int le_set_scan_enable(int s, int argc, char *argv[]);
54bcff2d91STakanori Watanabe static int parse_param(int argc, char *argv[], char *buf, int *len);
55bcff2d91STakanori Watanabe static int le_set_scan_response(int s, int argc, char *argv[]);
5621eefd31SHans Petter Selasky static int le_read_supported_states(int s, int argc, char *argv[]);
57bcff2d91STakanori Watanabe static int le_read_local_supported_features(int s, int argc ,char *argv[]);
58bcff2d91STakanori Watanabe static int set_le_event_mask(int s, uint64_t mask);
59bcff2d91STakanori Watanabe static int set_event_mask(int s, uint64_t mask);
60bcff2d91STakanori Watanabe static int le_enable(int s, int argc, char *argv[]);
61c3f60abcSHans Petter Selasky static int le_set_advertising_enable(int s, int argc, char *argv[]);
62c3f60abcSHans Petter Selasky static int le_set_advertising_param(int s, int argc, char *argv[]);
63c3f60abcSHans Petter Selasky static int le_read_advertising_channel_tx_power(int s, int argc, char *argv[]);
649287f06dSTakanori Watanabe static int le_scan(int s, int argc, char *argv[]);
659287f06dSTakanori Watanabe static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose);
66*11fb4bdbSTakanori Watanabe static int le_read_white_list_size(int s, int argc, char *argv[]);
67*11fb4bdbSTakanori Watanabe static int le_clear_white_list(int s, int argc, char *argv[]);
68*11fb4bdbSTakanori Watanabe static int le_add_device_to_white_list(int s, int argc, char *argv[]);
69*11fb4bdbSTakanori Watanabe static int le_remove_device_from_white_list(int s, int argc, char *argv[]);
70bcff2d91STakanori Watanabe 
719c3471faSMarcelo Araujo static int
729c3471faSMarcelo Araujo le_set_scan_param(int s, int argc, char *argv[])
73bcff2d91STakanori Watanabe {
74bcff2d91STakanori Watanabe 	int type;
75bcff2d91STakanori Watanabe 	int interval;
76bcff2d91STakanori Watanabe 	int window;
77bcff2d91STakanori Watanabe 	int adrtype;
78bcff2d91STakanori Watanabe 	int policy;
79eb2aebeaSTakanori Watanabe 	int n;
80bcff2d91STakanori Watanabe 
81bcff2d91STakanori Watanabe 	ng_hci_le_set_scan_parameters_cp cp;
82bcff2d91STakanori Watanabe 	ng_hci_le_set_scan_parameters_rp rp;
83bcff2d91STakanori Watanabe 
849c3471faSMarcelo Araujo 	if (argc != 5)
85eb2aebeaSTakanori Watanabe 		return (USAGE);
86bcff2d91STakanori Watanabe 
879c3471faSMarcelo Araujo 	if (strcmp(argv[0], "active") == 0)
88bcff2d91STakanori Watanabe 		type = 1;
899c3471faSMarcelo Araujo 	else if (strcmp(argv[0], "passive") == 0)
90bcff2d91STakanori Watanabe 		type = 0;
919c3471faSMarcelo Araujo 	else
92eb2aebeaSTakanori Watanabe 		return (USAGE);
93bcff2d91STakanori Watanabe 
94bcff2d91STakanori Watanabe 	interval = (int)(atof(argv[1])/0.625);
95bcff2d91STakanori Watanabe 	interval = (interval < 4)? 4: interval;
96bcff2d91STakanori Watanabe 	window = (int)(atof(argv[2])/0.625);
97bcff2d91STakanori Watanabe 	window = (window < 4) ? 4 : interval;
98bcff2d91STakanori Watanabe 
999c3471faSMarcelo Araujo 	if (strcmp(argv[3], "public") == 0)
100bcff2d91STakanori Watanabe 		adrtype = 0;
10105e526fbSTakanori Watanabe 	else if (strcmp(argv[3], "random") == 0)
102bcff2d91STakanori Watanabe 		adrtype = 1;
1039c3471faSMarcelo Araujo 	else
104eb2aebeaSTakanori Watanabe 		return (USAGE);
105bcff2d91STakanori Watanabe 
1069c3471faSMarcelo Araujo 	if (strcmp(argv[4], "all") == 0)
107bcff2d91STakanori Watanabe 		policy = 0;
1089c3471faSMarcelo Araujo 	else if (strcmp(argv[4], "whitelist") == 0)
109bcff2d91STakanori Watanabe 		policy = 1;
1109c3471faSMarcelo Araujo 	else
111eb2aebeaSTakanori Watanabe 		return (USAGE);
112bcff2d91STakanori Watanabe 
113bcff2d91STakanori Watanabe 	cp.le_scan_type = type;
114bcff2d91STakanori Watanabe 	cp.le_scan_interval = interval;
115bcff2d91STakanori Watanabe 	cp.own_address_type = adrtype;
116bcff2d91STakanori Watanabe 	cp.le_scan_window = window;
117bcff2d91STakanori Watanabe 	cp.scanning_filter_policy = policy;
118bcff2d91STakanori Watanabe 	n = sizeof(rp);
119bcff2d91STakanori Watanabe 
120eb2aebeaSTakanori Watanabe 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
121eb2aebeaSTakanori Watanabe 		NG_HCI_OCF_LE_SET_SCAN_PARAMETERS),
122eb2aebeaSTakanori Watanabe 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
123eb2aebeaSTakanori Watanabe 		return (ERROR);
124eb2aebeaSTakanori Watanabe 
125eb2aebeaSTakanori Watanabe 	if (rp.status != 0x00) {
126eb2aebeaSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
127eb2aebeaSTakanori Watanabe 			hci_status2str(rp.status), rp.status);
128eb2aebeaSTakanori Watanabe 		return (FAILED);
129eb2aebeaSTakanori Watanabe 	}
130eb2aebeaSTakanori Watanabe 
131eb2aebeaSTakanori Watanabe 	return (OK);
132bcff2d91STakanori Watanabe }
133bcff2d91STakanori Watanabe 
1349c3471faSMarcelo Araujo static int
1359c3471faSMarcelo Araujo le_set_scan_enable(int s, int argc, char *argv[])
136bcff2d91STakanori Watanabe {
137bcff2d91STakanori Watanabe 	ng_hci_le_set_scan_enable_cp cp;
138bcff2d91STakanori Watanabe 	ng_hci_le_set_scan_enable_rp rp;
139eb2aebeaSTakanori Watanabe 	int n, enable = 0;
140bcff2d91STakanori Watanabe 
141bcff2d91STakanori Watanabe 	if (argc != 1)
142eb2aebeaSTakanori Watanabe 		return (USAGE);
143bcff2d91STakanori Watanabe 
1449c3471faSMarcelo Araujo 	if (strcmp(argv[0], "enable") == 0)
145bcff2d91STakanori Watanabe 		enable = 1;
1469c3471faSMarcelo Araujo 	else if (strcmp(argv[0], "disable") != 0)
147eb2aebeaSTakanori Watanabe 		return (USAGE);
1489c3471faSMarcelo Araujo 
149bcff2d91STakanori Watanabe 	n = sizeof(rp);
150bcff2d91STakanori Watanabe 	cp.le_scan_enable = enable;
151bcff2d91STakanori Watanabe 	cp.filter_duplicates = 0;
152eb2aebeaSTakanori Watanabe 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
153bcff2d91STakanori Watanabe 		NG_HCI_OCF_LE_SET_SCAN_ENABLE),
154eb2aebeaSTakanori Watanabe 		(void *)&cp, sizeof(cp),
155eb2aebeaSTakanori Watanabe 		(void *)&rp, &n) == ERROR)
156eb2aebeaSTakanori Watanabe 		return (ERROR);
157bcff2d91STakanori Watanabe 
158eb2aebeaSTakanori Watanabe 	if (rp.status != 0x00) {
159eb2aebeaSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
160eb2aebeaSTakanori Watanabe 			hci_status2str(rp.status), rp.status);
161eb2aebeaSTakanori Watanabe 		return (FAILED);
162eb2aebeaSTakanori Watanabe 	}
163bcff2d91STakanori Watanabe 
164eb2aebeaSTakanori Watanabe 	fprintf(stdout, "LE Scan: %s\n",
165eb2aebeaSTakanori Watanabe 		enable? "Enabled" : "Disabled");
166eb2aebeaSTakanori Watanabe 
167eb2aebeaSTakanori Watanabe 	return (OK);
168bcff2d91STakanori Watanabe }
1699c3471faSMarcelo Araujo 
1709c3471faSMarcelo Araujo static int
1719c3471faSMarcelo Araujo parse_param(int argc, char *argv[], char *buf, int *len)
172bcff2d91STakanori Watanabe {
173bcff2d91STakanori Watanabe 	char *buflast  =  buf + (*len);
174bcff2d91STakanori Watanabe 	char *curbuf = buf;
175bcff2d91STakanori Watanabe 	char *token,*lenpos;
176bcff2d91STakanori Watanabe 	int ch;
177bcff2d91STakanori Watanabe 	int datalen;
178bcff2d91STakanori Watanabe 	uint16_t value;
179bcff2d91STakanori Watanabe 	optreset = 1;
180bcff2d91STakanori Watanabe 	optind = 0;
181bcff2d91STakanori Watanabe 	while ((ch = getopt(argc, argv , "n:f:u:")) != -1) {
182bcff2d91STakanori Watanabe 		switch(ch){
183bcff2d91STakanori Watanabe 		case 'n':
184bcff2d91STakanori Watanabe 			datalen = strlen(optarg);
1859c3471faSMarcelo Araujo 			if ((curbuf + datalen + 2) >= buflast)
186bcff2d91STakanori Watanabe 				goto done;
187bcff2d91STakanori Watanabe 			curbuf[0] = datalen + 1;
188bcff2d91STakanori Watanabe 			curbuf[1] = 8;
189bcff2d91STakanori Watanabe 			curbuf += 2;
190bcff2d91STakanori Watanabe 			memcpy(curbuf, optarg, datalen);
191bcff2d91STakanori Watanabe 			curbuf += datalen;
192bcff2d91STakanori Watanabe 			break;
193bcff2d91STakanori Watanabe 		case 'f':
1949c3471faSMarcelo Araujo 			if (curbuf+3 > buflast)
195bcff2d91STakanori Watanabe 				goto done;
196bcff2d91STakanori Watanabe 			curbuf[0] = 2;
197bcff2d91STakanori Watanabe 			curbuf[1] = 1;
19832f32669SHans Petter Selasky 			curbuf[2] = (uint8_t)strtol(optarg, NULL, 16);
199bcff2d91STakanori Watanabe 			curbuf += 3;
200bcff2d91STakanori Watanabe 			break;
201bcff2d91STakanori Watanabe 		case 'u':
202bcff2d91STakanori Watanabe 			if ((buf+2) >= buflast)
203bcff2d91STakanori Watanabe 				goto done;
20432f32669SHans Petter Selasky 			lenpos = curbuf;
205bcff2d91STakanori Watanabe 			curbuf[1] = 2;
206bcff2d91STakanori Watanabe 			*lenpos = 1;
207bcff2d91STakanori Watanabe 			curbuf += 2;
208bcff2d91STakanori Watanabe 			while ((token = strsep(&optarg, ",")) != NULL) {
209bcff2d91STakanori Watanabe 				value = strtol(token, NULL, 16);
210bcff2d91STakanori Watanabe 				if ((curbuf+2) >= buflast)
211bcff2d91STakanori Watanabe 					break;
212bcff2d91STakanori Watanabe 				curbuf[0] = value &0xff;
213bcff2d91STakanori Watanabe 				curbuf[1] = (value>>8)&0xff;
214bcff2d91STakanori Watanabe 				curbuf += 2;
21532f32669SHans Petter Selasky 				*lenpos += 2;
216bcff2d91STakanori Watanabe 			}
217bcff2d91STakanori Watanabe 
218bcff2d91STakanori Watanabe 		}
219bcff2d91STakanori Watanabe 	}
220bcff2d91STakanori Watanabe done:
221bcff2d91STakanori Watanabe 	*len = curbuf - buf;
222bcff2d91STakanori Watanabe 
223eb2aebeaSTakanori Watanabe 	return (OK);
224bcff2d91STakanori Watanabe }
225bcff2d91STakanori Watanabe 
2269c3471faSMarcelo Araujo static int
2279c3471faSMarcelo Araujo le_set_scan_response(int s, int argc, char *argv[])
228bcff2d91STakanori Watanabe {
229bcff2d91STakanori Watanabe 	ng_hci_le_set_scan_response_data_cp cp;
230bcff2d91STakanori Watanabe 	ng_hci_le_set_scan_response_data_rp rp;
231bcff2d91STakanori Watanabe 	int n;
232bcff2d91STakanori Watanabe 	int len;
233bcff2d91STakanori Watanabe 	char buf[NG_HCI_ADVERTISING_DATA_SIZE];
2349c3471faSMarcelo Araujo 
235bcff2d91STakanori Watanabe 	len = sizeof(buf);
236bcff2d91STakanori Watanabe 	parse_param(argc, argv, buf, &len);
237bcff2d91STakanori Watanabe 	memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data));
238bcff2d91STakanori Watanabe 	cp.scan_response_data_length = len;
239bcff2d91STakanori Watanabe 	memcpy(cp.scan_response_data, buf, len);
240bcff2d91STakanori Watanabe 	n = sizeof(rp);
241eb2aebeaSTakanori Watanabe 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
242bcff2d91STakanori Watanabe 			NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA),
243eb2aebeaSTakanori Watanabe 			(void *)&cp, sizeof(cp),
244eb2aebeaSTakanori Watanabe 			(void *)&rp, &n) == ERROR)
245eb2aebeaSTakanori Watanabe 		return (ERROR);
246bcff2d91STakanori Watanabe 
247eb2aebeaSTakanori Watanabe 	if (rp.status != 0x00) {
248eb2aebeaSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
249eb2aebeaSTakanori Watanabe 			hci_status2str(rp.status), rp.status);
250eb2aebeaSTakanori Watanabe 		return (FAILED);
251eb2aebeaSTakanori Watanabe 	}
252bcff2d91STakanori Watanabe 
253eb2aebeaSTakanori Watanabe 	return (OK);
254bcff2d91STakanori Watanabe }
255bcff2d91STakanori Watanabe 
2569c3471faSMarcelo Araujo static int
2579c3471faSMarcelo Araujo le_read_local_supported_features(int s, int argc ,char *argv[])
258bcff2d91STakanori Watanabe {
259bcff2d91STakanori Watanabe 	ng_hci_le_read_local_supported_features_rp rp;
260bcff2d91STakanori Watanabe 	int n = sizeof(rp);
2619c3471faSMarcelo Araujo 
262ea011491SHans Petter Selasky 	union {
263ea011491SHans Petter Selasky 		uint64_t raw;
264ea011491SHans Petter Selasky 		uint8_t octets[8];
265ea011491SHans Petter Selasky 	} le_features;
266ea011491SHans Petter Selasky 
267ea011491SHans Petter Selasky 	char buffer[2048];
268ea011491SHans Petter Selasky 
269ea011491SHans Petter Selasky 	if (hci_simple_request(s,
270bcff2d91STakanori Watanabe 			NG_HCI_OPCODE(NG_HCI_OGF_LE,
271bcff2d91STakanori Watanabe 			NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES),
272ea011491SHans Petter Selasky 			(void *)&rp, &n) == ERROR)
273ea011491SHans Petter Selasky 		return (ERROR);
2749c3471faSMarcelo Araujo 
275ea011491SHans Petter Selasky 	if (rp.status != 0x00) {
276ea011491SHans Petter Selasky 		fprintf(stdout, "Status: %s [%#02x]\n",
277ea011491SHans Petter Selasky 			hci_status2str(rp.status), rp.status);
278ea011491SHans Petter Selasky 		return (FAILED);
279ea011491SHans Petter Selasky 	}
280bcff2d91STakanori Watanabe 
281ea011491SHans Petter Selasky 	le_features.raw = rp.le_features;
282ea011491SHans Petter Selasky 
283ea011491SHans Petter Selasky 	fprintf(stdout, "LE Features: ");
284ea011491SHans Petter Selasky 	for(int i = 0; i < 8; i++)
285ea011491SHans Petter Selasky                 fprintf(stdout, " %#02x", le_features.octets[i]);
286ea011491SHans Petter Selasky 	fprintf(stdout, "\n%s\n", hci_le_features2str(le_features.octets,
287ea011491SHans Petter Selasky 		buffer, sizeof(buffer)));
288ea011491SHans Petter Selasky 	fprintf(stdout, "\n");
289ea011491SHans Petter Selasky 
290eb2aebeaSTakanori Watanabe 	return (OK);
291bcff2d91STakanori Watanabe }
2929c3471faSMarcelo Araujo 
2939c3471faSMarcelo Araujo static int
29421eefd31SHans Petter Selasky le_read_supported_states(int s, int argc, char *argv[])
295bcff2d91STakanori Watanabe {
29621eefd31SHans Petter Selasky 	ng_hci_le_read_supported_states_rp rp;
297bcff2d91STakanori Watanabe 	int n = sizeof(rp);
2989c3471faSMarcelo Araujo 
29921eefd31SHans Petter Selasky 	if (hci_simple_request(s, NG_HCI_OPCODE(
3009c3471faSMarcelo Araujo 					NG_HCI_OGF_LE,
30121eefd31SHans Petter Selasky 					NG_HCI_OCF_LE_READ_SUPPORTED_STATES),
30221eefd31SHans Petter Selasky 			       		(void *)&rp, &n) == ERROR)
30321eefd31SHans Petter Selasky 		return (ERROR);
3049c3471faSMarcelo Araujo 
30521eefd31SHans Petter Selasky 	if (rp.status != 0x00) {
30621eefd31SHans Petter Selasky 		fprintf(stdout, "Status: %s [%#02x]\n",
30721eefd31SHans Petter Selasky 			hci_status2str(rp.status), rp.status);
30821eefd31SHans Petter Selasky 		return (FAILED);
30921eefd31SHans Petter Selasky 	}
310bcff2d91STakanori Watanabe 
31121eefd31SHans Petter Selasky 	fprintf(stdout, "LE States: %jx\n", rp.le_states);
31221eefd31SHans Petter Selasky 
31321eefd31SHans Petter Selasky 	return (OK);
314bcff2d91STakanori Watanabe }
315bcff2d91STakanori Watanabe 
3169c3471faSMarcelo Araujo static int
3179c3471faSMarcelo Araujo set_le_event_mask(int s, uint64_t mask)
318bcff2d91STakanori Watanabe {
319bcff2d91STakanori Watanabe 	ng_hci_le_set_event_mask_cp semc;
320bcff2d91STakanori Watanabe 	ng_hci_le_set_event_mask_rp rp;
321eb2aebeaSTakanori Watanabe 	int i, n;
322bcff2d91STakanori Watanabe 
323bcff2d91STakanori Watanabe 	n = sizeof(rp);
324bcff2d91STakanori Watanabe 
325bcff2d91STakanori Watanabe 	for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) {
326bcff2d91STakanori Watanabe 		semc.event_mask[i] = mask&0xff;
327bcff2d91STakanori Watanabe 		mask >>= 8;
328bcff2d91STakanori Watanabe 	}
329eb2aebeaSTakanori Watanabe 	if(hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
3309c3471faSMarcelo Araujo 			NG_HCI_OCF_LE_SET_EVENT_MASK),
331eb2aebeaSTakanori Watanabe 			(void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR)
332eb2aebeaSTakanori Watanabe 		return (ERROR);
333bcff2d91STakanori Watanabe 
334eb2aebeaSTakanori Watanabe 	if (rp.status != 0x00) {
335eb2aebeaSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
336eb2aebeaSTakanori Watanabe 			hci_status2str(rp.status), rp.status);
337eb2aebeaSTakanori Watanabe 		return (FAILED);
338eb2aebeaSTakanori Watanabe 	}
339eb2aebeaSTakanori Watanabe 
340eb2aebeaSTakanori Watanabe 	return (OK);
341bcff2d91STakanori Watanabe }
342bcff2d91STakanori Watanabe 
3439c3471faSMarcelo Araujo static int
3449c3471faSMarcelo Araujo set_event_mask(int s, uint64_t mask)
345bcff2d91STakanori Watanabe {
346bcff2d91STakanori Watanabe 	ng_hci_set_event_mask_cp semc;
347bcff2d91STakanori Watanabe 	ng_hci_set_event_mask_rp rp;
348eb2aebeaSTakanori Watanabe 	int i, n;
349bcff2d91STakanori Watanabe 
350bcff2d91STakanori Watanabe 	n = sizeof(rp);
351bcff2d91STakanori Watanabe 
352bcff2d91STakanori Watanabe 	for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) {
353bcff2d91STakanori Watanabe 		semc.event_mask[i] = mask&0xff;
354bcff2d91STakanori Watanabe 		mask >>= 8;
355bcff2d91STakanori Watanabe 	}
356eb2aebeaSTakanori Watanabe 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
3579c3471faSMarcelo Araujo 			NG_HCI_OCF_SET_EVENT_MASK),
358eb2aebeaSTakanori Watanabe 			(void *)&semc, sizeof(semc), (void *)&rp, &n) == ERROR)
359eb2aebeaSTakanori Watanabe 		return (ERROR);
360bcff2d91STakanori Watanabe 
361eb2aebeaSTakanori Watanabe 	if (rp.status != 0x00) {
362eb2aebeaSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
363eb2aebeaSTakanori Watanabe 			hci_status2str(rp.status), rp.status);
364eb2aebeaSTakanori Watanabe 		return (FAILED);
365eb2aebeaSTakanori Watanabe 	}
366eb2aebeaSTakanori Watanabe 
367eb2aebeaSTakanori Watanabe 	return (OK);
368bcff2d91STakanori Watanabe }
369bcff2d91STakanori Watanabe 
3709c3471faSMarcelo Araujo static
3719c3471faSMarcelo Araujo int le_enable(int s, int argc, char *argv[])
372bcff2d91STakanori Watanabe {
373eb2aebeaSTakanori Watanabe         int result;
374eb2aebeaSTakanori Watanabe 
3759c3471faSMarcelo Araujo 	if (argc != 1)
376eb2aebeaSTakanori Watanabe 		return (USAGE);
377bcff2d91STakanori Watanabe 
378bcff2d91STakanori Watanabe 	if (strcasecmp(argv[0], "enable") == 0) {
379eb2aebeaSTakanori Watanabe 		result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT |
380bcff2d91STakanori Watanabe 			       NG_HCI_EVENT_MASK_LE);
381eb2aebeaSTakanori Watanabe 		if (result != OK)
382eb2aebeaSTakanori Watanabe 			return result;
383eb2aebeaSTakanori Watanabe 		result = set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL);
384eb2aebeaSTakanori Watanabe 		if (result == OK) {
385eb2aebeaSTakanori Watanabe 			fprintf(stdout, "LE enabled\n");
386eb2aebeaSTakanori Watanabe 			return (OK);
387eb2aebeaSTakanori Watanabe 		} else
388eb2aebeaSTakanori Watanabe 			return result;
389eb2aebeaSTakanori Watanabe 	} else if (strcasecmp(argv[0], "disable") == 0) {
390eb2aebeaSTakanori Watanabe 		result = set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT);
391eb2aebeaSTakanori Watanabe 		if (result == OK) {
392eb2aebeaSTakanori Watanabe 			fprintf(stdout, "LE disabled\n");
393eb2aebeaSTakanori Watanabe 			return (OK);
394eb2aebeaSTakanori Watanabe 		} else
395eb2aebeaSTakanori Watanabe 			return result;
396eb2aebeaSTakanori Watanabe 	} else
397eb2aebeaSTakanori Watanabe 		return (USAGE);
398bcff2d91STakanori Watanabe }
399bcff2d91STakanori Watanabe 
400c3f60abcSHans Petter Selasky static int
401c3f60abcSHans Petter Selasky le_set_advertising_enable(int s, int argc, char *argv[])
402c3f60abcSHans Petter Selasky {
403c3f60abcSHans Petter Selasky 	ng_hci_le_set_advertise_enable_cp cp;
404c3f60abcSHans Petter Selasky 	ng_hci_le_set_advertise_enable_rp rp;
405c3f60abcSHans Petter Selasky 	int n, enable = 0;
406c3f60abcSHans Petter Selasky 
407c3f60abcSHans Petter Selasky 	if (argc != 1)
408c3f60abcSHans Petter Selasky 		return USAGE;
409c3f60abcSHans Petter Selasky 
410c3f60abcSHans Petter Selasky 	if (strcmp(argv[0], "enable") == 0)
411c3f60abcSHans Petter Selasky 		enable = 1;
412c3f60abcSHans Petter Selasky 	else if (strcmp(argv[0], "disable") != 0)
413c3f60abcSHans Petter Selasky 		return USAGE;
414c3f60abcSHans Petter Selasky 
415c3f60abcSHans Petter Selasky 	n = sizeof(rp);
416c3f60abcSHans Petter Selasky 	cp.advertising_enable = enable;
417c3f60abcSHans Petter Selasky 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
418c3f60abcSHans Petter Selasky 		NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE),
419c3f60abcSHans Petter Selasky 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
420c3f60abcSHans Petter Selasky 		return (ERROR);
421c3f60abcSHans Petter Selasky 
422c3f60abcSHans Petter Selasky 	if (rp.status != 0x00) {
423c3f60abcSHans Petter Selasky 		fprintf(stdout, "Status: %s [%#02x]\n",
424c3f60abcSHans Petter Selasky 			hci_status2str(rp.status), rp.status);
425c3f60abcSHans Petter Selasky 		return (FAILED);
426c3f60abcSHans Petter Selasky 	}
427c3f60abcSHans Petter Selasky         fprintf(stdout, "LE Advertising %s\n", (enable ? "enabled" : "disabled"));
428c3f60abcSHans Petter Selasky 
429c3f60abcSHans Petter Selasky 	return (OK);
430c3f60abcSHans Petter Selasky }
431c3f60abcSHans Petter Selasky 
432c3f60abcSHans Petter Selasky static int
433c3f60abcSHans Petter Selasky le_set_advertising_param(int s, int argc, char *argv[])
434c3f60abcSHans Petter Selasky {
435c3f60abcSHans Petter Selasky 	ng_hci_le_set_advertising_parameters_cp cp;
436c3f60abcSHans Petter Selasky 	ng_hci_le_set_advertising_parameters_rp rp;
437c3f60abcSHans Petter Selasky 
438c3f60abcSHans Petter Selasky 	int n, ch;
439c3f60abcSHans Petter Selasky 
440c3f60abcSHans Petter Selasky 	cp.advertising_interval_min = 0x800;
441c3f60abcSHans Petter Selasky 	cp.advertising_interval_max = 0x800;
442c3f60abcSHans Petter Selasky 	cp.advertising_type = 0;
443c3f60abcSHans Petter Selasky 	cp.own_address_type = 0;
444c3f60abcSHans Petter Selasky 	cp.direct_address_type = 0;
445c3f60abcSHans Petter Selasky 
446c3f60abcSHans Petter Selasky 	cp.advertising_channel_map = 7;
447c3f60abcSHans Petter Selasky 	cp.advertising_filter_policy = 0;
448c3f60abcSHans Petter Selasky 
449c3f60abcSHans Petter Selasky 	optreset = 1;
450c3f60abcSHans Petter Selasky 	optind = 0;
451c3f60abcSHans Petter Selasky 	while ((ch = getopt(argc, argv , "m:M:t:o:p:a:c:f:")) != -1) {
452c3f60abcSHans Petter Selasky 		switch(ch) {
453c3f60abcSHans Petter Selasky 		case 'm':
454c3f60abcSHans Petter Selasky 			cp.advertising_interval_min =
455c3f60abcSHans Petter Selasky 				(uint16_t)(strtod(optarg, NULL)/0.625);
456c3f60abcSHans Petter Selasky 			break;
457c3f60abcSHans Petter Selasky 		case 'M':
458c3f60abcSHans Petter Selasky 			cp.advertising_interval_max =
459c3f60abcSHans Petter Selasky 				(uint16_t)(strtod(optarg, NULL)/0.625);
460c3f60abcSHans Petter Selasky 			break;
461c3f60abcSHans Petter Selasky 		case 't':
462c3f60abcSHans Petter Selasky 			cp.advertising_type =
463c3f60abcSHans Petter Selasky 				(uint8_t)strtod(optarg, NULL);
464c3f60abcSHans Petter Selasky 			break;
465c3f60abcSHans Petter Selasky 		case 'o':
466c3f60abcSHans Petter Selasky 			cp.own_address_type =
467c3f60abcSHans Petter Selasky 				(uint8_t)strtod(optarg, NULL);
468c3f60abcSHans Petter Selasky 			break;
469c3f60abcSHans Petter Selasky 		case 'p':
470c3f60abcSHans Petter Selasky 			cp.direct_address_type =
471c3f60abcSHans Petter Selasky 				(uint8_t)strtod(optarg, NULL);
472c3f60abcSHans Petter Selasky 			break;
473c3f60abcSHans Petter Selasky 		case 'a':
474c3f60abcSHans Petter Selasky 			if (!bt_aton(optarg, &cp.direct_address)) {
475c3f60abcSHans Petter Selasky 				struct hostent	*he = NULL;
476c3f60abcSHans Petter Selasky 
477c3f60abcSHans Petter Selasky 				if ((he = bt_gethostbyname(optarg)) == NULL)
478c3f60abcSHans Petter Selasky 					return (USAGE);
479c3f60abcSHans Petter Selasky 
480c3f60abcSHans Petter Selasky 				memcpy(&cp.direct_address, he->h_addr, sizeof(cp.direct_address));
481c3f60abcSHans Petter Selasky 			}
482c3f60abcSHans Petter Selasky 			break;
483c3f60abcSHans Petter Selasky 		case 'c':
484c3f60abcSHans Petter Selasky 			cp.advertising_channel_map =
485c3f60abcSHans Petter Selasky 				(uint8_t)strtod(optarg, NULL);
486c3f60abcSHans Petter Selasky 			break;
487c3f60abcSHans Petter Selasky 		case 'f':
488c3f60abcSHans Petter Selasky 			cp.advertising_filter_policy =
489c3f60abcSHans Petter Selasky 				(uint8_t)strtod(optarg, NULL);
490c3f60abcSHans Petter Selasky 			break;
491c3f60abcSHans Petter Selasky 		}
492c3f60abcSHans Petter Selasky 	}
493c3f60abcSHans Petter Selasky 
494c3f60abcSHans Petter Selasky 	n = sizeof(rp);
495c3f60abcSHans Petter Selasky 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
496c3f60abcSHans Petter Selasky 		NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS),
497c3f60abcSHans Petter Selasky 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
498c3f60abcSHans Petter Selasky 		return (ERROR);
499c3f60abcSHans Petter Selasky 
500c3f60abcSHans Petter Selasky 	if (rp.status != 0x00) {
501c3f60abcSHans Petter Selasky 		fprintf(stdout, "Status: %s [%#02x]\n",
502c3f60abcSHans Petter Selasky 			hci_status2str(rp.status), rp.status);
503c3f60abcSHans Petter Selasky 		return (FAILED);
504c3f60abcSHans Petter Selasky 	}
505c3f60abcSHans Petter Selasky 
506c3f60abcSHans Petter Selasky 	return (OK);
507c3f60abcSHans Petter Selasky }
508c3f60abcSHans Petter Selasky 
509c3f60abcSHans Petter Selasky static int
510c3f60abcSHans Petter Selasky le_read_advertising_channel_tx_power(int s, int argc, char *argv[])
511c3f60abcSHans Petter Selasky {
512c3f60abcSHans Petter Selasky 	ng_hci_le_read_advertising_channel_tx_power_rp rp;
513c3f60abcSHans Petter Selasky 	int n;
514c3f60abcSHans Petter Selasky 
515c3f60abcSHans Petter Selasky 	n = sizeof(rp);
516c3f60abcSHans Petter Selasky 
517c3f60abcSHans Petter Selasky 	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
518c3f60abcSHans Petter Selasky 		NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER),
519c3f60abcSHans Petter Selasky 		(void *)&rp, &n) == ERROR)
520c3f60abcSHans Petter Selasky 		return (ERROR);
521c3f60abcSHans Petter Selasky 
522c3f60abcSHans Petter Selasky 	if (rp.status != 0x00) {
523c3f60abcSHans Petter Selasky 		fprintf(stdout, "Status: %s [%#02x]\n",
524c3f60abcSHans Petter Selasky 			hci_status2str(rp.status), rp.status);
525c3f60abcSHans Petter Selasky 		return (FAILED);
526c3f60abcSHans Petter Selasky 	}
527c3f60abcSHans Petter Selasky 
528c3f60abcSHans Petter Selasky         fprintf(stdout, "Advertising transmit power level: %d dBm\n",
529c3f60abcSHans Petter Selasky 		(int8_t)rp.transmit_power_level);
530c3f60abcSHans Petter Selasky 
531c3f60abcSHans Petter Selasky 	return (OK);
532c3f60abcSHans Petter Selasky }
533c3f60abcSHans Petter Selasky 
534c3f60abcSHans Petter Selasky static int
535c3f60abcSHans Petter Selasky le_set_advertising_data(int s, int argc, char *argv[])
536c3f60abcSHans Petter Selasky {
537c3f60abcSHans Petter Selasky 	ng_hci_le_set_advertising_data_cp cp;
538c3f60abcSHans Petter Selasky 	ng_hci_le_set_advertising_data_rp rp;
539c3f60abcSHans Petter Selasky 	int n, len;
540c3f60abcSHans Petter Selasky 
541c3f60abcSHans Petter Selasky 	n = sizeof(rp);
542c3f60abcSHans Petter Selasky 
543c3f60abcSHans Petter Selasky 	char buf[NG_HCI_ADVERTISING_DATA_SIZE];
544c3f60abcSHans Petter Selasky 
545c3f60abcSHans Petter Selasky 	len = sizeof(buf);
546c3f60abcSHans Petter Selasky 	parse_param(argc, argv, buf, &len);
547c3f60abcSHans Petter Selasky 	memset(cp.advertising_data, 0, sizeof(cp.advertising_data));
548c3f60abcSHans Petter Selasky 	cp.advertising_data_length = len;
5497b2f84dbSHans Petter Selasky 	memcpy(cp.advertising_data, buf, len);
550c3f60abcSHans Petter Selasky 
551c3f60abcSHans Petter Selasky 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
552c3f60abcSHans Petter Selasky 		NG_HCI_OCF_LE_SET_ADVERTISING_DATA),
553c3f60abcSHans Petter Selasky 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
554c3f60abcSHans Petter Selasky 		return (ERROR);
555c3f60abcSHans Petter Selasky 
556c3f60abcSHans Petter Selasky 	if (rp.status != 0x00) {
557c3f60abcSHans Petter Selasky 		fprintf(stdout, "Status: %s [%#02x]\n",
558c3f60abcSHans Petter Selasky 			hci_status2str(rp.status), rp.status);
559c3f60abcSHans Petter Selasky 		return (FAILED);
560c3f60abcSHans Petter Selasky 	}
561c3f60abcSHans Petter Selasky 
562c3f60abcSHans Petter Selasky 	return (OK);
563c3f60abcSHans Petter Selasky }
5641f5d883dSTakanori Watanabe static int
5651f5d883dSTakanori Watanabe le_read_buffer_size(int s, int argc, char *argv[])
5661f5d883dSTakanori Watanabe {
5671f5d883dSTakanori Watanabe 	union {
5681f5d883dSTakanori Watanabe 		ng_hci_le_read_buffer_size_rp 		v1;
5691f5d883dSTakanori Watanabe 		ng_hci_le_read_buffer_size_rp_v2	v2;
5701f5d883dSTakanori Watanabe 	} rp;
5711f5d883dSTakanori Watanabe 
5721f5d883dSTakanori Watanabe 	int n, ch;
5731f5d883dSTakanori Watanabe 	uint8_t v;
5741f5d883dSTakanori Watanabe 	uint16_t cmd;
5751f5d883dSTakanori Watanabe 
5761f5d883dSTakanori Watanabe 	optreset = 1;
5771f5d883dSTakanori Watanabe 	optind = 0;
5781f5d883dSTakanori Watanabe 
5791f5d883dSTakanori Watanabe 	/* Default to version 1*/
5801f5d883dSTakanori Watanabe 	v = 1;
5811f5d883dSTakanori Watanabe 	cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE;
5821f5d883dSTakanori Watanabe 
5831f5d883dSTakanori Watanabe 	while ((ch = getopt(argc, argv , "v:")) != -1) {
5841f5d883dSTakanori Watanabe 		switch(ch) {
5851f5d883dSTakanori Watanabe 		case 'v':
5861f5d883dSTakanori Watanabe 			v = (uint8_t)strtol(optarg, NULL, 16);
5871f5d883dSTakanori Watanabe 			if (v == 2)
5881f5d883dSTakanori Watanabe 				cmd = NG_HCI_OCF_LE_READ_BUFFER_SIZE_V2;
5891f5d883dSTakanori Watanabe 			else if (v > 2)
5901f5d883dSTakanori Watanabe 				return (USAGE);
5911f5d883dSTakanori Watanabe 			break;
5921f5d883dSTakanori Watanabe 		default:
5931f5d883dSTakanori Watanabe 			v = 1;
5941f5d883dSTakanori Watanabe 		}
5951f5d883dSTakanori Watanabe 	}
5961f5d883dSTakanori Watanabe 
5971f5d883dSTakanori Watanabe 	n = sizeof(rp);
5981f5d883dSTakanori Watanabe 	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE, cmd),
5991f5d883dSTakanori Watanabe 		(void *)&rp, &n) == ERROR)
6001f5d883dSTakanori Watanabe 		return (ERROR);
6011f5d883dSTakanori Watanabe 
6021f5d883dSTakanori Watanabe 	if (rp.v1.status != 0x00) {
6031f5d883dSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
6041f5d883dSTakanori Watanabe 			hci_status2str(rp.v1.status), rp.v1.status);
6051f5d883dSTakanori Watanabe 		return (FAILED);
6061f5d883dSTakanori Watanabe 	}
6071f5d883dSTakanori Watanabe 
6081f5d883dSTakanori Watanabe 	fprintf(stdout, "ACL data packet length: %d\n",
6091f5d883dSTakanori Watanabe 		rp.v1.hc_le_data_packet_length);
6101f5d883dSTakanori Watanabe 	fprintf(stdout, "Number of ACL data packets: %d\n",
6111f5d883dSTakanori Watanabe 		rp.v1.hc_total_num_le_data_packets);
6121f5d883dSTakanori Watanabe 
6131f5d883dSTakanori Watanabe 	if (v == 2) {
6141f5d883dSTakanori Watanabe 		fprintf(stdout, "ISO data packet length: %d\n",
6151f5d883dSTakanori Watanabe 			rp.v2.hc_iso_data_packet_length);
6161f5d883dSTakanori Watanabe 		fprintf(stdout, "Number of ISO data packets: %d\n",
6171f5d883dSTakanori Watanabe 			rp.v2.hc_total_num_iso_data_packets);
6181f5d883dSTakanori Watanabe 	}
6191f5d883dSTakanori Watanabe 
6201f5d883dSTakanori Watanabe 	return (OK);
6211f5d883dSTakanori Watanabe }
622c3f60abcSHans Petter Selasky 
6239287f06dSTakanori Watanabe static int
6249287f06dSTakanori Watanabe le_scan(int s, int argc, char *argv[])
6259287f06dSTakanori Watanabe {
6269287f06dSTakanori Watanabe 	int n, bufsize, scancount, numscans;
6279287f06dSTakanori Watanabe 	bool verbose;
6289287f06dSTakanori Watanabe 	uint8_t active = 0;
6299287f06dSTakanori Watanabe 	char ch;
6309287f06dSTakanori Watanabe 
6319287f06dSTakanori Watanabe 	char			 b[512];
6329287f06dSTakanori Watanabe 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
6339287f06dSTakanori Watanabe 
6349287f06dSTakanori Watanabe 	ng_hci_le_set_scan_parameters_cp scan_param_cp;
6359287f06dSTakanori Watanabe 	ng_hci_le_set_scan_parameters_rp scan_param_rp;
6369287f06dSTakanori Watanabe 
6379287f06dSTakanori Watanabe 	ng_hci_le_set_scan_enable_cp scan_enable_cp;
6389287f06dSTakanori Watanabe 	ng_hci_le_set_scan_enable_rp scan_enable_rp;
6399287f06dSTakanori Watanabe 
6409287f06dSTakanori Watanabe 	optreset = 1;
6419287f06dSTakanori Watanabe 	optind = 0;
6429287f06dSTakanori Watanabe 	verbose = false;
6439287f06dSTakanori Watanabe 	numscans = 1;
6449287f06dSTakanori Watanabe 
6459287f06dSTakanori Watanabe 	while ((ch = getopt(argc, argv , "an:v")) != -1) {
6469287f06dSTakanori Watanabe 		switch(ch) {
6479287f06dSTakanori Watanabe 		case 'a':
6489287f06dSTakanori Watanabe 			active = 1;
6499287f06dSTakanori Watanabe 			break;
6509287f06dSTakanori Watanabe 		case 'n':
6519287f06dSTakanori Watanabe 			numscans = (uint8_t)strtol(optarg, NULL, 10);
6529287f06dSTakanori Watanabe 			break;
6539287f06dSTakanori Watanabe 		case 'v':
6549287f06dSTakanori Watanabe 			verbose = true;
6559287f06dSTakanori Watanabe 			break;
6569287f06dSTakanori Watanabe 		}
6579287f06dSTakanori Watanabe 	}
6589287f06dSTakanori Watanabe 
6599287f06dSTakanori Watanabe 	scan_param_cp.le_scan_type = active;
6609287f06dSTakanori Watanabe 	scan_param_cp.le_scan_interval = (uint16_t)(100/0.625);
6619287f06dSTakanori Watanabe 	scan_param_cp.le_scan_window = (uint16_t)(50/0.625);
6629287f06dSTakanori Watanabe 	/* Address type public */
6639287f06dSTakanori Watanabe 	scan_param_cp.own_address_type = 0;
6649287f06dSTakanori Watanabe 	/* 'All' filter policy */
6659287f06dSTakanori Watanabe 	scan_param_cp.scanning_filter_policy = 0;
6669287f06dSTakanori Watanabe 	n = sizeof(scan_param_rp);
6679287f06dSTakanori Watanabe 
6689287f06dSTakanori Watanabe 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
6699287f06dSTakanori Watanabe 		NG_HCI_OCF_LE_SET_SCAN_PARAMETERS),
6709287f06dSTakanori Watanabe 		(void *)&scan_param_cp, sizeof(scan_param_cp),
6719287f06dSTakanori Watanabe 		(void *)&scan_param_rp, &n) == ERROR)
6729287f06dSTakanori Watanabe 		return (ERROR);
6739287f06dSTakanori Watanabe 
6749287f06dSTakanori Watanabe 	if (scan_param_rp.status != 0x00) {
6759287f06dSTakanori Watanabe 		fprintf(stdout, "LE_Set_Scan_Parameters failed. Status: %s [%#02x]\n",
6769287f06dSTakanori Watanabe 			hci_status2str(scan_param_rp.status),
6779287f06dSTakanori Watanabe 			scan_param_rp.status);
6789287f06dSTakanori Watanabe 		return (FAILED);
6799287f06dSTakanori Watanabe 	}
6809287f06dSTakanori Watanabe 
6819287f06dSTakanori Watanabe 	/* Enable scanning */
6829287f06dSTakanori Watanabe 	n = sizeof(scan_enable_rp);
6839287f06dSTakanori Watanabe 	scan_enable_cp.le_scan_enable = 1;
6849287f06dSTakanori Watanabe 	scan_enable_cp.filter_duplicates = 1;
6859287f06dSTakanori Watanabe 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
6869287f06dSTakanori Watanabe 		NG_HCI_OCF_LE_SET_SCAN_ENABLE),
6879287f06dSTakanori Watanabe 		(void *)&scan_enable_cp, sizeof(scan_enable_cp),
6889287f06dSTakanori Watanabe 		(void *)&scan_enable_rp, &n) == ERROR)
6899287f06dSTakanori Watanabe 		return (ERROR);
6909287f06dSTakanori Watanabe 
6919287f06dSTakanori Watanabe 	if (scan_enable_rp.status != 0x00) {
6929287f06dSTakanori Watanabe 		fprintf(stdout, "LE_Scan_Enable enable failed. Status: %s [%#02x]\n",
6939287f06dSTakanori Watanabe 			hci_status2str(scan_enable_rp.status),
6949287f06dSTakanori Watanabe 			scan_enable_rp.status);
6959287f06dSTakanori Watanabe 		return (FAILED);
6969287f06dSTakanori Watanabe 	}
6979287f06dSTakanori Watanabe 
6989287f06dSTakanori Watanabe 	scancount = 0;
6999287f06dSTakanori Watanabe 	while (scancount < numscans) {
7009287f06dSTakanori Watanabe 		/* wait for scan events */
7019287f06dSTakanori Watanabe 		bufsize = sizeof(b);
7029287f06dSTakanori Watanabe 		if (hci_recv(s, b, &bufsize) == ERROR) {
7039287f06dSTakanori Watanabe 			return (ERROR);
7049287f06dSTakanori Watanabe 		}
7059287f06dSTakanori Watanabe 
7069287f06dSTakanori Watanabe 		if (bufsize < sizeof(*e)) {
7079287f06dSTakanori Watanabe 			errno = EIO;
7089287f06dSTakanori Watanabe 			return (ERROR);
7099287f06dSTakanori Watanabe 		}
7109287f06dSTakanori Watanabe 		scancount++;
7119287f06dSTakanori Watanabe 		if (e->event == NG_HCI_EVENT_LE) {
7129287f06dSTakanori Watanabe 		 	fprintf(stdout, "Scan %d\n", scancount);
7139287f06dSTakanori Watanabe 			handle_le_event(e, verbose);
7149287f06dSTakanori Watanabe 		}
7159287f06dSTakanori Watanabe 	}
7169287f06dSTakanori Watanabe 
7179287f06dSTakanori Watanabe 	fprintf(stdout, "Scan complete\n");
7189287f06dSTakanori Watanabe 
7199287f06dSTakanori Watanabe 	/* Disable scanning */
7209287f06dSTakanori Watanabe 	n = sizeof(scan_enable_rp);
7219287f06dSTakanori Watanabe 	scan_enable_cp.le_scan_enable = 0;
7229287f06dSTakanori Watanabe 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
7239287f06dSTakanori Watanabe 		NG_HCI_OCF_LE_SET_SCAN_ENABLE),
7249287f06dSTakanori Watanabe 		(void *)&scan_enable_cp, sizeof(scan_enable_cp),
7259287f06dSTakanori Watanabe 		(void *)&scan_enable_rp, &n) == ERROR)
7269287f06dSTakanori Watanabe 		return (ERROR);
7279287f06dSTakanori Watanabe 
7289287f06dSTakanori Watanabe 	if (scan_enable_rp.status != 0x00) {
7299287f06dSTakanori Watanabe 		fprintf(stdout, "LE_Scan_Enable disable failed. Status: %s [%#02x]\n",
7309287f06dSTakanori Watanabe 			hci_status2str(scan_enable_rp.status),
7319287f06dSTakanori Watanabe 			scan_enable_rp.status);
7329287f06dSTakanori Watanabe 		return (FAILED);
7339287f06dSTakanori Watanabe 	}
7349287f06dSTakanori Watanabe 
7359287f06dSTakanori Watanabe 	return (OK);
7369287f06dSTakanori Watanabe }
7379287f06dSTakanori Watanabe 
7389287f06dSTakanori Watanabe static void handle_le_event(ng_hci_event_pkt_t* e, bool verbose)
7399287f06dSTakanori Watanabe {
7409287f06dSTakanori Watanabe 	int rc;
7419287f06dSTakanori Watanabe 	ng_hci_le_ep	*leer =
7429287f06dSTakanori Watanabe 			(ng_hci_le_ep *)(e + 1);
7439287f06dSTakanori Watanabe 	ng_hci_le_advertising_report_ep *advrep =
7449287f06dSTakanori Watanabe 		(ng_hci_le_advertising_report_ep *)(leer + 1);
7459287f06dSTakanori Watanabe 	ng_hci_le_advreport	*reports =
7469287f06dSTakanori Watanabe 		(ng_hci_le_advreport *)(advrep + 1);
7479287f06dSTakanori Watanabe 
7489287f06dSTakanori Watanabe 	if (leer->subevent_code == NG_HCI_LEEV_ADVREP) {
7499287f06dSTakanori Watanabe 		fprintf(stdout, "Scan result, num_reports: %d\n",
7509287f06dSTakanori Watanabe 			advrep->num_reports);
7519287f06dSTakanori Watanabe 		for(rc = 0; rc < advrep->num_reports; rc++) {
7529287f06dSTakanori Watanabe 			uint8_t length = (uint8_t)reports[rc].length_data;
7539287f06dSTakanori Watanabe 			fprintf(stdout, "\tBD_ADDR %s \n",
7549287f06dSTakanori Watanabe 				hci_bdaddr2str(&reports[rc].bdaddr));
7559287f06dSTakanori Watanabe 			fprintf(stdout, "\tAddress type: %s\n",
7569287f06dSTakanori Watanabe 				hci_addrtype2str(reports[rc].addr_type));
7579287f06dSTakanori Watanabe 			if (length > 0 && verbose) {
7589287f06dSTakanori Watanabe 				dump_adv_data(length, reports[rc].data);
7599287f06dSTakanori Watanabe 				print_adv_data(length, reports[rc].data);
7609287f06dSTakanori Watanabe 				fprintf(stdout,
7619287f06dSTakanori Watanabe 					"\tRSSI: %d dBm\n",
7629287f06dSTakanori Watanabe 					(int8_t)reports[rc].data[length]);
7639287f06dSTakanori Watanabe 				fprintf(stdout, "\n");
7649287f06dSTakanori Watanabe 			}
7659287f06dSTakanori Watanabe 		}
7669287f06dSTakanori Watanabe 	}
7679287f06dSTakanori Watanabe }
7689287f06dSTakanori Watanabe 
769*11fb4bdbSTakanori Watanabe static int
770*11fb4bdbSTakanori Watanabe le_read_white_list_size(int s, int argc, char *argv[])
771*11fb4bdbSTakanori Watanabe {
772*11fb4bdbSTakanori Watanabe 	ng_hci_le_read_white_list_size_rp rp;
773*11fb4bdbSTakanori Watanabe 	int n;
774*11fb4bdbSTakanori Watanabe 
775*11fb4bdbSTakanori Watanabe 	n = sizeof(rp);
776*11fb4bdbSTakanori Watanabe 
777*11fb4bdbSTakanori Watanabe 	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
778*11fb4bdbSTakanori Watanabe 		NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE),
779*11fb4bdbSTakanori Watanabe 		(void *)&rp, &n) == ERROR)
780*11fb4bdbSTakanori Watanabe 		return (ERROR);
781*11fb4bdbSTakanori Watanabe 
782*11fb4bdbSTakanori Watanabe 	if (rp.status != 0x00) {
783*11fb4bdbSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
784*11fb4bdbSTakanori Watanabe 			hci_status2str(rp.status), rp.status);
785*11fb4bdbSTakanori Watanabe 		return (FAILED);
786*11fb4bdbSTakanori Watanabe 	}
787*11fb4bdbSTakanori Watanabe 
788*11fb4bdbSTakanori Watanabe         fprintf(stdout, "White list size: %d\n",
789*11fb4bdbSTakanori Watanabe 		(uint8_t)rp.white_list_size);
790*11fb4bdbSTakanori Watanabe 
791*11fb4bdbSTakanori Watanabe 	return (OK);
792*11fb4bdbSTakanori Watanabe }
793*11fb4bdbSTakanori Watanabe 
794*11fb4bdbSTakanori Watanabe static int
795*11fb4bdbSTakanori Watanabe le_clear_white_list(int s, int argc, char *argv[])
796*11fb4bdbSTakanori Watanabe {
797*11fb4bdbSTakanori Watanabe 	ng_hci_le_clear_white_list_rp rp;
798*11fb4bdbSTakanori Watanabe 	int n;
799*11fb4bdbSTakanori Watanabe 
800*11fb4bdbSTakanori Watanabe 	n = sizeof(rp);
801*11fb4bdbSTakanori Watanabe 
802*11fb4bdbSTakanori Watanabe 	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
803*11fb4bdbSTakanori Watanabe 		NG_HCI_OCF_LE_CLEAR_WHITE_LIST),
804*11fb4bdbSTakanori Watanabe 		(void *)&rp, &n) == ERROR)
805*11fb4bdbSTakanori Watanabe 		return (ERROR);
806*11fb4bdbSTakanori Watanabe 
807*11fb4bdbSTakanori Watanabe 	if (rp.status != 0x00) {
808*11fb4bdbSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
809*11fb4bdbSTakanori Watanabe 			hci_status2str(rp.status), rp.status);
810*11fb4bdbSTakanori Watanabe 		return (FAILED);
811*11fb4bdbSTakanori Watanabe 	}
812*11fb4bdbSTakanori Watanabe 
813*11fb4bdbSTakanori Watanabe         fprintf(stdout, "White list cleared\n");
814*11fb4bdbSTakanori Watanabe 
815*11fb4bdbSTakanori Watanabe 	return (OK);
816*11fb4bdbSTakanori Watanabe }
817*11fb4bdbSTakanori Watanabe 
818*11fb4bdbSTakanori Watanabe static int
819*11fb4bdbSTakanori Watanabe le_add_device_to_white_list(int s, int argc, char *argv[])
820*11fb4bdbSTakanori Watanabe {
821*11fb4bdbSTakanori Watanabe 	ng_hci_le_add_device_to_white_list_cp cp;
822*11fb4bdbSTakanori Watanabe 	ng_hci_le_add_device_to_white_list_rp rp;
823*11fb4bdbSTakanori Watanabe 	int n;
824*11fb4bdbSTakanori Watanabe 	char ch;
825*11fb4bdbSTakanori Watanabe 	optreset = 1;
826*11fb4bdbSTakanori Watanabe 	optind = 0;
827*11fb4bdbSTakanori Watanabe 	bool addr_set = false;
828*11fb4bdbSTakanori Watanabe 
829*11fb4bdbSTakanori Watanabe 	n = sizeof(rp);
830*11fb4bdbSTakanori Watanabe 
831*11fb4bdbSTakanori Watanabe 	cp.address_type = 0x00;
832*11fb4bdbSTakanori Watanabe 
833*11fb4bdbSTakanori Watanabe 	while ((ch = getopt(argc, argv , "t:a:")) != -1) {
834*11fb4bdbSTakanori Watanabe 		switch(ch) {
835*11fb4bdbSTakanori Watanabe 		case 't':
836*11fb4bdbSTakanori Watanabe 			if (strcmp(optarg, "public") == 0)
837*11fb4bdbSTakanori Watanabe 				cp.address_type = 0x00;
838*11fb4bdbSTakanori Watanabe 			else if (strcmp(optarg, "random") == 0)
839*11fb4bdbSTakanori Watanabe 				cp.address_type = 0x01;
840*11fb4bdbSTakanori Watanabe 			else
841*11fb4bdbSTakanori Watanabe 				return (USAGE);
842*11fb4bdbSTakanori Watanabe 			break;
843*11fb4bdbSTakanori Watanabe 		case 'a':
844*11fb4bdbSTakanori Watanabe 			addr_set = true;
845*11fb4bdbSTakanori Watanabe 			if (!bt_aton(optarg, &cp.address)) {
846*11fb4bdbSTakanori Watanabe 				struct hostent	*he = NULL;
847*11fb4bdbSTakanori Watanabe 
848*11fb4bdbSTakanori Watanabe 				if ((he = bt_gethostbyname(optarg)) == NULL)
849*11fb4bdbSTakanori Watanabe 					return (USAGE);
850*11fb4bdbSTakanori Watanabe 
851*11fb4bdbSTakanori Watanabe 				memcpy(&cp.address, he->h_addr,
852*11fb4bdbSTakanori Watanabe 					sizeof(cp.address));
853*11fb4bdbSTakanori Watanabe 			}
854*11fb4bdbSTakanori Watanabe 			break;
855*11fb4bdbSTakanori Watanabe 		}
856*11fb4bdbSTakanori Watanabe 	}
857*11fb4bdbSTakanori Watanabe 
858*11fb4bdbSTakanori Watanabe 	if (addr_set == false)
859*11fb4bdbSTakanori Watanabe 		return (USAGE);
860*11fb4bdbSTakanori Watanabe 
861*11fb4bdbSTakanori Watanabe 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
862*11fb4bdbSTakanori Watanabe 		NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST),
863*11fb4bdbSTakanori Watanabe 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
864*11fb4bdbSTakanori Watanabe 		return (ERROR);
865*11fb4bdbSTakanori Watanabe 
866*11fb4bdbSTakanori Watanabe 	if (rp.status != 0x00) {
867*11fb4bdbSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
868*11fb4bdbSTakanori Watanabe 			hci_status2str(rp.status), rp.status);
869*11fb4bdbSTakanori Watanabe 		return (FAILED);
870*11fb4bdbSTakanori Watanabe 	}
871*11fb4bdbSTakanori Watanabe 
872*11fb4bdbSTakanori Watanabe         fprintf(stdout, "Address added to white list\n");
873*11fb4bdbSTakanori Watanabe 
874*11fb4bdbSTakanori Watanabe 	return (OK);
875*11fb4bdbSTakanori Watanabe }
876*11fb4bdbSTakanori Watanabe 
877*11fb4bdbSTakanori Watanabe static int
878*11fb4bdbSTakanori Watanabe le_remove_device_from_white_list(int s, int argc, char *argv[])
879*11fb4bdbSTakanori Watanabe {
880*11fb4bdbSTakanori Watanabe 	ng_hci_le_remove_device_from_white_list_cp cp;
881*11fb4bdbSTakanori Watanabe 	ng_hci_le_remove_device_from_white_list_rp rp;
882*11fb4bdbSTakanori Watanabe 	int n;
883*11fb4bdbSTakanori Watanabe 	char ch;
884*11fb4bdbSTakanori Watanabe 	optreset = 1;
885*11fb4bdbSTakanori Watanabe 	optind = 0;
886*11fb4bdbSTakanori Watanabe 	bool addr_set = false;
887*11fb4bdbSTakanori Watanabe 
888*11fb4bdbSTakanori Watanabe 	n = sizeof(rp);
889*11fb4bdbSTakanori Watanabe 
890*11fb4bdbSTakanori Watanabe 	cp.address_type = 0x00;
891*11fb4bdbSTakanori Watanabe 
892*11fb4bdbSTakanori Watanabe 	while ((ch = getopt(argc, argv , "t:a:")) != -1) {
893*11fb4bdbSTakanori Watanabe 		switch(ch) {
894*11fb4bdbSTakanori Watanabe 		case 't':
895*11fb4bdbSTakanori Watanabe 			if (strcmp(optarg, "public") == 0)
896*11fb4bdbSTakanori Watanabe 				cp.address_type = 0x00;
897*11fb4bdbSTakanori Watanabe 			else if (strcmp(optarg, "random") == 0)
898*11fb4bdbSTakanori Watanabe 				cp.address_type = 0x01;
899*11fb4bdbSTakanori Watanabe 			else
900*11fb4bdbSTakanori Watanabe 				return (USAGE);
901*11fb4bdbSTakanori Watanabe 			break;
902*11fb4bdbSTakanori Watanabe 		case 'a':
903*11fb4bdbSTakanori Watanabe 			addr_set = true;
904*11fb4bdbSTakanori Watanabe 			if (!bt_aton(optarg, &cp.address)) {
905*11fb4bdbSTakanori Watanabe 				struct hostent	*he = NULL;
906*11fb4bdbSTakanori Watanabe 
907*11fb4bdbSTakanori Watanabe 				if ((he = bt_gethostbyname(optarg)) == NULL)
908*11fb4bdbSTakanori Watanabe 					return (USAGE);
909*11fb4bdbSTakanori Watanabe 
910*11fb4bdbSTakanori Watanabe 				memcpy(&cp.address, he->h_addr,
911*11fb4bdbSTakanori Watanabe 					sizeof(cp.address));
912*11fb4bdbSTakanori Watanabe 			}
913*11fb4bdbSTakanori Watanabe 			break;
914*11fb4bdbSTakanori Watanabe 		}
915*11fb4bdbSTakanori Watanabe 	}
916*11fb4bdbSTakanori Watanabe 
917*11fb4bdbSTakanori Watanabe 	if (addr_set == false)
918*11fb4bdbSTakanori Watanabe 		return (USAGE);
919*11fb4bdbSTakanori Watanabe 
920*11fb4bdbSTakanori Watanabe 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
921*11fb4bdbSTakanori Watanabe 		NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST),
922*11fb4bdbSTakanori Watanabe 		(void *)&cp, sizeof(cp), (void *)&rp, &n) == ERROR)
923*11fb4bdbSTakanori Watanabe 		return (ERROR);
924*11fb4bdbSTakanori Watanabe 
925*11fb4bdbSTakanori Watanabe 	if (rp.status != 0x00) {
926*11fb4bdbSTakanori Watanabe 		fprintf(stdout, "Status: %s [%#02x]\n",
927*11fb4bdbSTakanori Watanabe 			hci_status2str(rp.status), rp.status);
928*11fb4bdbSTakanori Watanabe 		return (FAILED);
929*11fb4bdbSTakanori Watanabe 	}
930*11fb4bdbSTakanori Watanabe 
931*11fb4bdbSTakanori Watanabe         fprintf(stdout, "Address removed from white list\n");
932*11fb4bdbSTakanori Watanabe 
933*11fb4bdbSTakanori Watanabe 	return (OK);
934*11fb4bdbSTakanori Watanabe }
935*11fb4bdbSTakanori Watanabe 
936bcff2d91STakanori Watanabe struct hci_command le_commands[] = {
937bcff2d91STakanori Watanabe {
938bcff2d91STakanori Watanabe 	"le_enable",
939bcff2d91STakanori Watanabe 	"le_enable [enable|disable] \n"
940bcff2d91STakanori Watanabe 	"Enable LE event ",
941bcff2d91STakanori Watanabe 	&le_enable,
942bcff2d91STakanori Watanabe },
943bcff2d91STakanori Watanabe   {
944bcff2d91STakanori Watanabe 	  "le_read_local_supported_features",
945bcff2d91STakanori Watanabe 	  "le_read_local_supported_features\n"
946bcff2d91STakanori Watanabe 	  "read local supported features mask",
947bcff2d91STakanori Watanabe 	  &le_read_local_supported_features,
948bcff2d91STakanori Watanabe   },
949bcff2d91STakanori Watanabe   {
95021eefd31SHans Petter Selasky 	  "le_read_supported_states",
95121eefd31SHans Petter Selasky 	  "le_read_supported_states\n"
952bcff2d91STakanori Watanabe 	  "read supported status"
953bcff2d91STakanori Watanabe 	  ,
95421eefd31SHans Petter Selasky 	  &le_read_supported_states,
955bcff2d91STakanori Watanabe   },
956bcff2d91STakanori Watanabe   {
957bcff2d91STakanori Watanabe 	  "le_set_scan_response",
958bcff2d91STakanori Watanabe 	  "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n"
959bcff2d91STakanori Watanabe 	  "set LE scan response data"
960bcff2d91STakanori Watanabe 	  ,
961bcff2d91STakanori Watanabe 	  &le_set_scan_response,
962bcff2d91STakanori Watanabe   },
963bcff2d91STakanori Watanabe   {
964bcff2d91STakanori Watanabe 	  "le_set_scan_enable",
965bcff2d91STakanori Watanabe 	  "le_set_scan_enable [enable|disable] \n"
966bcff2d91STakanori Watanabe 	  "enable or disable LE device scan",
967bcff2d91STakanori Watanabe 	  &le_set_scan_enable
968bcff2d91STakanori Watanabe   },
969bcff2d91STakanori Watanabe   {
970bcff2d91STakanori Watanabe 	  "le_set_scan_param",
971bcff2d91STakanori Watanabe 	  "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n"
972bcff2d91STakanori Watanabe 	  "set LE device scan parameter",
973bcff2d91STakanori Watanabe 	  &le_set_scan_param
974bcff2d91STakanori Watanabe   },
975c3f60abcSHans Petter Selasky   {
976c3f60abcSHans Petter Selasky 	  "le_set_advertising_enable",
977c3f60abcSHans Petter Selasky 	  "le_set_advertising_enable [enable|disable] \n"
978c3f60abcSHans Petter Selasky 	  "start or stop advertising",
979c3f60abcSHans Petter Selasky 	  &le_set_advertising_enable
980c3f60abcSHans Petter Selasky   },
981c3f60abcSHans Petter Selasky   {
982c3f60abcSHans Petter Selasky 	  "le_read_advertising_channel_tx_power",
983c3f60abcSHans Petter Selasky 	  "le_read_advertising_channel_tx_power\n"
984c3f60abcSHans Petter Selasky 	  "read host advertising transmit poser level (dBm)",
985c3f60abcSHans Petter Selasky 	  &le_read_advertising_channel_tx_power
986c3f60abcSHans Petter Selasky   },
987c3f60abcSHans Petter Selasky   {
988c3f60abcSHans Petter Selasky 	  "le_set_advertising_param",
989c3f60abcSHans Petter Selasky 	  "le_set_advertising_param  [-m min_interval(ms)] [-M max_interval(ms)]\n"
990c3f60abcSHans Petter Selasky 	  "[-t advertising_type] [-o own_address_type] [-p peer_address_type]\n"
991c3f60abcSHans Petter Selasky 	  "[-c advertising_channel_map] [-f advertising_filter_policy]\n"
992c3f60abcSHans Petter Selasky 	  "[-a peer_address]\n"
993c3f60abcSHans Petter Selasky 	  "set LE device advertising parameters",
994c3f60abcSHans Petter Selasky 	  &le_set_advertising_param
995c3f60abcSHans Petter Selasky   },
996c3f60abcSHans Petter Selasky   {
997c3f60abcSHans Petter Selasky 	  "le_set_advertising_data",
998c3f60abcSHans Petter Selasky 	  "le_set_advertising_data -n $name -f $flag -u $uuid16,$uuid16 \n"
999c3f60abcSHans Petter Selasky 	  "set LE device advertising packed data",
1000c3f60abcSHans Petter Selasky 	  &le_set_advertising_data
1001c3f60abcSHans Petter Selasky   },
10021f5d883dSTakanori Watanabe   {
10031f5d883dSTakanori Watanabe 	  "le_read_buffer_size",
10041f5d883dSTakanori Watanabe 	  "le_read_buffer_size [-v 1|2]\n"
10051f5d883dSTakanori Watanabe 	  "Read the maximum size of ACL and ISO data packets",
10061f5d883dSTakanori Watanabe 	  &le_read_buffer_size
10071f5d883dSTakanori Watanabe   },
10089287f06dSTakanori Watanabe   {
10099287f06dSTakanori Watanabe 	  "le_scan",
10109287f06dSTakanori Watanabe 	  "le_scan [-a] [-v] [-n number_of_scans]\n"
10119287f06dSTakanori Watanabe 	  "Do an LE scan",
10129287f06dSTakanori Watanabe 	  &le_scan
10139287f06dSTakanori Watanabe   },
1014*11fb4bdbSTakanori Watanabe   {
1015*11fb4bdbSTakanori Watanabe 	  "le_read_white_list_size",
1016*11fb4bdbSTakanori Watanabe 	  "le_read_white_list_size\n"
1017*11fb4bdbSTakanori Watanabe 	  "Read total number of white list entries that can be stored",
1018*11fb4bdbSTakanori Watanabe 	  &le_read_white_list_size
1019*11fb4bdbSTakanori Watanabe   },
1020*11fb4bdbSTakanori Watanabe   {
1021*11fb4bdbSTakanori Watanabe 	  "le_clear_white_list",
1022*11fb4bdbSTakanori Watanabe 	  "le_clear_white_list\n"
1023*11fb4bdbSTakanori Watanabe 	  "Clear the white list in the controller",
1024*11fb4bdbSTakanori Watanabe 	  &le_clear_white_list
1025*11fb4bdbSTakanori Watanabe   },
1026*11fb4bdbSTakanori Watanabe   {
1027*11fb4bdbSTakanori Watanabe 	  "le_add_device_to_white_list",
1028*11fb4bdbSTakanori Watanabe 	  "le_add_device_to_white_list\n"
1029*11fb4bdbSTakanori Watanabe 	  "[-t public|random] -a address\n"
1030*11fb4bdbSTakanori Watanabe 	  "Add device to the white list",
1031*11fb4bdbSTakanori Watanabe 	  &le_add_device_to_white_list
1032*11fb4bdbSTakanori Watanabe   },
1033*11fb4bdbSTakanori Watanabe   {
1034*11fb4bdbSTakanori Watanabe 	  "le_remove_device_from_white_list",
1035*11fb4bdbSTakanori Watanabe 	  "le_remove_device_from_white_list\n"
1036*11fb4bdbSTakanori Watanabe 	  "[-t public|random] -a address\n"
1037*11fb4bdbSTakanori Watanabe 	  "Remove device from the white list",
1038*11fb4bdbSTakanori Watanabe 	  &le_remove_device_from_white_list
1039*11fb4bdbSTakanori Watanabe   },
1040bcff2d91STakanori Watanabe };
1041