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