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