xref: /freebsd/usr.sbin/bluetooth/hccontrol/link_control.c (revision d93a896ef95946b0bf1219866fcb324b78543444)
1 /*
2  * link_control.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: link_control.c,v 1.4 2003/08/18 19:19:54 max Exp $
29  * $FreeBSD$
30  */
31 
32 #define L2CAP_SOCKET_CHECKED
33 #include <bluetooth.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include "hccontrol.h"
38 
39 static void hci_inquiry_response (int n, uint8_t **b);
40 
41 /* Send Inquiry command to the unit */
42 static int
43 hci_inquiry(int s, int argc, char **argv)
44 {
45 	int			 n0, n1, n2, timo;
46 	char			 b[512];
47 	ng_hci_inquiry_cp	 cp;
48 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
49 
50 	/* set defaults */
51 	cp.lap[2] = 0x9e;
52 	cp.lap[1] = 0x8b;
53 	cp.lap[0] = 0x33;
54 	cp.inquiry_length = 5;
55 	cp.num_responses = 8;
56 
57 	/* parse command parameters */
58 	switch (argc) {
59 	case 3:
60 		/* number of responses, range 0x00 - 0xff */
61 		if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 0xff)
62 			return (USAGE);
63 
64 		cp.num_responses = (n0 & 0xff);
65 
66 	case 2:
67 		/* inquiry length (N * 1.28) sec, range 0x01 - 0x30 */
68 		if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x1 || n0 > 0x30)
69 			return (USAGE);
70 
71 		cp.inquiry_length = (n0 & 0xff);
72 
73 	case 1:
74 		/* LAP */
75 		if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3)
76 			return (USAGE);
77 
78 		cp.lap[0] = (n0 & 0xff);
79 		cp.lap[1] = (n1 & 0xff);
80 		cp.lap[2] = (n2 & 0xff);
81 
82 	case 0:
83 		/* use defaults */
84 		break;
85 
86 	default:
87 		return (USAGE);
88 	}
89 
90 	/* send request and expect status back */
91 	n0 = sizeof(b);
92 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
93 			NG_HCI_OCF_INQUIRY), (char const *) &cp, sizeof(cp),
94 			b, &n0) == ERROR)
95 		return (ERROR);
96 
97 	if (*b != 0x00)
98 		return (FAILED);
99 
100 	timo = timeout;
101 	timeout = cp.inquiry_length * 1.28 + 1;
102 
103 wait_for_more:
104 	/* wait for inquiry events */
105 	n0 = sizeof(b);
106 	if (hci_recv(s, b, &n0) == ERROR) {
107 		timeout = timo;
108 		return (ERROR);
109 	}
110 
111 	if (n0 < sizeof(*e)) {
112 		timeout = timo;
113 		errno = EIO;
114 		return (ERROR);
115 	}
116 
117 	switch (e->event) {
118 	case NG_HCI_EVENT_INQUIRY_RESULT: {
119 		ng_hci_inquiry_result_ep	*ir =
120 				(ng_hci_inquiry_result_ep *)(e + 1);
121 		uint8_t				*r = (uint8_t *)(ir + 1);
122 
123 		fprintf(stdout, "Inquiry result, num_responses=%d\n",
124 			ir->num_responses);
125 
126 		for (n0 = 0; n0 < ir->num_responses; n0++)
127 			hci_inquiry_response(n0, &r);
128 
129 		goto wait_for_more;
130 		}
131 
132 	case NG_HCI_EVENT_INQUIRY_COMPL:
133 		fprintf(stdout, "Inquiry complete. Status: %s [%#02x]\n",
134 			hci_status2str(*(b + sizeof(*e))), *(b + sizeof(*e)));
135 		break;
136 
137 	default:
138 		goto wait_for_more;
139 	}
140 
141 	timeout = timo;
142 
143 	return (OK);
144 } /* hci_inquiry */
145 
146 /* Print Inquiry_Result event */
147 static void
148 hci_inquiry_response(int n, uint8_t **b)
149 {
150 	ng_hci_inquiry_response	*ir = (ng_hci_inquiry_response *)(*b);
151 
152 	fprintf(stdout, "Inquiry result #%d\n", n);
153 	fprintf(stdout, "\tBD_ADDR: %s\n", hci_bdaddr2str(&ir->bdaddr));
154 	fprintf(stdout, "\tPage Scan Rep. Mode: %#02x\n",
155 		ir->page_scan_rep_mode);
156 	fprintf(stdout, "\tPage Scan Period Mode: %#02x\n",
157 		ir->page_scan_period_mode);
158 	fprintf(stdout, "\tPage Scan Mode: %#02x\n",
159 		ir->page_scan_mode);
160 	fprintf(stdout, "\tClass: %02x:%02x:%02x\n",
161 		ir->uclass[2], ir->uclass[1], ir->uclass[0]);
162 	fprintf(stdout, "\tClock offset: %#04x\n",
163 		le16toh(ir->clock_offset));
164 
165 	*b += sizeof(*ir);
166 } /* hci_inquiry_response */
167 
168 /* Send Create_Connection command to the unit */
169 static int
170 hci_create_connection(int s, int argc, char **argv)
171 {
172 	int			 n0;
173 	char			 b[512];
174 	ng_hci_create_con_cp	 cp;
175 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
176 
177 	/* Set defaults */
178 	memset(&cp, 0, sizeof(cp));
179 	cp.pkt_type = htole16(	NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
180 				NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
181 				NG_HCI_PKT_DM5);
182 	cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
183 	cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;
184 	cp.clock_offset = 0;
185 	cp.accept_role_switch = 1;
186 
187 	/* parse command parameters */
188 	switch (argc) {
189 	case 6:
190 		/* accept role switch */
191 		if (sscanf(argv[5], "%d", &n0) != 1)
192 			return (USAGE);
193 
194 		cp.accept_role_switch = n0 ? 1 : 0;
195 
196 	case 5:
197 		/* clock offset */
198 		if (sscanf(argv[4], "%d", &n0) != 1)
199 			return (USAGE);
200 
201 		cp.clock_offset = (n0 & 0xffff);
202 		cp.clock_offset = htole16(cp.clock_offset);
203 
204 	case 4:
205 		/* page scan mode */
206 		if (sscanf(argv[3], "%d", &n0) != 1 || n0 < 0 || n0 > 3)
207 			return (USAGE);
208 
209 		cp.page_scan_mode = (n0 & 0xff);
210 
211 	case 3:
212 		/* page scan rep mode */
213 		if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 2)
214 			return (USAGE);
215 
216 		cp.page_scan_rep_mode = (n0 & 0xff);
217 
218 	case 2:
219 		/* packet type */
220 		if (sscanf(argv[1], "%x", &n0) != 1)
221 			return (USAGE);
222 
223 		n0 &= (	NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
224 			NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
225 			NG_HCI_PKT_DM5);
226 		if (n0 == 0)
227 			return (USAGE);
228 
229 		cp.pkt_type = (n0 & 0xffff);
230 		cp.pkt_type = htole16(cp.pkt_type);
231 
232 	case 1:
233 		/* BD_ADDR */
234 		if (!bt_aton(argv[0], &cp.bdaddr)) {
235 			struct hostent	*he = NULL;
236 
237 			if ((he = bt_gethostbyname(argv[0])) == NULL)
238 				return (USAGE);
239 
240 			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
241 		}
242 		break;
243 
244 	default:
245 		return (USAGE);
246 	}
247 
248 	/* send request and expect status response */
249 	n0 = sizeof(b);
250 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
251 			NG_HCI_OCF_CREATE_CON),
252 			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
253 		return (ERROR);
254 
255 	if (*b != 0x00)
256 		return (FAILED);
257 
258 	/* wait for event */
259 again:
260 	n0 = sizeof(b);
261 	if (hci_recv(s, b, &n0) == ERROR)
262 		return (ERROR);
263 	if (n0 < sizeof(*e)) {
264 		errno = EIO;
265 		return (ERROR);
266 	}
267 
268 	if (e->event == NG_HCI_EVENT_CON_COMPL) {
269 		ng_hci_con_compl_ep	*ep = (ng_hci_con_compl_ep *)(e + 1);
270 
271 		if (ep->status != 0x00) {
272 			fprintf(stdout, "Status: %s [%#02x]\n",
273 				hci_status2str(ep->status), ep->status);
274 			return (FAILED);
275 		}
276 
277 		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
278 		fprintf(stdout, "Connection handle: %d\n",
279 			le16toh(ep->con_handle));
280 		fprintf(stdout, "Encryption mode: %s [%d]\n",
281 			hci_encrypt2str(ep->encryption_mode, 0),
282 			ep->encryption_mode);
283 	} else
284 		goto again;
285 
286 	return (OK);
287 } /* hci_create_connection */
288 
289 /* Send Disconnect command to the unit */
290 static int
291 hci_disconnect(int s, int argc, char **argv)
292 {
293 	int			 n;
294 	char			 b[512];
295 	ng_hci_discon_cp	 cp;
296 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
297 
298 	/* Set defaults */
299 	memset(&cp, 0, sizeof(cp));
300 	cp.reason = 0x13;
301 
302 	/* parse command parameters */
303 	switch (argc) {
304 	case 2:
305 		/* reason */
306 		if (sscanf(argv[1], "%d", &n) != 1 || n <= 0x00 || n > 0xff)
307 			return (USAGE);
308 
309 		cp.reason = (uint8_t) (n & 0xff);
310 
311 	case 1:
312 		/* connection handle */
313 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
314 			return (USAGE);
315 
316 		cp.con_handle = (uint16_t) (n & 0x0fff);
317 		cp.con_handle = htole16(cp.con_handle);
318 		break;
319 
320 	default:
321 		return (USAGE);
322 	}
323 
324 	/* send request and expect status response */
325 	n = sizeof(b);
326 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
327 			NG_HCI_OCF_DISCON),
328 			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
329 		return (ERROR);
330 
331 	if (*b != 0x00)
332 		return (FAILED);
333 
334 	/* wait for event */
335 again:
336 	n = sizeof(b);
337 	if (hci_recv(s, b, &n) == ERROR)
338 		return (ERROR);
339 	if (n < sizeof(*e)) {
340 		errno = EIO;
341 		return (ERROR);
342 	}
343 
344 	if (e->event == NG_HCI_EVENT_DISCON_COMPL) {
345 		ng_hci_discon_compl_ep	*ep = (ng_hci_discon_compl_ep *)(e + 1);
346 
347 		if (ep->status != 0x00) {
348 			fprintf(stdout, "Status: %s [%#02x]\n",
349 				hci_status2str(ep->status), ep->status);
350 			return (FAILED);
351 		}
352 
353 		fprintf(stdout, "Connection handle: %d\n",
354 			le16toh(ep->con_handle));
355 		fprintf(stdout, "Reason: %s [%#02x]\n",
356 			hci_status2str(ep->reason), ep->reason);
357 	} else
358 		goto again;
359 
360 	return (OK);
361 } /* hci_disconnect */
362 
363 /* Send Add_SCO_Connection command to the unit */
364 static int
365 hci_add_sco_connection(int s, int argc, char **argv)
366 {
367 	int			 n;
368 	char			 b[512];
369 	ng_hci_add_sco_con_cp	 cp;
370 	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
371 
372 	/* Set defaults */
373 	memset(&cp, 0, sizeof(cp));
374 	cp.pkt_type = htole16(NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);
375 
376 	/* parse command parameters */
377 	switch (argc) {
378 	case 2:
379 		/* packet type */
380 		if (sscanf(argv[1], "%x", &n) != 1)
381 			return (USAGE);
382 
383 		n &= (NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);
384 		if (n == 0)
385 			return (USAGE);
386 
387 		cp.pkt_type = (uint16_t) (n & 0x0fff);
388 		cp.pkt_type = htole16(cp.pkt_type);
389 
390 	case 1:
391 		/* acl connection handle */
392 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
393 			return (USAGE);
394 
395 		cp.con_handle = (uint16_t) (n & 0x0fff);
396 		cp.con_handle = htole16(cp.con_handle);
397 		break;
398 
399 	default:
400 		return (USAGE);
401 	}
402 
403 	/* send request and expect status response */
404 	n = sizeof(b);
405 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
406 			NG_HCI_OCF_ADD_SCO_CON),
407 			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
408 		return (ERROR);
409 
410 	if (*b != 0x00)
411 		return (FAILED);
412 
413 	/* wait for event */
414 again:
415 	n = sizeof(b);
416 	if (hci_recv(s, b, &n) == ERROR)
417 		return (ERROR);
418 	if (n < sizeof(*e)) {
419 		errno = EIO;
420 		return (ERROR);
421 	}
422 
423 	if (e->event == NG_HCI_EVENT_CON_COMPL) {
424 		ng_hci_con_compl_ep	*ep = (ng_hci_con_compl_ep *)(e + 1);
425 
426 		if (ep->status != 0x00) {
427 			fprintf(stdout, "Status: %s [%#02x]\n",
428 				hci_status2str(ep->status), ep->status);
429 			return (FAILED);
430 		}
431 
432 		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
433 		fprintf(stdout, "Connection handle: %d\n",
434 			le16toh(ep->con_handle));
435 		fprintf(stdout, "Encryption mode: %s [%d]\n",
436 			hci_encrypt2str(ep->encryption_mode, 0),
437 			ep->encryption_mode);
438 	} else
439 		goto again;
440 
441 	return (OK);
442 } /* Add_SCO_Connection */
443 
444 /* Send Change_Connection_Packet_Type command to the unit */
445 static int
446 hci_change_connection_packet_type(int s, int argc, char **argv)
447 {
448 	int				 n;
449 	char				 b[512];
450 	ng_hci_change_con_pkt_type_cp	 cp;
451 	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b;
452 
453 	switch (argc) {
454 	case 2:
455 		/* connection handle */
456 		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
457 			return (USAGE);
458 
459 		cp.con_handle = (uint16_t) (n & 0x0fff);
460 		cp.con_handle = htole16(cp.con_handle);
461 
462 		/* packet type */
463 		if (sscanf(argv[1], "%x", &n) != 1)
464 			return (USAGE);
465 
466 		cp.pkt_type = (uint16_t) (n & 0xffff);
467 		cp.pkt_type = htole16(cp.pkt_type);
468 		break;
469 
470 	default:
471 		return (USAGE);
472 	}
473 
474 	/* send request and expect status response */
475 	n = sizeof(b);
476 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
477 			NG_HCI_OCF_CHANGE_CON_PKT_TYPE),
478 			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
479 		return (ERROR);
480 
481 	if (*b != 0x00)
482 		return (FAILED);
483 
484 	/* wait for event */
485 again:
486 	n = sizeof(b);
487 	if (hci_recv(s, b, &n) == ERROR)
488 		return (ERROR);
489 	if (n < sizeof(*e)) {
490 		errno = EIO;
491 		return (ERROR);
492 	}
493 
494 	if (e->event == NG_HCI_EVENT_CON_PKT_TYPE_CHANGED) {
495 		ng_hci_con_pkt_type_changed_ep	*ep =
496 				(ng_hci_con_pkt_type_changed_ep *)(e + 1);
497 
498 		if (ep->status != 0x00) {
499 			fprintf(stdout, "Status: %s [%#02x]\n",
500 				hci_status2str(ep->status), ep->status);
501 			return (FAILED);
502 		}
503 
504 		fprintf(stdout, "Connection handle: %d\n",
505 			le16toh(ep->con_handle));
506 		fprintf(stdout, "Packet type: %#04x\n",
507 			le16toh(ep->pkt_type));
508 	} else
509 		goto again;
510 
511 	return (OK);
512 } /* hci_change_connection_packet_type */
513 
514 /* Send Remote_Name_Request command to the unit */
515 static int
516 hci_remote_name_request(int s, int argc, char **argv)
517 {
518 	int				 n0;
519 	char				 b[512];
520 	ng_hci_remote_name_req_cp	 cp;
521 	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b;
522 
523 	memset(&cp, 0, sizeof(cp));
524 	cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
525 	cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;
526 
527 	/* parse command parameters */
528 	switch (argc) {
529 	case 4:
530 		/* clock_offset */
531 		if (sscanf(argv[3], "%x", &n0) != 1)
532 			return (USAGE);
533 
534 		cp.clock_offset = (n0 & 0xffff);
535 		cp.clock_offset = htole16(cp.clock_offset);
536 
537 	case 3:
538 		/* page_scan_mode */
539 		if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x03)
540 			return (USAGE);
541 
542 		cp.page_scan_mode = (n0 & 0xff);
543 
544 	case 2:
545 		/* page_scan_rep_mode */
546 		if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x02)
547 			return (USAGE);
548 
549 		cp.page_scan_rep_mode = (n0 & 0xff);
550 
551 	case 1:
552 		/* BD_ADDR */
553 		if (!bt_aton(argv[0], &cp.bdaddr)) {
554 			struct hostent	*he = NULL;
555 
556 			if ((he = bt_gethostbyname(argv[0])) == NULL)
557 				return (USAGE);
558 
559 			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
560 		}
561 		break;
562 
563 	default:
564 		return (USAGE);
565 	}
566 
567 	/* send request and expect status response */
568 	n0 = sizeof(b);
569 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
570 			NG_HCI_OCF_REMOTE_NAME_REQ),
571 			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
572 		return (ERROR);
573 
574 	if (*b != 0x00)
575 		return (FAILED);
576 
577 	/* wait for event */
578 again:
579 	n0 = sizeof(b);
580 	if (hci_recv(s, b, &n0) == ERROR)
581 		return (ERROR);
582 	if (n0 < sizeof(*e)) {
583 		errno = EIO;
584 		return (ERROR);
585 	}
586 
587 	if (e->event == NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL) {
588 		ng_hci_remote_name_req_compl_ep	*ep =
589 				(ng_hci_remote_name_req_compl_ep *)(e + 1);
590 
591 		if (ep->status != 0x00) {
592 			fprintf(stdout, "Status: %s [%#02x]\n",
593 				hci_status2str(ep->status), ep->status);
594 			return (FAILED);
595 		}
596 
597 		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
598 		fprintf(stdout, "Name: %s\n", ep->name);
599 	} else
600 		goto again;
601 
602 	return (OK);
603 } /* hci_remote_name_request */
604 
605 /* Send Read_Remote_Supported_Features command to the unit */
606 static int
607 hci_read_remote_supported_features(int s, int argc, char **argv)
608 {
609 	int				 n;
610 	char				 b[512];
611 	ng_hci_read_remote_features_cp	 cp;
612 	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b;
613 	char				 buffer[1024];
614 
615 	/* parse command parameters */
616 	switch (argc) {
617 	case 1:
618 		/* connecton handle */
619 		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
620 			return (USAGE);
621 
622 		cp.con_handle = (n & 0x0fff);
623 		cp.con_handle = htole16(cp.con_handle);
624 		break;
625 
626 	default:
627 		return (USAGE);
628 	}
629 
630 	/* send request and expect status response */
631 	n = sizeof(b);
632 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
633 			NG_HCI_OCF_READ_REMOTE_FEATURES),
634 			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
635 		return (ERROR);
636 
637 	if (*b != 0x00)
638 		return (FAILED);
639 
640 	/* wait for event */
641 again:
642 	n = sizeof(b);
643 	if (hci_recv(s, b, &n) == ERROR)
644 		return (ERROR);
645 
646 	if (n < sizeof(*e)) {
647 		errno = EIO;
648 		return (ERROR);
649 	}
650 
651 	if (e->event == NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL) {
652 		ng_hci_read_remote_features_compl_ep	*ep =
653 				(ng_hci_read_remote_features_compl_ep *)(e + 1);
654 
655 		if (ep->status != 0x00) {
656 			fprintf(stdout, "Status: %s [%#02x]\n",
657 				hci_status2str(ep->status), ep->status);
658 			return (FAILED);
659 		}
660 
661 		fprintf(stdout, "Connection handle: %d\n",
662 			le16toh(ep->con_handle));
663 		fprintf(stdout, "Features: ");
664 		for (n = 0; n < sizeof(ep->features); n++)
665 			fprintf(stdout, "%#02x ", ep->features[n]);
666 		fprintf(stdout, "\n%s\n", hci_features2str(ep->features,
667 			buffer, sizeof(buffer)));
668 	} else
669 		goto again;
670 
671 	return (OK);
672 } /* hci_read_remote_supported_features */
673 
674 /* Send Read_Remote_Version_Information command to the unit */
675 static int
676 hci_read_remote_version_information(int s, int argc, char **argv)
677 {
678 	int				 n;
679 	char				 b[512];
680 	ng_hci_read_remote_ver_info_cp	 cp;
681 	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b;
682 
683 	/* parse command parameters */
684 	switch (argc) {
685 	case 1:
686 		/* connecton handle */
687 		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
688 			return (USAGE);
689 
690 		cp.con_handle = (n & 0x0fff);
691 		cp.con_handle = htole16(cp.con_handle);
692 		break;
693 
694 	default:
695 		return (USAGE);
696 	}
697 
698 	/* send request and expect status response */
699 	n = sizeof(b);
700 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
701 			NG_HCI_OCF_READ_REMOTE_VER_INFO),
702 			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
703 		return (ERROR);
704 
705 	if (*b != 0x00)
706 		return (FAILED);
707 
708 	/* wait for event */
709 again:
710 	n = sizeof(b);
711 	if (hci_recv(s, b, &n) == ERROR)
712 		return (ERROR);
713 
714 	if (n < sizeof(*e)) {
715 		errno = EIO;
716 		return (ERROR);
717 	}
718 
719 	if (e->event == NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL) {
720 		ng_hci_read_remote_ver_info_compl_ep	*ep =
721 				(ng_hci_read_remote_ver_info_compl_ep *)(e + 1);
722 
723 		if (ep->status != 0x00) {
724 			fprintf(stdout, "Status: %s [%#02x]\n",
725 				hci_status2str(ep->status), ep->status);
726 			return (FAILED);
727 		}
728 
729 		ep->manufacturer = le16toh(ep->manufacturer);
730 
731 		fprintf(stdout, "Connection handle: %d\n",
732 			le16toh(ep->con_handle));
733 		fprintf(stdout, "LMP version: %s [%#02x]\n",
734 			hci_lmpver2str(ep->lmp_version), ep->lmp_version);
735 		fprintf(stdout, "LMP sub-version: %#04x\n",
736 			le16toh(ep->lmp_subversion));
737 		fprintf(stdout, "Manufacturer: %s [%#04x]\n",
738 			hci_manufacturer2str(ep->manufacturer),
739 			ep->manufacturer);
740 	} else
741 		goto again;
742 
743 	return (OK);
744 } /* hci_read_remote_version_information */
745 
746 /* Send Read_Clock_Offset command to the unit */
747 static int
748 hci_read_clock_offset(int s, int argc, char **argv)
749 {
750 	int				 n;
751 	char				 b[512];
752 	ng_hci_read_clock_offset_cp	 cp;
753 	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b;
754 
755 	/* parse command parameters */
756 	switch (argc) {
757 	case 1:
758 		/* connecton handle */
759 		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
760 			return (USAGE);
761 
762 		cp.con_handle = (n & 0x0fff);
763 		cp.con_handle = htole16(cp.con_handle);
764 		break;
765 
766 	default:
767 		return (USAGE);
768 	}
769 
770 	/* send request and expect status response */
771 	n = sizeof(b);
772 	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
773 			NG_HCI_OCF_READ_CLOCK_OFFSET),
774 			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
775 		return (ERROR);
776 
777 	if (*b != 0x00)
778 		return (FAILED);
779 
780 	/* wait for event */
781 again:
782 	n = sizeof(b);
783 	if (hci_recv(s, b, &n) == ERROR)
784 		return (ERROR);
785 
786 	if (n < sizeof(*e)) {
787 		errno = EIO;
788 		return (ERROR);
789 	}
790 
791 	if (e->event == NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL) {
792 		ng_hci_read_clock_offset_compl_ep	*ep =
793 				(ng_hci_read_clock_offset_compl_ep *)(e + 1);
794 
795 		if (ep->status != 0x00) {
796 			fprintf(stdout, "Status: %s [%#02x]\n",
797 				hci_status2str(ep->status), ep->status);
798 			return (FAILED);
799 		}
800 
801 		fprintf(stdout, "Connection handle: %d\n",
802 			le16toh(ep->con_handle));
803 		fprintf(stdout, "Clock offset: %#04x\n",
804 			le16toh(ep->clock_offset));
805 	} else
806 		goto again;
807 
808 	return (OK);
809 } /* hci_read_clock_offset */
810 
811 struct hci_command	link_control_commands[] = {
812 {
813 "inquiry <LAP> <inquiry_length> <num_reponses>",
814 "\nThis command will cause the Bluetooth unit to enter Inquiry Mode.\n" \
815 "Inquiry Mode is used to discover other nearby Bluetooth units. The LAP\n" \
816 "input parameter contains the LAP from which the inquiry access code shall\n" \
817 "be derived when the inquiry procedure is made. The Inquiry_Length parameter\n"\
818 "specifies the total duration of the Inquiry Mode and, when this time\n" \
819 "expires, Inquiry will be halted. The Num_Responses parameter specifies the\n" \
820 "number of responses that can be received before the Inquiry is halted.\n\n" \
821 "\t<LAP>            - xx:xx:xx; 9e:8b:33 (GIAC), 93:8b:00 (LDIAC)\n" \
822 "\t<inquiry_length> - dd; total length == dd * 1.28 sec\n" \
823 "\t<num_responses>  - dd",
824 &hci_inquiry
825 },
826 {
827 "create_connection <BD_ADDR> <pkt> <rep_mode> <ps_mode> <clck_off> <role_sw>",
828 "" \
829 "\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n\n" \
830 "\t<pkt>     - xxxx; packet type\n" \
831 "" \
832 "\t\tACL packets\n" \
833 "\t\t-----------\n" \
834 "\t\t0x0008 DM1\n" \
835 "\t\t0x0010 DH1\n" \
836 "\t\t0x0400 DM3\n" \
837 "\t\t0x0800 DH3\n" \
838 "\t\t0x4000 DM5\n" \
839 "\t\t0x8000 DH5\n\n" \
840 "" \
841 "\trep_mode  - d; page scan repetition mode\n" \
842 "" \
843 "\t\tPage scan repetition modes\n" \
844 "\t\t--------------------------\n" \
845 "\t\t0 Page scan repetition mode 0\n" \
846 "\t\t1 Page scan repetition mode 1\n" \
847 "\t\t2 Page scan repetition mode 2\n" \
848 "\n" \
849 "\tps_mode   - d; Page scan mode\n" \
850 "" \
851 "\t\tPage scan modes\n" \
852 "\t\t---------------\n" \
853 "\t\t0 Mandatory page scan mode\n" \
854 "\t\t1 Optional page scan mode1\n" \
855 "\t\t2 Optional page scan mode2\n" \
856 "\t\t3 Optional page scan mode3\n" \
857 "\n" \
858 "\tclck_off  - dddd; clock offset. Use 0 if unknown\n\n" \
859 "\trole_sw   - d; allow (1) or deny role switch\n",
860 &hci_create_connection
861 },
862 {
863 "disconnect <connection_handle> <reason>",
864 "\nThe Disconnection command is used to terminate an existing connection.\n" \
865 "The connection handle command parameter indicates which connection is to\n" \
866 "be disconnected. The Reason command parameter indicates the reason for\n" \
867 "ending the connection.\n\n" \
868 "\t<connection_handle> - dddd; connection handle\n" \
869 "\t<reason>            - dd; reason; usually 19 (0x13) - user ended;\n" \
870 "\t                      also 0x05, 0x13-0x15, 0x1A, 0x29",
871 &hci_disconnect
872 },
873 {
874 "add_sco_connection <acl connection handle> <packet type>",
875 "This command will cause the link manager to create a SCO connection using\n" \
876 "the ACL connection specified by the connection handle command parameter.\n" \
877 "The Link Manager will determine how the new connection is established. This\n"\
878 "connection is determined by the current state of the device, its piconet,\n" \
879 "and the state of the device to be connected. The packet type command parameter\n" \
880 "specifies which packet types the Link Manager should use for the connection.\n"\
881 "The Link Manager must only use the packet type(s) specified by the packet\n" \
882 "type command parameter for sending HCI SCO data packets. Multiple packet\n" \
883 "types may be specified for the packet type command parameter by performing\n" \
884 "a bitwise OR operation of the different packet types. Note: An SCO connection\n" \
885 "can only be created when an ACL connection already exists and when it is\n" \
886 "not put in park mode.\n\n" \
887 "\t<connection_handle> - dddd; ACL connection handle\n" \
888 "\t<packet_type>       - xxxx; packet type\n" \
889 "" \
890 "\t\tSCO packets\n" \
891 "\t\t-----------\n" \
892 "\t\t0x0020 HV1\n" \
893 "\t\t0x0040 HV2\n" \
894 "\t\t0x0080 HV3\n",
895 &hci_add_sco_connection
896 },
897 {
898 "change_connection_packet_type <connection_hande> <packet_type>",
899 "The Change_Connection_Packet_Type command is used to change which packet\n" \
900 "types can be used for a connection that is currently established. This\n" \
901 "allows current connections to be dynamically modified to support different\n" \
902 "types of user data. The Packet_Type command parameter specifies which\n" \
903 "packet types the Link Manager can use for the connection. Multiple packet\n" \
904 "types may be specified for the Packet_Type command parameter by bitwise OR\n" \
905 "operation of the different packet types.\n\n" \
906 "\t<connection_handle> - dddd; connection handle\n" \
907 "\t<packet_type>       - xxxx; packet type mask\n" \
908 "" \
909 "\t\tACL packets\n" \
910 "\t\t-----------\n" \
911 "\t\t0x0008 DM1\n" \
912 "\t\t0x0010 DH1\n" \
913 "\t\t0x0400 DM3\n" \
914 "\t\t0x0800 DH3\n" \
915 "\t\t0x4000 DM5\n" \
916 "\t\t0x8000 DH5\n\n" \
917 "" \
918 "\t\tSCO packets\n" \
919 "\t\t-----------\n" \
920 "\t\t0x0020 HV1\n" \
921 "\t\t0x0040 HV2\n" \
922 "\t\t0x0080 HV3\n" \
923 "",
924 &hci_change_connection_packet_type
925 },
926 {
927 "remote_name_request <BD_ADDR> <ps_rep_mode> <ps_mode> <clock_offset>",
928 "\nThe Remote_Name_Request command is used to obtain the user-friendly\n" \
929 "name of another Bluetooth unit.\n\n" \
930 "\t<BD_ADDR>      - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \
931 "\t<ps_rep_mode>  - dd; page scan repetition mode [0-2]\n" \
932 "\t<ps_mode>      - dd; page scan mode [0-3]\n" \
933 "\t<clock_offset> - xxxx; clock offset [0 - 0xffff]",
934 &hci_remote_name_request
935 },
936 {
937 "read_remote_supported_features <connection_handle>",
938 "\nThis command requests a list of the supported features for the remote\n" \
939 "unit identified by the connection handle parameter. The connection handle\n" \
940 "must be a connection handle for an ACL connection.\n\n" \
941 "\t<connection_handle> - dddd; connection handle",
942 &hci_read_remote_supported_features
943 },
944 {
945 "read_remote_version_information <connection_handle>",
946 "\nThis command will obtain the values for the version information for the\n" \
947 "remote Bluetooth unit identified by the connection handle parameter. The\n" \
948 "connection handle must be a connection handle for an ACL connection.\n\n" \
949 "\t<connection_handle> - dddd; connection handle",
950 &hci_read_remote_version_information
951 },
952 {
953 "read_clock_offset <connection_handle>",
954 "\nThis command allows the Host to read the clock offset from the remote unit.\n" \
955 "\t<connection_handle> - dddd; connection handle",
956 &hci_read_clock_offset
957 },
958 {
959 NULL,
960 }};
961 
962