host_controller_baseband.c revision 128079
1/*
2 * host_controller_baseband.c
3 *
4 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
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: host_controller_baseband.c,v 1.4 2003/08/18 19:19:53 max Exp $
29 * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/host_controller_baseband.c 128079 2004-04-09 23:58:53Z emax $
30 */
31
32#include <bluetooth.h>
33#include <errno.h>
34#include <stdio.h>
35#include <string.h>
36#include "hccontrol.h"
37
38/* Convert hex ASCII to int4 */
39static int
40hci_hexa2int4(const char *a)
41{
42	if ('0' <= *a && *a <= '9')
43		return (*a - '0');
44
45	if ('A' <= *a && *a <= 'F')
46		return (*a - 'A' + 0xa);
47
48	if ('a' <= *a && *a <= 'f')
49		return (*a - 'a' + 0xa);
50
51	return (-1);
52}
53
54/* Convert hex ASCII to int8 */
55static int
56hci_hexa2int8(const char *a)
57{
58	int	hi = hci_hexa2int4(a);
59	int	lo = hci_hexa2int4(a + 1);
60
61	if (hi < 0 || lo < 0)
62		return (-1);
63
64	return ((hi << 4) | lo);
65}
66
67/* Convert ascii hex string to the uint8_t[] */
68static int
69hci_hexstring2array(char const *s, uint8_t *a, int asize)
70{
71	int	i, l, b;
72
73	l = strlen(s) / 2;
74	if (l > asize)
75		l = asize;
76
77	for (i = 0; i < l; i++) {
78		b = hci_hexa2int8(s + i * 2);
79		if (b < 0)
80			return (-1);
81
82		a[i] = (b & 0xff);
83	}
84
85	return (0);
86}
87
88/* Send RESET to the unit */
89static int
90hci_reset(int s, int argc, char **argv)
91{
92	ng_hci_status_rp	rp;
93	int			n;
94
95	n = sizeof(rp);
96	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
97			NG_HCI_OCF_RESET), (char *) &rp, &n) == ERROR)
98		return (ERROR);
99
100	if (rp.status != 0x00) {
101		fprintf(stdout, "Status: %s [%#02x]\n",
102			hci_status2str(rp.status), rp.status);
103		return (FAILED);
104	}
105
106	return (OK);
107} /* hci_reset */
108
109/* Send Read_PIN_Type command to the unit */
110static int
111hci_read_pin_type(int s, int argc, char **argv)
112{
113	ng_hci_read_pin_type_rp	rp;
114	int			n;
115
116	n = sizeof(rp);
117	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
118			NG_HCI_OCF_READ_PIN_TYPE),
119			(char *) &rp, &n) == ERROR)
120		return (ERROR);
121
122	if (rp.status != 0x00) {
123		fprintf(stdout, "Status: %s [%#02x]\n",
124			hci_status2str(rp.status), rp.status);
125		return (FAILED);
126	}
127
128	fprintf(stdout, "PIN type: %s [%#02x]\n",
129			hci_pin2str(rp.pin_type), rp.pin_type);
130
131	return (OK);
132} /* hci_read_pin_type */
133
134/* Send Write_PIN_Type command to the unit */
135static int
136hci_write_pin_type(int s, int argc, char **argv)
137{
138	ng_hci_write_pin_type_cp	cp;
139	ng_hci_write_pin_type_rp	rp;
140	int				n;
141
142	/* parse command parameters */
143	switch (argc) {
144	case 1:
145		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 1)
146			return (USAGE);
147
148		cp.pin_type = (uint8_t) n;
149		break;
150
151	default:
152		return (USAGE);
153	}
154
155	/* send command */
156	n = sizeof(rp);
157	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
158			NG_HCI_OCF_WRITE_PIN_TYPE),
159			(char const *) &cp, sizeof(cp),
160			(char *) &rp , &n) ==  ERROR)
161		return (ERROR);
162
163	if (rp.status != 0x00) {
164		fprintf(stdout, "Status: %s [%#02x]\n",
165			hci_status2str(rp.status), rp.status);
166		return (FAILED);
167	}
168
169	return (OK);
170} /* hci_write_pin_type */
171
172/* Send Read_Stored_Link_Key command to the unit */
173static int
174hci_read_stored_link_key(int s, int argc, char **argv)
175{
176	struct {
177		ng_hci_cmd_pkt_t			hdr;
178		ng_hci_read_stored_link_key_cp		cp;
179	} __attribute__ ((packed))			cmd;
180
181	struct {
182		ng_hci_event_pkt_t			hdr;
183		union {
184			ng_hci_command_compl_ep		cc;
185			ng_hci_return_link_keys_ep	key;
186			uint8_t				b[NG_HCI_EVENT_PKT_SIZE];
187		}					ep;
188	} __attribute__ ((packed))			event;
189
190	int						n, n1;
191
192	/* Send command */
193	memset(&cmd, 0, sizeof(cmd));
194	cmd.hdr.type = NG_HCI_CMD_PKT;
195	cmd.hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
196				NG_HCI_OCF_READ_STORED_LINK_KEY));
197	cmd.hdr.length = sizeof(cmd.cp);
198
199	switch (argc) {
200	case 1:
201		/* parse BD_ADDR */
202		if (!bt_aton(argv[0], &cmd.cp.bdaddr)) {
203			struct hostent	*he = NULL;
204
205			if ((he = bt_gethostbyname(argv[0])) == NULL)
206				return (USAGE);
207
208			memcpy(&cmd.cp.bdaddr, he->h_addr, sizeof(cmd.cp.bdaddr));
209		}
210		break;
211
212	default:
213		cmd.cp.read_all = 1;
214		break;
215	}
216
217	if (hci_send(s, (char const *) &cmd, sizeof(cmd)) != OK)
218		return (ERROR);
219
220	/* Receive events */
221again:
222	memset(&event, 0, sizeof(event));
223	n = sizeof(event);
224	if (hci_recv(s, (char *) &event, &n) != OK)
225		return (ERROR);
226
227	if (n <= sizeof(event.hdr)) {
228		errno = EMSGSIZE;
229		return (ERROR);
230	}
231
232	if (event.hdr.type != NG_HCI_EVENT_PKT) {
233		errno = EIO;
234		return (ERROR);
235	}
236
237	/* Parse event */
238	switch (event.hdr.event) {
239	case NG_HCI_EVENT_COMMAND_COMPL: {
240		ng_hci_read_stored_link_key_rp	*rp = NULL;
241
242		if (event.ep.cc.opcode == 0x0000 ||
243		    event.ep.cc.opcode != cmd.hdr.opcode)
244			goto again;
245
246		rp = (ng_hci_read_stored_link_key_rp *)(event.ep.b +
247				sizeof(event.ep.cc));
248
249		fprintf(stdout, "Complete: Status: %s [%#x]\n",
250				hci_status2str(rp->status), rp->status);
251		fprintf(stdout, "Maximum Number of keys: %d\n",
252				le16toh(rp->max_num_keys));
253		fprintf(stdout, "Number of keys read: %d\n",
254				le16toh(rp->num_keys_read));
255		} break;
256
257	case NG_HCI_EVENT_RETURN_LINK_KEYS: {
258		struct _key {
259			bdaddr_t	bdaddr;
260			uint8_t		key[NG_HCI_KEY_SIZE];
261		} __attribute__ ((packed))	*k = NULL;
262
263		fprintf(stdout, "Event: Number of keys: %d\n",
264			event.ep.key.num_keys);
265
266		k = (struct _key *)(event.ep.b + sizeof(event.ep.key));
267		for (n = 0; n < event.ep.key.num_keys; n++) {
268			fprintf(stdout, "\t%d: %s ",
269				n + 1, hci_bdaddr2str(&k->bdaddr));
270
271			for (n1 = 0; n1 < sizeof(k->key); n1++)
272				fprintf(stdout, "%02x", k->key[n1]);
273			fprintf(stdout, "\n");
274
275			k ++;
276		}
277
278		goto again;
279
280		} break;
281
282	default:
283		goto again;
284	}
285
286	return (OK);
287} /* hci_read_store_link_key */
288
289/* Send Write_Stored_Link_Key command to the unit */
290static int
291hci_write_stored_link_key(int s, int argc, char **argv)
292{
293	struct {
294		ng_hci_write_stored_link_key_cp	p;
295		bdaddr_t			bdaddr;
296		uint8_t				key[NG_HCI_KEY_SIZE];
297	}					cp;
298	ng_hci_write_stored_link_key_rp		rp;
299	int32_t					n;
300
301	memset(&cp, 0, sizeof(cp));
302
303	switch (argc) {
304	case 2:
305		cp.p.num_keys_write = 1;
306
307		/* parse BD_ADDR */
308		if (!bt_aton(argv[0], &cp.bdaddr)) {
309			struct hostent	*he = NULL;
310
311			if ((he = bt_gethostbyname(argv[0])) == NULL)
312				return (USAGE);
313
314			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
315		}
316
317		/* parse key */
318		if (hci_hexstring2array(argv[1], cp.key, sizeof(cp.key)) < 0)
319			return (USAGE);
320		break;
321
322	default:
323		return (USAGE);
324	}
325
326	/* send command */
327	n = sizeof(rp);
328	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
329			NG_HCI_OCF_WRITE_STORED_LINK_KEY),
330			(char const *) &cp, sizeof(cp),
331			(char *) &rp, &n) == ERROR)
332		return (ERROR);
333
334	if (rp.status != 0x00) {
335		fprintf(stdout, "Status: %s [%#02x]\n",
336			hci_status2str(rp.status), rp.status);
337		return (FAILED);
338	}
339
340	fprintf(stdout, "Number of keys written: %d\n", rp.num_keys_written);
341
342	return (OK);
343} /* hci_write_stored_link_key */
344
345
346/* Send Delete_Stored_Link_Key command to the unit */
347static int
348hci_delete_stored_link_key(int s, int argc, char **argv)
349{
350	ng_hci_delete_stored_link_key_cp	cp;
351	ng_hci_delete_stored_link_key_rp	rp;
352	int32_t					n;
353
354	memset(&cp, 0, sizeof(cp));
355
356	switch (argc) {
357	case 1:
358		/* parse BD_ADDR */
359		if (!bt_aton(argv[0], &cp.bdaddr)) {
360			struct hostent	*he = NULL;
361
362			if ((he = bt_gethostbyname(argv[0])) == NULL)
363				return (USAGE);
364
365			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
366		}
367		break;
368
369	default:
370		cp.delete_all = 1;
371		break;
372	}
373
374	/* send command */
375	n = sizeof(cp);
376	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
377			NG_HCI_OCF_DELETE_STORED_LINK_KEY),
378			(char const *) &cp, sizeof(cp),
379			(char *) &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	fprintf(stdout, "Number of keys deleted: %d\n", rp.num_keys_deleted);
389
390	return (OK);
391} /* hci_delete_stored_link_key */
392
393/* Send Change_Local_Name command to the unit */
394static int
395hci_change_local_name(int s, int argc, char **argv)
396{
397	ng_hci_change_local_name_cp	cp;
398	ng_hci_change_local_name_rp	rp;
399	int				n;
400
401	/* parse command parameters */
402	switch (argc) {
403	case 1:
404		snprintf(cp.name, sizeof(cp.name), "%s", argv[0]);
405		break;
406
407	default:
408		return (USAGE);
409	}
410
411	/* send command */
412	n = sizeof(rp);
413	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
414			NG_HCI_OCF_CHANGE_LOCAL_NAME),
415			(char const *) &cp, sizeof(cp),
416			(char *) &rp, &n) == ERROR)
417		return (ERROR);
418
419	if (rp.status != 0x00) {
420		fprintf(stdout, "Status: %s [%#02x]\n",
421			hci_status2str(rp.status), rp.status);
422		return (FAILED);
423	}
424
425	return (OK);
426} /* hci_change_local_name */
427
428/* Send Read_Local_Name command to the unit */
429static int
430hci_read_local_name(int s, int argc, char **argv)
431{
432	ng_hci_read_local_name_rp	rp;
433	int				n;
434
435	n = sizeof(rp);
436	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
437			NG_HCI_OCF_READ_LOCAL_NAME),
438			(char *) &rp, &n) == ERROR)
439		return (ERROR);
440
441	if (rp.status != 0x00) {
442		fprintf(stdout, "Status: %s [%#02x]\n",
443			hci_status2str(rp.status), rp.status);
444		return (FAILED);
445	}
446
447	fprintf(stdout, "Local name: %s\n", rp.name);
448
449	return (OK);
450} /* hci_read_local_name */
451
452/* Send Read_Connection_Accept_Timeout to the unit */
453static int
454hci_read_connection_accept_timeout(int s, int argc, char **argv)
455{
456	ng_hci_read_con_accept_timo_rp	rp;
457	int				n;
458
459	n = sizeof(rp);
460	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
461			NG_HCI_OCF_READ_CON_ACCEPT_TIMO),
462			(char *) &rp, &n) == ERROR)
463		return (ERROR);
464
465	if (rp.status != 0x00) {
466		fprintf(stdout, "Status: %s [%#02x]\n",
467			hci_status2str(rp.status), rp.status);
468		return (FAILED);
469	}
470
471	rp.timeout = le16toh(rp.timeout);
472	fprintf(stdout, "Connection accept timeout: %.2f msec [%d slots]\n",
473			rp.timeout * 0.625, rp.timeout);
474
475	return (OK);
476} /* hci_read_connection_accept_timeout */
477
478/* Send Write_Connection_Accept_Timeout to the unit */
479static int
480hci_write_connection_accept_timeout(int s, int argc, char **argv)
481{
482	ng_hci_write_con_accept_timo_cp	cp;
483	ng_hci_write_con_accept_timo_rp	rp;
484	int				n;
485
486	/* parse command parameters */
487	switch (argc) {
488	case 1:
489		if (sscanf(argv[0], "%d", &n) != 1 || n < 1 || n > 0xb540)
490			return (USAGE);
491
492		cp.timeout = (uint16_t) n;
493		cp.timeout = htole16(cp.timeout);
494		break;
495
496	default:
497		return (USAGE);
498	}
499
500	/* send command */
501	n = sizeof(rp);
502	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
503			NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO),
504			(char const *) &cp, sizeof(cp),
505			(char *) &rp, &n) == ERROR)
506		return (ERROR);
507
508	if (rp.status != 0x00) {
509		fprintf(stdout, "Status: %s [%#02x]\n",
510			hci_status2str(rp.status), rp.status);
511		return (FAILED);
512	}
513
514	return (OK);
515} /* hci_write_connection_accept_timeout */
516
517/* Send Read_Page_Timeout command to the unit */
518static int
519hci_read_page_timeout(int s, int argc, char **argv)
520{
521	ng_hci_read_page_timo_rp	rp;
522	int				n;
523
524	n = sizeof(rp);
525	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
526			NG_HCI_OCF_READ_PAGE_TIMO),
527			(char *) &rp, &n) == ERROR)
528		return (ERROR);
529
530	if (rp.status != 0x00) {
531		fprintf(stdout, "Status: %s [%#02x]\n",
532			hci_status2str(rp.status), rp.status);
533		return (FAILED);
534	}
535
536	rp.timeout = le16toh(rp.timeout);
537	fprintf(stdout, "Page timeout: %.2f msec [%d slots]\n",
538		rp.timeout * 0.625, rp.timeout);
539
540	return (OK);
541} /* hci_read_page_timeoout */
542
543/* Send Write_Page_Timeout command to the unit */
544static int
545hci_write_page_timeout(int s, int argc, char **argv)
546{
547	ng_hci_write_page_timo_cp	cp;
548	ng_hci_write_page_timo_rp	rp;
549	int				n;
550
551	/* parse command parameters */
552	switch (argc) {
553	case 1:
554		if (sscanf(argv[0], "%d", &n) != 1 || n < 1 || n > 0xffff)
555			return (USAGE);
556
557		cp.timeout = (uint16_t) n;
558		cp.timeout = htole16(cp.timeout);
559		break;
560
561	default:
562		return (USAGE);
563	}
564
565	/* send command */
566	n = sizeof(rp);
567	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
568			NG_HCI_OCF_WRITE_PAGE_TIMO),
569			(char const *) &cp, sizeof(cp),
570			(char *) &rp, &n) == ERROR)
571		return (ERROR);
572
573	if (rp.status != 0x00) {
574		fprintf(stdout, "Status: %s [%#02x]\n",
575			hci_status2str(rp.status), rp.status);
576		return (FAILED);
577	}
578
579	return (OK);
580} /* hci_write_page_timeout */
581
582/* Send Read_Scan_Enable command to the unit */
583static int
584hci_read_scan_enable(int s, int argc, char **argv)
585{
586	ng_hci_read_scan_enable_rp	rp;
587	int				n;
588
589	n = sizeof(rp);
590	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
591			NG_HCI_OCF_READ_SCAN_ENABLE),
592			(char *) &rp, &n) == ERROR)
593		return (ERROR);
594
595	if (rp.status != 0x00) {
596		fprintf(stdout, "Status: %s [%#02x]\n",
597			hci_status2str(rp.status), rp.status);
598		return (FAILED);
599	}
600
601	fprintf(stdout, "Scan enable: %s [%#02x]\n",
602		hci_scan2str(rp.scan_enable), rp.scan_enable);
603
604	return (OK);
605} /* hci_read_scan_enable */
606
607/* Send Write_Scan_Enable command to the unit */
608static int
609hci_write_scan_enable(int s, int argc, char **argv)
610{
611	ng_hci_write_scan_enable_cp	cp;
612	ng_hci_write_scan_enable_rp	rp;
613	int				n;
614
615	/* parse command parameters */
616	switch (argc) {
617	case 1:
618		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 3)
619			return (USAGE);
620
621		cp.scan_enable = (uint8_t) n;
622		break;
623
624	default:
625		return (USAGE);
626	}
627
628	n = sizeof(rp);
629	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
630			NG_HCI_OCF_WRITE_SCAN_ENABLE),
631			(char const *) &cp, sizeof(cp),
632			(char *) &rp, &n) == ERROR)
633		return (ERROR);
634
635	if (rp.status != 0x00) {
636		fprintf(stdout, "Status: %s [%#02x]\n",
637			hci_status2str(rp.status), rp.status);
638		return (FAILED);
639	}
640
641	return (OK);
642} /* hci_write_scan_enable */
643
644/* Send Read_Page_Scan_Activity command to the unit */
645static int
646hci_read_page_scan_activity(int s, int argc, char **argv)
647{
648	ng_hci_read_page_scan_activity_rp	rp;
649	int					n;
650
651	n = sizeof(rp);
652	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
653			NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY),
654			(char *) &rp, &n) == ERROR)
655		return (ERROR);
656
657	if (rp.status != 0x00) {
658		fprintf(stdout, "Status: %s [%#02x]\n",
659			hci_status2str(rp.status), rp.status);
660		return (FAILED);
661	}
662
663	rp.page_scan_interval = le16toh(rp.page_scan_interval);
664	rp.page_scan_window = le16toh(rp.page_scan_window);
665
666	fprintf(stdout, "Page Scan Interval: %.2f msec [%d slots]\n",
667		rp.page_scan_interval * 0.625, rp.page_scan_interval);
668	fprintf(stdout, "Page Scan Window: %.2f msec [%d slots]\n",
669		rp.page_scan_window * 0.625, rp.page_scan_window);
670
671	return (OK);
672} /* hci_read_page_scan_activity */
673
674/* Send Write_Page_Scan_Activity command to the unit */
675static int
676hci_write_page_scan_activity(int s, int argc, char **argv)
677{
678	ng_hci_write_page_scan_activity_cp	cp;
679	ng_hci_write_page_scan_activity_rp	rp;
680	int					n;
681
682	/* parse command parameters */
683	switch (argc) {
684	case 2:
685		/* page scan interval */
686		if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
687			return (USAGE);
688
689		cp.page_scan_interval = (uint16_t) n;
690
691		/* page scan window */
692		if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
693			return (USAGE);
694
695		cp.page_scan_window = (uint16_t) n;
696
697		if (cp.page_scan_window > cp.page_scan_interval)
698			return (USAGE);
699
700		cp.page_scan_interval = htole16(cp.page_scan_interval);
701		cp.page_scan_window = htole16(cp.page_scan_window);
702		break;
703
704	default:
705		return (USAGE);
706	}
707
708	/* send command */
709	n = sizeof(rp);
710	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
711			NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY),
712			(char const *) &cp, sizeof(cp),
713			(char *) &rp, &n) == ERROR)
714		return (ERROR);
715
716	if (rp.status != 0x00) {
717		fprintf(stdout, "Status: %s [%#02x]\n",
718			hci_status2str(rp.status), rp.status);
719		return (FAILED);
720	}
721
722	return (OK);
723} /* hci_write_page_scan_activity */
724
725/* Send Read_Inquiry_Scan_Activity command to the unit */
726static int
727hci_read_inquiry_scan_activity(int s, int argc, char **argv)
728{
729	ng_hci_read_inquiry_scan_activity_rp	rp;
730	int					n;
731
732	n = sizeof(rp);
733	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
734			NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY),
735			(char *) &rp, &n) == ERROR)
736		return (ERROR);
737
738	if (rp.status != 0x00) {
739		fprintf(stdout, "Status: %s [%#02x]\n",
740			hci_status2str(rp.status), rp.status);
741		return (FAILED);
742	}
743
744	rp.inquiry_scan_interval = le16toh(rp.inquiry_scan_interval);
745	rp.inquiry_scan_window = le16toh(rp.inquiry_scan_window);
746
747	fprintf(stdout, "Inquiry Scan Interval: %.2f msec [%d slots]\n",
748		rp.inquiry_scan_interval * 0.625, rp.inquiry_scan_interval);
749	fprintf(stdout, "Inquiry Scan Window: %.2f msec [%d slots]\n",
750		rp.inquiry_scan_window * 0.625, rp.inquiry_scan_interval);
751
752	return (OK);
753} /* hci_read_inquiry_scan_activity */
754
755/* Send Write_Inquiry_Scan_Activity command to the unit */
756static int
757hci_write_inquiry_scan_activity(int s, int argc, char **argv)
758{
759	ng_hci_write_inquiry_scan_activity_cp	cp;
760	ng_hci_write_inquiry_scan_activity_rp	rp;
761	int					n;
762
763	/* parse command parameters */
764	switch (argc) {
765	case 2:
766		/* inquiry scan interval */
767		if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
768			return (USAGE);
769
770		cp.inquiry_scan_interval = (uint16_t) n;
771
772		/* inquiry scan window */
773		if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
774			return (USAGE);
775
776		cp.inquiry_scan_window = (uint16_t) n;
777
778		if (cp.inquiry_scan_window > cp.inquiry_scan_interval)
779			return (USAGE);
780
781		cp.inquiry_scan_interval =
782			htole16(cp.inquiry_scan_interval);
783		cp.inquiry_scan_window = htole16(cp.inquiry_scan_window);
784		break;
785
786	default:
787		return (USAGE);
788	}
789
790	/* send command */
791	n = sizeof(rp);
792	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
793			NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY),
794			(char const *) &cp, sizeof(cp),
795			(char *) &rp, &n) == ERROR)
796		return (ERROR);
797
798	if (rp.status != 0x00) {
799		fprintf(stdout, "Status: %s [%#02x]\n",
800			hci_status2str(rp.status), rp.status);
801		return (FAILED);
802	}
803
804	return (OK);
805} /* hci_write_inquiry_scan_activity */
806
807/* Send Read_Authentication_Enable command to the unit */
808static int
809hci_read_authentication_enable(int s, int argc, char **argv)
810{
811	ng_hci_read_auth_enable_rp	rp;
812	int				n;
813
814	n = sizeof(rp);
815	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
816			NG_HCI_OCF_READ_AUTH_ENABLE),
817			(char *) &rp, &n) == ERROR)
818		return (ERROR);
819
820	if (rp.status != 0x00) {
821		fprintf(stdout, "Status: %s [%#02x]\n",
822			hci_status2str(rp.status), rp.status);
823		return (FAILED);
824	}
825
826	fprintf(stdout, "Authentication Enable: %s [%d]\n",
827		rp.auth_enable? "Enabled" : "Disabled", rp.auth_enable);
828
829	return (OK);
830} /* hci_read_authentication_enable */
831
832/* Send Write_Authentication_Enable command to the unit */
833static int
834hci_write_authentication_enable(int s, int argc, char **argv)
835{
836	ng_hci_write_auth_enable_cp	cp;
837	ng_hci_write_auth_enable_rp	rp;
838	int				n;
839
840	/* parse command parameters */
841	switch (argc) {
842	case 1:
843		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 1)
844			return (USAGE);
845
846		cp.auth_enable = (uint8_t) n;
847		break;
848
849	default:
850		return (USAGE);
851	}
852
853	/* send command */
854	n = sizeof(rp);
855	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
856			NG_HCI_OCF_WRITE_AUTH_ENABLE),
857			(char const *) &cp, sizeof(cp),
858			(char *) &rp, &n) == ERROR)
859		return (ERROR);
860
861	if (rp.status != 0x00) {
862		fprintf(stdout, "Status: %s [%#02x]\n",
863			hci_status2str(rp.status), rp.status);
864		return (FAILED);
865	}
866
867	return (OK);
868} /* hci_write_authentication_enable */
869
870/* Send Read_Encryption_Mode command to the unit */
871static int
872hci_read_encryption_mode(int s, int argc, char **argv)
873{
874	ng_hci_read_encryption_mode_rp	rp;
875	int				n;
876
877	n = sizeof(rp);
878	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
879			NG_HCI_OCF_READ_ENCRYPTION_MODE),
880			(char *) &rp, &n) == ERROR)
881		return (ERROR);
882
883	if (rp.status != 0x00) {
884		fprintf(stdout, "Status: %s [%#02x]\n",
885			hci_status2str(rp.status), rp.status);
886		return (FAILED);
887	}
888
889	fprintf(stdout, "Encryption mode: %s [%#02x]\n",
890		hci_encrypt2str(rp.encryption_mode, 0), rp.encryption_mode);
891
892	return (OK);
893} /* hci_read_encryption_mode */
894
895/* Send Write_Encryption_Mode command to the unit */
896static int
897hci_write_encryption_mode(int s, int argc, char **argv)
898{
899	ng_hci_write_encryption_mode_cp	cp;
900	ng_hci_write_encryption_mode_rp	rp;
901	int				n;
902
903	/* parse command parameters */
904	switch (argc) {
905	case 1:
906		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 2)
907			return (USAGE);
908
909		cp.encryption_mode = (uint8_t) n;
910		break;
911
912	default:
913		return (USAGE);
914	}
915
916	/* send command */
917	n = sizeof(rp);
918	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
919			NG_HCI_OCF_WRITE_ENCRYPTION_MODE),
920			(char const *) &cp, sizeof(cp),
921			(char *) &rp, &n) == ERROR)
922		return (ERROR);
923
924	if (rp.status != 0x00) {
925		fprintf(stdout, "Status: %s [%#02x]\n",
926			hci_status2str(rp.status), rp.status);
927		return (FAILED);
928	}
929
930	return (OK);
931} /* hci_write_encryption_mode */
932
933/* Send Read_Class_Of_Device command to the unit */
934static int
935hci_read_class_of_device(int s, int argc, char **argv)
936{
937	ng_hci_read_unit_class_rp	rp;
938	int				n;
939
940	n = sizeof(rp);
941	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
942			NG_HCI_OCF_READ_UNIT_CLASS),
943			(char *) &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, "Class: %02x:%02x:%02x\n",
953		rp.uclass[2], rp.uclass[1], rp.uclass[0]);
954
955	return (0);
956} /* hci_read_class_of_device */
957
958/* Send Write_Class_Of_Device command to the unit */
959static int
960hci_write_class_of_device(int s, int argc, char **argv)
961{
962	ng_hci_write_unit_class_cp	cp;
963	ng_hci_write_unit_class_rp	rp;
964	int				n0, n1, n2;
965
966	/* parse command parameters */
967	switch (argc) {
968	case 1:
969		if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3)
970			return (USAGE);
971
972		cp.uclass[0] = (n0 & 0xff);
973		cp.uclass[1] = (n1 & 0xff);
974		cp.uclass[2] = (n2 & 0xff);
975		break;
976
977	default:
978		return (USAGE);
979	}
980
981	/* send command */
982	n0 = sizeof(rp);
983	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
984			NG_HCI_OCF_WRITE_UNIT_CLASS),
985			(char const *) &cp, sizeof(cp),
986			(char *) &rp, &n0) == ERROR)
987		return (ERROR);
988
989	if (rp.status != 0x00) {
990		fprintf(stdout, "Status: %s [%#02x]\n",
991			hci_status2str(rp.status), rp.status);
992		return (FAILED);
993	}
994
995	return (OK);
996} /* hci_write_class_of_device */
997
998/* Send Read_Voice_Settings command to the unit */
999static int
1000hci_read_voice_settings(int s, int argc, char **argv)
1001{
1002	ng_hci_read_voice_settings_rp	rp;
1003	int				n,
1004					input_coding,
1005					input_data_format,
1006					input_sample_size;
1007
1008	n = sizeof(rp);
1009	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1010			NG_HCI_OCF_READ_VOICE_SETTINGS),
1011			(char *) &rp, &n) == ERROR)
1012		return (ERROR);
1013
1014	if (rp.status != 0x00) {
1015		fprintf(stdout, "Status: %s [%#02x]\n",
1016			hci_status2str(rp.status), rp.status);
1017		return (FAILED);
1018	}
1019
1020	rp.settings = le16toh(rp.settings);
1021
1022	input_coding      = (rp.settings & 0x0300) >> 8;
1023	input_data_format = (rp.settings & 0x00c0) >> 6;
1024	input_sample_size = (rp.settings & 0x0020) >> 5;
1025
1026	fprintf(stdout, "Voice settings: %#04x\n", rp.settings);
1027	fprintf(stdout, "Input coding: %s [%d]\n",
1028		hci_coding2str(input_coding), input_coding);
1029	fprintf(stdout, "Input data format: %s [%d]\n",
1030		hci_vdata2str(input_data_format), input_data_format);
1031
1032	if (input_coding == 0x00) /* Only for Linear PCM */
1033		fprintf(stdout, "Input sample size: %d bit [%d]\n",
1034			input_sample_size? 16 : 8, input_sample_size);
1035
1036	return (OK);
1037} /* hci_read_voice_settings */
1038
1039/* Send Write_Voice_Settings command to the unit */
1040static int
1041hci_write_voice_settings(int s, int argc, char **argv)
1042{
1043	ng_hci_write_voice_settings_cp	cp;
1044	ng_hci_write_voice_settings_rp	rp;
1045	int				n;
1046
1047	/* parse command parameters */
1048	switch (argc) {
1049	case 1:
1050		if (sscanf(argv[0], "%x", &n) != 1)
1051			return (USAGE);
1052
1053		cp.settings = (uint16_t) n;
1054		cp.settings = htole16(cp.settings);
1055		break;
1056
1057	default:
1058		return (USAGE);
1059	}
1060
1061	/* send command */
1062	n = sizeof(rp);
1063	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1064			NG_HCI_OCF_WRITE_VOICE_SETTINGS),
1065			(char const *) &cp, sizeof(cp),
1066			(char *) &rp, &n) == ERROR)
1067		return (ERROR);
1068
1069	if (rp.status != 0x00) {
1070		fprintf(stdout, "Status: %s [%#02x]\n",
1071			hci_status2str(rp.status), rp.status);
1072		return (FAILED);
1073	}
1074
1075	return (OK);
1076} /* hci_write_voice_settings */
1077
1078/* Send Read_Number_Broadcast_Restransmissions */
1079static int
1080hci_read_number_broadcast_retransmissions(int s, int argc, char **argv)
1081{
1082	ng_hci_read_num_broadcast_retrans_rp	rp;
1083	int					n;
1084
1085	n = sizeof(rp);
1086	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1087			NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS),
1088			(char *) &rp, &n) == ERROR)
1089		return (ERROR);
1090
1091	if (rp.status != 0x00) {
1092		fprintf(stdout, "Status: %s [%#02x]\n",
1093			hci_status2str(rp.status), rp.status);
1094		return (FAILED);
1095	}
1096
1097	fprintf(stdout, "Number of broadcast retransmissions: %d\n",
1098		rp.counter);
1099
1100	return (OK);
1101} /* hci_read_number_broadcast_retransmissions */
1102
1103/* Send Write_Number_Broadcast_Restransmissions */
1104static int
1105hci_write_number_broadcast_retransmissions(int s, int argc, char **argv)
1106{
1107	ng_hci_write_num_broadcast_retrans_cp	cp;
1108	ng_hci_write_num_broadcast_retrans_rp	rp;
1109	int					n;
1110
1111	/* parse command parameters */
1112	switch (argc) {
1113	case 1:
1114		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0xff)
1115			return (USAGE);
1116
1117		cp.counter = (uint8_t) n;
1118		break;
1119
1120	default:
1121		return (USAGE);
1122	}
1123
1124	/* send command */
1125	n = sizeof(rp);
1126	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1127			NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS),
1128			(char const *) &cp, sizeof(cp),
1129			(char *) &rp, &n) == ERROR)
1130		return (ERROR);
1131
1132	if (rp.status != 0x00) {
1133		fprintf(stdout, "Status: %s [%#02x]\n",
1134			hci_status2str(rp.status), rp.status);
1135		return (FAILED);
1136	}
1137
1138	return (OK);
1139} /* hci_write_number_broadcast_retransmissions */
1140
1141/* Send Read_Hold_Mode_Activity command to the unit */
1142static int
1143hci_read_hold_mode_activity(int s, int argc, char **argv)
1144{
1145	ng_hci_read_hold_mode_activity_rp	rp;
1146	int					n;
1147	char					buffer[1024];
1148
1149	n = sizeof(rp);
1150	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1151			NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY),
1152			(char *) &rp, &n) == ERROR)
1153		return (ERROR);
1154
1155	if (rp.status != 0x00) {
1156		fprintf(stdout, "Status: %s [%#02x]\n",
1157			hci_status2str(rp.status), rp.status);
1158		return (FAILED);
1159	}
1160
1161	fprintf(stdout, "Hold Mode Activities: %#02x\n", rp.hold_mode_activity);
1162	if (rp.hold_mode_activity == 0)
1163		fprintf(stdout, "Maintain current Power State");
1164	else
1165		fprintf(stdout, "%s", hci_hmode2str(rp.hold_mode_activity,
1166				buffer, sizeof(buffer)));
1167
1168	fprintf(stdout, "\n");
1169
1170	return (OK);
1171} /* hci_read_hold_mode_activity */
1172
1173/* Send Write_Hold_Mode_Activity command to the unit */
1174static int
1175hci_write_hold_mode_activity(int s, int argc, char **argv)
1176{
1177	ng_hci_write_hold_mode_activity_cp	cp;
1178	ng_hci_write_hold_mode_activity_rp	rp;
1179	int					n;
1180
1181	/* parse command parameters */
1182	switch (argc) {
1183	case 1:
1184		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 4)
1185			return (USAGE);
1186
1187		cp.hold_mode_activity = (uint8_t) n;
1188		break;
1189
1190	default:
1191		return (USAGE);
1192	}
1193
1194	/* send command */
1195	n = sizeof(rp);
1196	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1197			NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY),
1198			(char const *) &cp, sizeof(cp),
1199			(char *) &rp, &n) == ERROR)
1200		return (ERROR);
1201
1202	if (rp.status != 0x00) {
1203		fprintf(stdout, "Status: %s [%#02x]\n",
1204			hci_status2str(rp.status), rp.status);
1205		return (FAILED);
1206	}
1207
1208	return (OK);
1209} /* hci_write_hold_mode_activity */
1210
1211/* Send Read_SCO_Flow_Control_Enable command to the unit */
1212static int
1213hci_read_sco_flow_control_enable(int s, int argc, char **argv)
1214{
1215	ng_hci_read_sco_flow_control_rp	rp;
1216	int				n;
1217
1218	n = sizeof(rp);
1219	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1220			NG_HCI_OCF_READ_SCO_FLOW_CONTROL),
1221			(char *) &rp, &n) == ERROR)
1222		return (ERROR);
1223
1224	if (rp.status != 0x00) {
1225		fprintf(stdout, "Status: %s [%#02x]\n",
1226			hci_status2str(rp.status), rp.status);
1227		return (FAILED);
1228	}
1229
1230	fprintf(stdout, "SCO flow control %s [%d]\n",
1231		rp.flow_control? "enabled" : "disabled", rp.flow_control);
1232
1233	return (OK);
1234} /* hci_read_sco_flow_control_enable */
1235
1236/* Send Write_SCO_Flow_Control_Enable command to the unit */
1237static int
1238hci_write_sco_flow_control_enable(int s, int argc, char **argv)
1239{
1240	ng_hci_write_sco_flow_control_cp	cp;
1241	ng_hci_write_sco_flow_control_rp	rp;
1242	int					n;
1243
1244	/* parse command parameters */
1245	switch (argc) {
1246	case 1:
1247		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 1)
1248			return (USAGE);
1249
1250		cp.flow_control = (uint8_t) n;
1251		break;
1252
1253	default:
1254		return (USAGE);
1255	}
1256
1257	/* send command */
1258	n = sizeof(rp);
1259	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1260			NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL),
1261			(char const *) &cp, sizeof(cp),
1262			(char *) &rp, &n) == ERROR)
1263		return (ERROR);
1264
1265	if (rp.status != 0x00) {
1266		fprintf(stdout, "Status: %s [%#02x]\n",
1267			hci_status2str(rp.status), rp.status);
1268		return (FAILED);
1269	}
1270
1271	return (OK);
1272} /* hci_write_sco_flow_control_enable */
1273
1274/* Send Read_Link_Supervision_Timeout command to the unit */
1275static int
1276hci_read_link_supervision_timeout(int s, int argc, char **argv)
1277{
1278	ng_hci_read_link_supervision_timo_cp	cp;
1279	ng_hci_read_link_supervision_timo_rp	rp;
1280	int					n;
1281
1282	switch (argc) {
1283	case 1:
1284		/* connection handle */
1285		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
1286			return (USAGE);
1287
1288		cp.con_handle = (uint16_t) (n & 0x0fff);
1289		cp.con_handle = htole16(cp.con_handle);
1290		break;
1291
1292	default:
1293		return (USAGE);
1294	}
1295
1296	/* send command */
1297	n = sizeof(rp);
1298	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1299			NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO),
1300			(char const *) &cp, sizeof(cp),
1301			(char *) &rp, &n) == ERROR)
1302		return (ERROR);
1303
1304	if (rp.status != 0x00) {
1305		fprintf(stdout, "Status: %s [%#02x]\n",
1306			hci_status2str(rp.status), rp.status);
1307		return (FAILED);
1308	}
1309
1310	rp.timeout = le16toh(rp.timeout);
1311
1312	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
1313	fprintf(stdout, "Link supervision timeout: %.2f msec [%d slots]\n",
1314		rp.timeout * 0.625, rp.timeout);
1315
1316	return (OK);
1317} /* hci_read_link_supervision_timeout */
1318
1319/* Send Write_Link_Supervision_Timeout command to the unit */
1320static int
1321hci_write_link_supervision_timeout(int s, int argc, char **argv)
1322{
1323	ng_hci_write_link_supervision_timo_cp	cp;
1324	ng_hci_write_link_supervision_timo_rp	rp;
1325	int					n;
1326
1327	switch (argc) {
1328	case 2:
1329		/* connection handle */
1330		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
1331			return (USAGE);
1332
1333		cp.con_handle = (uint16_t) (n & 0x0fff);
1334		cp.con_handle = htole16(cp.con_handle);
1335
1336		/* link supervision timeout */
1337		if (sscanf(argv[1], "%d", &n) != 1 || n < 0 || n > 0xeff)
1338			return (USAGE);
1339
1340		cp.timeout = (uint16_t) (n & 0x0fff);
1341		cp.timeout = htole16(cp.timeout);
1342		break;
1343
1344	default:
1345		return (USAGE);
1346	}
1347
1348	/* send command */
1349	n = sizeof(rp);
1350	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1351			NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO),
1352			(char const *) &cp, sizeof(cp),
1353			(char *) &rp, &n) == ERROR)
1354		return (ERROR);
1355
1356	if (rp.status != 0x00) {
1357		fprintf(stdout, "Status: %s [%#02x]\n",
1358			hci_status2str(rp.status), rp.status);
1359		return (FAILED);
1360	}
1361
1362	return (OK);
1363} /* hci_write_link_supervision_timeout */
1364
1365/* Send Read_Page_Scan_Period_Mode command to the unit */
1366static int
1367hci_read_page_scan_period_mode(int s, int argc, char **argv)
1368{
1369	ng_hci_read_page_scan_period_rp	rp;
1370	int				n;
1371
1372	n = sizeof(rp);
1373	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1374			NG_HCI_OCF_READ_PAGE_SCAN_PERIOD),
1375			(char *) &rp, &n) == ERROR)
1376		return (ERROR);
1377
1378	if (rp.status != 0x00) {
1379		fprintf(stdout, "Status: %s [%#02x]\n",
1380			hci_status2str(rp.status), rp.status);
1381		return (FAILED);
1382	}
1383
1384	fprintf(stdout, "Page scan period mode: %#02x\n",
1385		rp.page_scan_period_mode);
1386
1387	return (OK);
1388} /* hci_read_page_scan_period_mode */
1389
1390/* Send Write_Page_Scan_Period_Mode command to the unit */
1391static int
1392hci_write_page_scan_period_mode(int s, int argc, char **argv)
1393{
1394	ng_hci_write_page_scan_period_cp	cp;
1395	ng_hci_write_page_scan_period_rp	rp;
1396	int					n;
1397
1398	/* parse command arguments */
1399	switch (argc) {
1400	case 1:
1401		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 2)
1402			return (USAGE);
1403
1404		cp.page_scan_period_mode = (n & 0xff);
1405		break;
1406
1407	default:
1408		return (USAGE);
1409	}
1410
1411	/* send command */
1412	n = sizeof(rp);
1413	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1414			NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD),
1415			(char const *) &cp, sizeof(cp),
1416			(char *) &rp, &n) == ERROR)
1417		return (ERROR);
1418
1419	if (rp.status != 0x00) {
1420		fprintf(stdout, "Status: %s [%#02x]\n",
1421			hci_status2str(rp.status), rp.status);
1422		return (FAILED);
1423	}
1424
1425	return (OK);
1426} /* hci_write_page_scan_period_mode */
1427
1428/* Send Read_Page_Scan_Mode command to the unit */
1429static int
1430hci_read_page_scan_mode(int s, int argc, char **argv)
1431{
1432	ng_hci_read_page_scan_rp	rp;
1433	int				n;
1434
1435	n = sizeof(rp);
1436	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1437			NG_HCI_OCF_READ_PAGE_SCAN),
1438			(char *) &rp, &n) == ERROR)
1439		return (ERROR);
1440
1441	if (rp.status != 0x00) {
1442		fprintf(stdout, "Status: %s [%#02x]\n",
1443			hci_status2str(rp.status), rp.status);
1444		return (FAILED);
1445	}
1446
1447	fprintf(stdout, "Page scan mode: %#02x\n", rp.page_scan_mode);
1448
1449	return (OK);
1450} /* hci_read_page_scan_mode */
1451
1452/* Send Write_Page_Scan_Mode command to the unit */
1453static int
1454hci_write_page_scan_mode(int s, int argc, char **argv)
1455{
1456	ng_hci_write_page_scan_cp	cp;
1457	ng_hci_write_page_scan_rp	rp;
1458	int				n;
1459
1460	/* parse command arguments */
1461	switch (argc) {
1462	case 1:
1463		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 3)
1464			return (USAGE);
1465
1466		cp.page_scan_mode = (n & 0xff);
1467		break;
1468
1469	default:
1470		return (USAGE);
1471	}
1472
1473	/* send command */
1474	n = sizeof(rp);
1475	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
1476			NG_HCI_OCF_WRITE_PAGE_SCAN),
1477			(char const *) &cp, sizeof(cp),
1478			(char *) &rp, &n) == ERROR)
1479		return (ERROR);
1480
1481	if (rp.status != 0x00) {
1482		fprintf(stdout, "Status: %s [%#02x]\n",
1483			hci_status2str(rp.status), rp.status);
1484		return (FAILED);
1485	}
1486
1487	return (OK);
1488} /* hci_write_page_scan_mode */
1489
1490struct hci_command	host_controller_baseband_commands[] = {
1491{
1492"reset",
1493"\nThe Reset command will reset the Host Controller and the Link Manager.\n" \
1494"After the reset is completed, the current operational state will be lost,\n" \
1495"the Bluetooth unit will enter standby mode and the Host Controller will\n" \
1496"automatically revert to the default values for the parameters for which\n" \
1497"default values are defined in the specification.",
1498&hci_reset
1499},
1500{
1501"read_pin_type",
1502"\nThe Read_PIN_Type command is used for the Host to read whether the Link\n" \
1503"Manager assumes that the Host supports variable PIN codes only a fixed PIN\n" \
1504"code.",
1505&hci_read_pin_type
1506},
1507{
1508"write_pin_type <pin_type>",
1509"\nThe Write_PIN_Type command is used for the Host to write to the Host\n" \
1510"Controller whether the Host supports variable PIN codes or only a fixed PIN\n"\
1511"code.\n\n" \
1512"\t<pin_type> - dd; 0 - Variable; 1 - Fixed",
1513&hci_write_pin_type
1514},
1515{
1516"read_stored_link_key [<bdaddr>]",
1517"\nThe Read_Stored_Link_Key command provides the ability to read one or\n" \
1518"more link keys stored in the Bluetooth Host Controller. The Bluetooth Host\n" \
1519"Controller can store a limited number of link keys for other Bluetooth\n" \
1520"devices.\n\n" \
1521"\t<bdaddr> - xx:xx:xx:xx:xx:xx BD_ADDR",
1522&hci_read_stored_link_key
1523},
1524{
1525"write_stored_link_key <bdaddr> <key>",
1526"\nThe Write_Stored_Link_Key command provides the ability to write one\n" \
1527"or more link keys to be stored in the Bluetooth Host Controller. The\n" \
1528"Bluetooth Host Controller can store a limited number of link keys for other\n"\
1529"Bluetooth devices. If no additional space is available in the Bluetooth\n"\
1530"Host Controller then no additional link keys will be stored.\n\n" \
1531"\t<bdaddr> - xx:xx:xx:xx:xx:xx BD_ADDR\n" \
1532"\t<key>    - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx up to 16 bytes link key",
1533&hci_write_stored_link_key
1534},
1535{
1536"delete_stored_link_key [<bdaddr>]",
1537"\nThe Delete_Stored_Link_Key command provides the ability to remove one\n" \
1538"or more of the link keys stored in the Bluetooth Host Controller. The\n" \
1539"Bluetooth Host Controller can store a limited number of link keys for other\n"\
1540"Bluetooth devices.\n\n" \
1541"\t<bdaddr> - xx:xx:xx:xx:xx:xx BD_ADDR",
1542&hci_delete_stored_link_key
1543},
1544{
1545"change_local_name <name>",
1546"\nThe Change_Local_Name command provides the ability to modify the user\n" \
1547"friendly name for the Bluetooth unit.\n\n" \
1548"\t<name> - string",
1549&hci_change_local_name
1550},
1551{
1552"read_local_name",
1553"\nThe Read_Local_Name command provides the ability to read the\n" \
1554"stored user-friendly name for the Bluetooth unit.",
1555&hci_read_local_name
1556},
1557{
1558"read_connection_accept_timeout",
1559"\nThis command will read the value for the Connection_Accept_Timeout\n" \
1560"configuration parameter. The Connection_Accept_Timeout configuration\n" \
1561"parameter allows the Bluetooth hardware to automatically deny a\n" \
1562"connection request after a specified time period has occurred and\n" \
1563"the new connection is not accepted. Connection Accept Timeout\n" \
1564"measured in Number of Baseband slots.",
1565&hci_read_connection_accept_timeout
1566},
1567{
1568"write_connection_accept_timeout <timeout>",
1569"\nThis command will write the value for the Connection_Accept_Timeout\n" \
1570"configuration parameter.\n\n" \
1571"\t<timeout> - dddd; measured in number of baseband slots.",
1572&hci_write_connection_accept_timeout
1573},
1574{
1575"read_page_timeout",
1576"\nThis command will read the value for the Page_Timeout configuration\n" \
1577"parameter. The Page_Timeout configuration parameter defines the\n" \
1578"maximum time the local Link Manager will wait for a baseband page\n" \
1579"response from the remote unit at a locally initiated connection\n" \
1580"attempt. Page Timeout measured in Number of Baseband slots.",
1581&hci_read_page_timeout
1582},
1583{
1584"write_page_timeout <timeout>",
1585"\nThis command will write the value for the Page_Timeout configuration\n" \
1586"parameter.\n\n" \
1587"\t<timeout> - dddd; measured in number of baseband slots.",
1588&hci_write_page_timeout
1589},
1590{
1591"read_scan_enable",
1592"\nThis command will read the value for the Scan_Enable parameter. The\n" \
1593"Scan_Enable parameter controls whether or not the Bluetooth uint\n" \
1594"will periodically scan for page attempts and/or inquiry requests\n" \
1595"from other Bluetooth unit.\n\n" \
1596"\t0x00 - No Scans enabled.\n" \
1597"\t0x01 - Inquiry Scan enabled. Page Scan disabled.\n" \
1598"\t0x02 - Inquiry Scan disabled. Page Scan enabled.\n" \
1599"\t0x03 - Inquiry Scan enabled. Page Scan enabled.",
1600&hci_read_scan_enable
1601},
1602{
1603"write_scan_enable <scan_enable>",
1604"\nThis command will write the value for the Scan_Enable parameter.\n" \
1605"The Scan_Enable parameter controls whether or not the Bluetooth\n" \
1606"unit will periodically scan for page attempts and/or inquiry\n" \
1607"requests from other Bluetooth unit.\n\n" \
1608"\t<scan_enable> - dd;\n" \
1609"\t0 - No Scans enabled.\n" \
1610"\t1 - Inquiry Scan enabled. Page Scan disabled.\n" \
1611"\t2 - Inquiry Scan disabled. Page Scan enabled.\n" \
1612"\t3 - Inquiry Scan enabled. Page Scan enabled.",
1613&hci_write_scan_enable
1614},
1615{
1616"read_page_scan_activity",
1617"\nThis command will read the value for Page_Scan_Activity configuration\n" \
1618"parameters. The Page_Scan_Interval configuration parameter defines the\n" \
1619"amount of time between consecutive page scans. This time interval is \n" \
1620"defined from when the Host Controller started its last page scan until\n" \
1621"it begins the next page scan. The Page_Scan_Window configuration parameter\n" \
1622"defines the amount of time for the duration of the page scan. The\n" \
1623"Page_Scan_Window can only be less than or equal to the Page_Scan_Interval.",
1624&hci_read_page_scan_activity
1625},
1626{
1627"write_page_scan_activity interval(dddd) window(dddd)",
1628"\nThis command will write the value for Page_Scan_Activity configuration\n" \
1629"parameter. The Page_Scan_Interval configuration parameter defines the\n" \
1630"amount of time between consecutive page scans. This is defined as the time\n" \
1631"interval from when the Host Controller started its last page scan until it\n" \
1632"begins the next page scan. The Page_Scan_Window configuration parameter\n" \
1633"defines the amount of time for the duration of the page scan. \n" \
1634"The Page_Scan_Window can only be less than or equal to the Page_Scan_Interval.\n\n" \
1635"\t<interval> - Range: 0x0012 -� 0x100, Time = N * 0.625 msec\n" \
1636"\t<window>   - Range: 0x0012 -� 0x100, Time = N * 0.625 msen",
1637&hci_write_page_scan_activity
1638},
1639{
1640"read_inquiry_scan_activity",
1641"\nThis command will read the value for Inquiry_Scan_Activity configuration\n" \
1642"parameter. The Inquiry_Scan_Interval configuration parameter defines the\n" \
1643"amount of time between consecutive inquiry scans. This is defined as the\n" \
1644"time interval from when the Host Controller started its last inquiry scan\n" \
1645"until it begins the next inquiry scan.",
1646&hci_read_inquiry_scan_activity
1647},
1648{
1649"write_inquiry_scan_activity interval(dddd) window(dddd)",
1650"\nThis command will write the value for Inquiry_Scan_Activity configuration\n"\
1651"parameter. The Inquiry_Scan_Interval configuration parameter defines the\n" \
1652"amount of time between consecutive inquiry scans. This is defined as the\n" \
1653"time interval from when the Host Controller started its last inquiry scan\n" \
1654"until it begins the next inquiry scan. The Inquiry_Scan_Window configuration\n" \
1655"parameter defines the amount of time for the duration of the inquiry scan.\n" \
1656"The Inquiry_Scan_Window can only be less than or equal to the Inquiry_Scan_Interval.\n\n" \
1657"\t<interval> - Range: 0x0012 -� 0x100, Time = N * 0.625 msec\n" \
1658"\t<window>   - Range: 0x0012 -� 0x100, Time = N * 0.625 msen",
1659&hci_write_inquiry_scan_activity
1660},
1661{
1662"read_authentication_enable",
1663"\nThis command will read the value for the Authentication_Enable parameter.\n"\
1664"The Authentication_Enable parameter controls if the local unit requires\n"\
1665"to authenticate the remote unit at connection setup (between the\n" \
1666"Create_Connection command or acceptance of an incoming ACL connection\n"\
1667"and the corresponding Connection Complete event). At connection setup, only\n"\
1668"the unit(s) with the Authentication_Enable parameter enabled will try to\n"\
1669"authenticate the other unit.",
1670&hci_read_authentication_enable
1671},
1672{
1673"write_authentication_enable enable(0|1)",
1674"\nThis command will write the value for the Authentication_Enable parameter.\n"\
1675"The Authentication_Enable parameter controls if the local unit requires to\n"\
1676"authenticate the remote unit at connection setup (between the\n" \
1677"Create_Connection command or acceptance of an incoming ACL connection\n" \
1678"and the corresponding Connection Complete event). At connection setup, only\n"\
1679"the unit(s) with the Authentication_Enable parameter enabled will try to\n"\
1680"authenticate the other unit.",
1681&hci_write_authentication_enable
1682},
1683{
1684"read_encryption_mode",
1685"\nThis command will read the value for the Encryption_Mode parameter. The\n" \
1686"Encryption_Mode parameter controls if the local unit requires encryption\n" \
1687"to the remote unit at connection setup (between the Create_Connection\n" \
1688"command or acceptance of an incoming ACL connection and the corresponding\n" \
1689"Connection Complete event). At connection setup, only the unit(s) with\n" \
1690"the Authentication_Enable parameter enabled and Encryption_Mode parameter\n" \
1691"enabled will try to encrypt the connection to the other unit.\n\n" \
1692"\t<encryption_mode>:\n" \
1693"\t0x00 - Encryption disabled.\n" \
1694"\t0x01 - Encryption only for point-to-point packets.\n" \
1695"\t0x02 - Encryption for both point-to-point and broadcast packets.",
1696&hci_read_encryption_mode
1697},
1698{
1699"write_encryption_mode mode(0|1|2)",
1700"\tThis command will write the value for the Encryption_Mode parameter.\n" \
1701"The Encryption_Mode parameter controls if the local unit requires\n" \
1702"encryption to the remote unit at connection setup (between the\n" \
1703"Create_Connection command or acceptance of an incoming ACL connection\n" \
1704"and the corresponding Connection Complete event). At connection setup,\n" \
1705"only the unit(s) with the Authentication_Enable parameter enabled and\n" \
1706"Encryption_Mode parameter enabled will try to encrypt the connection to\n" \
1707"the other unit.\n\n" \
1708"\t<encryption_mode> (dd)\n" \
1709"\t0 - Encryption disabled.\n" \
1710"\t1 - Encryption only for point-to-point packets.\n" \
1711"\t2 - Encryption for both point-to-point and broadcast packets.",
1712&hci_write_encryption_mode
1713},
1714{
1715"read_class_of_device",
1716"\nThis command will read the value for the Class_of_Device parameter.\n" \
1717"The Class_of_Device parameter is used to indicate the capabilities of\n" \
1718"the local unit to other units.",
1719&hci_read_class_of_device
1720},
1721{
1722"write_class_of_device class(xx:xx:xx)",
1723"\nThis command will write the value for the Class_of_Device parameter.\n" \
1724"The Class_of_Device parameter is used to indicate the capabilities of \n" \
1725"the local unit to other units.\n\n" \
1726"\t<class> (xx:xx:xx) - class of device",
1727&hci_write_class_of_device
1728},
1729{
1730"read_voice_settings",
1731"\nThis command will read the values for the Voice_Setting parameter.\n" \
1732"The Voice_Setting parameter controls all the various settings for voice\n" \
1733"connections. These settings apply to all voice connections, and cannot be\n" \
1734"set for individual voice connections. The Voice_Setting parameter controls\n" \
1735"the configuration for voice connections: Input Coding, Air coding format,\n" \
1736"input data format, Input sample size, and linear PCM parameter.",
1737&hci_read_voice_settings
1738},
1739{
1740"write_voice_settings settings(xxxx)",
1741"\nThis command will write the values for the Voice_Setting parameter.\n" \
1742"The Voice_Setting parameter controls all the various settings for voice\n" \
1743"connections. These settings apply to all voice connections, and cannot be\n" \
1744"set for individual voice connections. The Voice_Setting parameter controls\n" \
1745"the configuration for voice connections: Input Coding, Air coding format,\n" \
1746"input data format, Input sample size, and linear PCM parameter.\n\n" \
1747"\t<voice_settings> (xxxx) - voice settings",
1748&hci_write_voice_settings
1749},
1750{
1751"read_number_broadcast_retransmissions",
1752"\nThis command will read the unit's parameter value for the Number of\n" \
1753"Broadcast Retransmissions. Broadcast packets are not acknowledged and are\n" \
1754"unreliable.",
1755&hci_read_number_broadcast_retransmissions
1756},
1757{
1758"write_number_broadcast_retransmissions count(dd)",
1759"\nThis command will write the unit's parameter value for the Number of\n" \
1760"Broadcast Retransmissions. Broadcast packets are not acknowledged and are\n" \
1761"unreliable.\n\n" \
1762"\t<count> (dd) - number of broadcast retransimissions",
1763&hci_write_number_broadcast_retransmissions
1764},
1765{
1766"read_hold_mode_activity",
1767"\nThis command will read the value for the Hold_Mode_Activity parameter.\n" \
1768"The Hold_Mode_Activity value is used to determine what activities should\n" \
1769"be suspended when the unit is in hold mode.",
1770&hci_read_hold_mode_activity
1771},
1772{
1773"write_hold_mode_activity settings(0|1|2|4)",
1774"\nThis command will write the value for the Hold_Mode_Activity parameter.\n" \
1775"The Hold_Mode_Activity value is used to determine what activities should\n" \
1776"be suspended when the unit is in hold mode.\n\n" \
1777"\t<settings> (dd) - bit mask:\n" \
1778"\t0 - Maintain current Power State. Default\n" \
1779"\t1 - Suspend Page Scan.\n" \
1780"\t2 - Suspend Inquiry Scan.\n" \
1781"\t4 - Suspend Periodic Inquiries.",
1782&hci_write_hold_mode_activity
1783},
1784{
1785"read_sco_flow_control_enable",
1786"\nThe Read_SCO_Flow_Control_Enable command provides the ability to read\n" \
1787"the SCO_Flow_Control_Enable setting. By using this setting, the Host can\n" \
1788"decide if the Host Controller will send Number Of Completed Packets events\n" \
1789"for SCO Connection Handles. This setting allows the Host to enable and\n" \
1790"disable SCO flow control.",
1791&hci_read_sco_flow_control_enable
1792},
1793{
1794"write_sco_flow_control_enable enable(0|1)",
1795"\nThe Write_SCO_Flow_Control_Enable command provides the ability to write\n" \
1796"the SCO_Flow_Control_Enable setting. By using this setting, the Host can\n" \
1797"decide if the Host Controller will send Number Of Completed Packets events\n" \
1798"for SCO Connection Handles. This setting allows the Host to enable and\n" \
1799"disable SCO flow control. The SCO_Flow_Control_Enable setting can only be\n" \
1800"changed if no connections exist.",
1801&hci_write_sco_flow_control_enable
1802},
1803{
1804"read_link_supervision_timeout <connection_handle>",
1805"\nThis command will read the value for the Link_Supervision_Timeout\n" \
1806"parameter for the device. The Link_Supervision_Timeout parameter is used\n" \
1807"by the master or slave Bluetooth device to monitor link loss. If, for any\n" \
1808"reason, no Baseband packets are received from that Connection Handle for a\n" \
1809"duration longer than the Link_Supervision_Timeout, the connection is\n"
1810"disconnected.\n\n" \
1811"\t<connection_handle> - dddd; connection handle\n",
1812&hci_read_link_supervision_timeout
1813},
1814{
1815"write_link_supervision_timeout <connection_handle> <timeout>",
1816"\nThis command will write the value for the Link_Supervision_Timeout\n" \
1817"parameter for the device. The Link_Supervision_Timeout parameter is used\n" \
1818"by the master or slave Bluetooth device to monitor link loss. If, for any\n" \
1819"reason, no Baseband packets are received from that connection handle for a\n" \
1820"duration longer than the Link_Supervision_Timeout, the connection is\n" \
1821"disconnected.\n\n" \
1822"\t<connection_handle> - dddd; connection handle\n" \
1823"\t<timeout>           - dddd; timeout measured in number of baseband slots\n",
1824&hci_write_link_supervision_timeout
1825},
1826{
1827"read_page_scan_period_mode",
1828"\nThis command is used to read the mandatory Page_Scan_Period_Mode of the\n" \
1829"local Bluetooth device. Every time an inquiry response message is sent, the\n"\
1830"Bluetooth device will start a timer (T_mandatory_pscan), the value of which\n"\
1831"is dependent on the Page_Scan_Period_Mode. As long as this timer has not\n" \
1832"expired, the Bluetooth device will use the Page_Scan_Period_Mode for all\n" \
1833"following page scans.",
1834&hci_read_page_scan_period_mode
1835},
1836{
1837"write_page_scan_period_mode <page_scan_period_mode>",
1838"\nThis command is used to write the mandatory Page_Scan_Period_Mode of the\n" \
1839"local Bluetooth device. Every time an inquiry response message is sent, the\n"\
1840"Bluetooth device will start a timer (T_mandatory_pscan), the value of which\n"\
1841"is dependent on the Page_Scan_Period_Mode. As long as this timer has not\n" \
1842"expired, the Bluetooth device will use the Page_Scan_Period_Mode for all\n" \
1843"following page scans.\n\n" \
1844"\t<page_scan_period_mode> - dd; page scan period mode:\n" \
1845"\t0x00 - P0 (Default)\n" \
1846"\t0x01 - P1\n" \
1847"\t0x02 - P2",
1848&hci_write_page_scan_period_mode
1849},
1850{
1851"read_page_scan_mode",
1852"\nThis command is used to read the default page scan mode of the local\n" \
1853"Bluetooth device. The Page_Scan_Mode parameter indicates the page scan mode\n"\
1854"that is used for the default page scan. Currently one mandatory page scan\n"\
1855"mode and three optional page scan modes are defined. Following an inquiry\n" \
1856"response, if the Baseband timer T_mandatory_pscan has not expired, the\n" \
1857"mandatory page scan mode must be applied.",
1858&hci_read_page_scan_mode
1859},
1860{
1861"write_page_scan_mode <page_scan_mode>",
1862"\nThis command is used to write the default page scan mode of the local\n" \
1863"Bluetooth device. The Page_Scan_Mode parameter indicates the page scan mode\n"\
1864"that is used for the default page scan. Currently, one mandatory page scan\n"\
1865"mode and three optional page scan modes are defined. Following an inquiry\n"\
1866"response, if the Baseband timer T_mandatory_pscan has not expired, the\n" \
1867"mandatory page scan mode must be applied.\n\n" \
1868"\t<page_scan_mode> - dd; page scan mode:\n" \
1869"\t0x00 - Mandatory Page Scan Mode (Default)\n" \
1870"\t0x01 - Optional Page Scan Mode I\n" \
1871"\t0x02 - Optional Page Scan Mode II\n" \
1872"\t0x03 - Optional Page Scan Mode III",
1873&hci_write_page_scan_mode
1874},
1875{ NULL, }
1876};
1877
1878