Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/hccontrol/link_control.c
106462 views
1
/*-
2
* link_control.c
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2001-2002 Maksim Yevmenkin <[email protected]>
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
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
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
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
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
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
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
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
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
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
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
964